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