1 /* 2 * kmp_io.cpp -- RTL IO 3 */ 4 5 6 //===----------------------------------------------------------------------===// 7 // 8 // The LLVM Compiler Infrastructure 9 // 10 // This file is dual licensed under the MIT and the University of Illinois Open 11 // Source Licenses. See LICENSE.txt for details. 12 // 13 //===----------------------------------------------------------------------===// 14 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <stddef.h> 19 #include <stdarg.h> 20 #include <string.h> 21 #ifndef __ABSOFT_WIN 22 # include <sys/types.h> 23 #endif 24 25 #include "kmp_os.h" 26 #include "kmp_lock.h" 27 #include "kmp_str.h" 28 #include "kmp_io.h" 29 #include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc 30 31 #if KMP_OS_WINDOWS 32 # pragma warning( push ) 33 # pragma warning( disable: 271 310 ) 34 # include <windows.h> 35 # pragma warning( pop ) 36 #endif 37 38 /* ------------------------------------------------------------------------ */ 39 /* ------------------------------------------------------------------------ */ 40 41 kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_stdio_lock ); /* Control stdio functions */ 42 kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_console_lock ); /* Control console initialization */ 43 44 #if KMP_OS_WINDOWS 45 46 # ifdef KMP_DEBUG 47 /* __kmp_stdout is used only for dev build */ 48 static HANDLE __kmp_stdout = NULL; 49 # endif 50 static HANDLE __kmp_stderr = NULL; 51 static int __kmp_console_exists = FALSE; 52 static kmp_str_buf_t __kmp_console_buf; 53 54 static int 55 is_console( void ) 56 { 57 char buffer[ 128 ]; 58 DWORD rc = 0; 59 DWORD err = 0; 60 // Try to get console title. 61 SetLastError( 0 ); 62 // GetConsoleTitle does not reset last error in case of success or short buffer, 63 // so we need to clear it explicitly. 64 rc = GetConsoleTitle( buffer, sizeof( buffer ) ); 65 if ( rc == 0 ) { 66 // rc == 0 means getting console title failed. Let us find out why. 67 err = GetLastError(); 68 // err == 0 means buffer too short (we suppose console exists). 69 // In Window applications we usually have err == 6 (invalid handle). 70 }; // if 71 return rc > 0 || err == 0; 72 } 73 74 void 75 __kmp_close_console( void ) 76 { 77 /* wait until user presses return before closing window */ 78 /* TODO only close if a window was opened */ 79 if( __kmp_console_exists ) { 80 #ifdef KMP_DEBUG 81 /* standard out is used only in dev build */ 82 __kmp_stdout = NULL; 83 #endif 84 __kmp_stderr = NULL; 85 __kmp_str_buf_free( &__kmp_console_buf ); 86 __kmp_console_exists = FALSE; 87 } 88 } 89 90 /* For windows, call this before stdout, stderr, or stdin are used. 91 * It opens a console window and starts processing */ 92 static void 93 __kmp_redirect_output( void ) 94 { 95 __kmp_acquire_bootstrap_lock( &__kmp_console_lock ); 96 97 if( ! __kmp_console_exists ) { 98 #ifdef KMP_DEBUG 99 /* standard out is used only in dev build */ 100 HANDLE ho; 101 #endif 102 HANDLE he; 103 104 __kmp_str_buf_init( &__kmp_console_buf ); 105 106 AllocConsole(); 107 // We do not check the result of AllocConsole because 108 // 1. the call is harmless 109 // 2. it is not clear how to communicate failue 110 // 3. we will detect failure later when we get handle(s) 111 112 #ifdef KMP_DEBUG 113 ho = GetStdHandle( STD_OUTPUT_HANDLE ); 114 if ( ho == INVALID_HANDLE_VALUE || ho == NULL ) { 115 116 DWORD err = GetLastError(); 117 // TODO: output error somehow (maybe message box) 118 __kmp_stdout = NULL; 119 120 } else { 121 122 __kmp_stdout = ho; // temporary code, need new global for ho 123 124 } 125 #endif 126 he = GetStdHandle( STD_ERROR_HANDLE ); 127 if ( he == INVALID_HANDLE_VALUE || he == NULL ) { 128 129 DWORD err = GetLastError(); 130 // TODO: output error somehow (maybe message box) 131 __kmp_stderr = NULL; 132 133 } else { 134 135 __kmp_stderr = he; // temporary code, need new global 136 } 137 __kmp_console_exists = TRUE; 138 } 139 __kmp_release_bootstrap_lock( &__kmp_console_lock ); 140 } 141 142 #else 143 #define __kmp_stderr (stderr) 144 #endif /* KMP_OS_WINDOWS */ 145 146 void 147 __kmp_vprintf( enum kmp_io __kmp_io, char const * format, va_list ap ) 148 { 149 #if KMP_OS_WINDOWS 150 if( !__kmp_console_exists ) { 151 __kmp_redirect_output(); 152 } 153 if( ! __kmp_stderr && __kmp_io == kmp_err ) { 154 return; 155 } 156 #ifdef KMP_DEBUG 157 if( ! __kmp_stdout && __kmp_io == kmp_out ) { 158 return; 159 } 160 #endif 161 #endif /* KMP_OS_WINDOWS */ 162 163 if ( __kmp_debug_buf && __kmp_debug_buffer != NULL ) { 164 165 int dc = ( __kmp_debug_buf_atomic ? 166 KMP_TEST_THEN_INC32( & __kmp_debug_count) : __kmp_debug_count++ ) 167 % __kmp_debug_buf_lines; 168 char *db = & __kmp_debug_buffer[ dc * __kmp_debug_buf_chars ]; 169 int chars = 0; 170 171 #ifdef KMP_DEBUG_PIDS 172 chars = KMP_SNPRINTF( db, __kmp_debug_buf_chars, "pid=%d: ", (kmp_int32)getpid() ); 173 #endif 174 chars += KMP_VSNPRINTF( db, __kmp_debug_buf_chars, format, ap ); 175 176 if ( chars + 1 > __kmp_debug_buf_chars ) { 177 if ( chars + 1 > __kmp_debug_buf_warn_chars ) { 178 #if KMP_OS_WINDOWS 179 DWORD count; 180 __kmp_str_buf_print( &__kmp_console_buf, 181 "OMP warning: Debugging buffer overflow; increase KMP_DEBUG_BUF_CHARS to %d\n", 182 chars + 1 ); 183 WriteFile( __kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used, &count, NULL ); 184 __kmp_str_buf_clear( &__kmp_console_buf ); 185 #else 186 fprintf( __kmp_stderr, 187 "OMP warning: Debugging buffer overflow; increase KMP_DEBUG_BUF_CHARS to %d\n", 188 chars + 1 ); 189 fflush( __kmp_stderr ); 190 #endif 191 __kmp_debug_buf_warn_chars = chars + 1; 192 } 193 /* terminate string if overflow occurred */ 194 db[ __kmp_debug_buf_chars - 2 ] = '\n'; 195 db[ __kmp_debug_buf_chars - 1 ] = '\0'; 196 } 197 } else { 198 #if KMP_OS_WINDOWS 199 DWORD count; 200 #ifdef KMP_DEBUG_PIDS 201 __kmp_str_buf_print( &__kmp_console_buf, "pid=%d: ", 202 (kmp_int32)getpid() ); 203 #endif 204 __kmp_str_buf_vprint( &__kmp_console_buf, format, ap ); 205 WriteFile( 206 __kmp_stderr, 207 __kmp_console_buf.str, 208 __kmp_console_buf.used, 209 &count, 210 NULL 211 ); 212 __kmp_str_buf_clear( &__kmp_console_buf ); 213 #else 214 #ifdef KMP_DEBUG_PIDS 215 fprintf( __kmp_stderr, "pid=%d: ", (kmp_int32)getpid() ); 216 #endif 217 vfprintf( __kmp_stderr, format, ap ); 218 fflush( __kmp_stderr ); 219 #endif 220 } 221 } 222 223 void 224 __kmp_printf( char const * format, ... ) 225 { 226 va_list ap; 227 va_start( ap, format ); 228 229 __kmp_acquire_bootstrap_lock( & __kmp_stdio_lock ); 230 __kmp_vprintf( kmp_err, format, ap ); 231 __kmp_release_bootstrap_lock( & __kmp_stdio_lock ); 232 233 va_end( ap ); 234 } 235 236 void 237 __kmp_printf_no_lock( char const * format, ... ) 238 { 239 va_list ap; 240 va_start( ap, format ); 241 242 __kmp_vprintf( kmp_err, format, ap ); 243 244 va_end( ap ); 245 } 246 247 /* ------------------------------------------------------------------------ */ 248 /* ------------------------------------------------------------------------ */ 249