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