17cc577a4SJonathan Peyton /*
2*de4749b7SJonathan Peyton  * kmp_io.cpp -- RTL IO
37cc577a4SJonathan Peyton  */
47cc577a4SJonathan Peyton 
57cc577a4SJonathan Peyton 
67cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
77cc577a4SJonathan Peyton //
87cc577a4SJonathan Peyton //                     The LLVM Compiler Infrastructure
97cc577a4SJonathan Peyton //
107cc577a4SJonathan Peyton // This file is dual licensed under the MIT and the University of Illinois Open
117cc577a4SJonathan Peyton // Source Licenses. See LICENSE.txt for details.
127cc577a4SJonathan Peyton //
137cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
147cc577a4SJonathan Peyton 
157cc577a4SJonathan Peyton 
167cc577a4SJonathan Peyton #include <stdio.h>
177cc577a4SJonathan Peyton #include <stdlib.h>
187cc577a4SJonathan Peyton #include <stddef.h>
197cc577a4SJonathan Peyton #include <stdarg.h>
207cc577a4SJonathan Peyton #include <string.h>
217cc577a4SJonathan Peyton #ifndef __ABSOFT_WIN
227cc577a4SJonathan Peyton # include <sys/types.h>
237cc577a4SJonathan Peyton #endif
247cc577a4SJonathan Peyton 
257cc577a4SJonathan Peyton #include "kmp_os.h"
267cc577a4SJonathan Peyton #include "kmp_lock.h"
277cc577a4SJonathan Peyton #include "kmp_str.h"
287cc577a4SJonathan Peyton #include "kmp_io.h"
297cc577a4SJonathan Peyton #include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc
307cc577a4SJonathan Peyton 
317cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
327cc577a4SJonathan Peyton # pragma warning( push )
337cc577a4SJonathan Peyton # pragma warning( disable: 271 310 )
347cc577a4SJonathan Peyton # include <windows.h>
357cc577a4SJonathan Peyton # pragma warning( pop )
367cc577a4SJonathan Peyton #endif
377cc577a4SJonathan Peyton 
387cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
397cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
407cc577a4SJonathan Peyton 
417cc577a4SJonathan Peyton kmp_bootstrap_lock_t __kmp_stdio_lock   = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_stdio_lock   ); /* Control stdio functions */
427cc577a4SJonathan Peyton kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_console_lock ); /* Control console initialization */
437cc577a4SJonathan Peyton 
447cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
457cc577a4SJonathan Peyton 
467cc577a4SJonathan Peyton     # ifdef KMP_DEBUG
477cc577a4SJonathan Peyton     /* __kmp_stdout is used only for dev build */
487cc577a4SJonathan Peyton     static HANDLE    __kmp_stdout = NULL;
497cc577a4SJonathan Peyton     # endif
507cc577a4SJonathan Peyton     static HANDLE        __kmp_stderr = NULL;
517cc577a4SJonathan Peyton     static int           __kmp_console_exists = FALSE;
527cc577a4SJonathan Peyton     static kmp_str_buf_t __kmp_console_buf;
537cc577a4SJonathan Peyton 
547cc577a4SJonathan Peyton     static int
557cc577a4SJonathan Peyton     is_console( void )
567cc577a4SJonathan Peyton     {
577cc577a4SJonathan Peyton         char buffer[ 128 ];
587cc577a4SJonathan Peyton         DWORD rc  = 0;
597cc577a4SJonathan Peyton         DWORD err = 0;
607cc577a4SJonathan Peyton         // Try to get console title.
617cc577a4SJonathan Peyton         SetLastError( 0 );
627cc577a4SJonathan Peyton             // GetConsoleTitle does not reset last error in case of success or short buffer,
637cc577a4SJonathan Peyton             // so we need to clear it explicitly.
647cc577a4SJonathan Peyton         rc = GetConsoleTitle( buffer, sizeof( buffer ) );
657cc577a4SJonathan Peyton         if ( rc == 0 ) {
667cc577a4SJonathan Peyton             // rc == 0 means getting console title failed. Let us find out why.
677cc577a4SJonathan Peyton             err = GetLastError();
687cc577a4SJonathan Peyton             // err == 0 means buffer too short (we suppose console exists).
697cc577a4SJonathan Peyton             // In Window applications we usually have err == 6 (invalid handle).
707cc577a4SJonathan Peyton         }; // if
717cc577a4SJonathan Peyton         return rc > 0 || err == 0;
727cc577a4SJonathan Peyton     }
737cc577a4SJonathan Peyton 
747cc577a4SJonathan Peyton     void
757cc577a4SJonathan Peyton     __kmp_close_console( void )
767cc577a4SJonathan Peyton     {
777cc577a4SJonathan Peyton         /* wait until user presses return before closing window */
787cc577a4SJonathan Peyton         /* TODO only close if a window was opened */
797cc577a4SJonathan Peyton         if( __kmp_console_exists ) {
807cc577a4SJonathan Peyton             #ifdef KMP_DEBUG
817cc577a4SJonathan Peyton             /* standard out is used only in dev build */
827cc577a4SJonathan Peyton             __kmp_stdout = NULL;
837cc577a4SJonathan Peyton             #endif
847cc577a4SJonathan Peyton             __kmp_stderr = NULL;
857cc577a4SJonathan Peyton             __kmp_str_buf_free( &__kmp_console_buf );
867cc577a4SJonathan Peyton             __kmp_console_exists = FALSE;
877cc577a4SJonathan Peyton         }
887cc577a4SJonathan Peyton     }
897cc577a4SJonathan Peyton 
907cc577a4SJonathan Peyton     /* For windows, call this before stdout, stderr, or stdin are used.
917cc577a4SJonathan Peyton      * It opens a console window and starts processing */
927cc577a4SJonathan Peyton     static void
937cc577a4SJonathan Peyton     __kmp_redirect_output( void )
947cc577a4SJonathan Peyton     {
957cc577a4SJonathan Peyton         __kmp_acquire_bootstrap_lock( &__kmp_console_lock );
967cc577a4SJonathan Peyton 
977cc577a4SJonathan Peyton         if( ! __kmp_console_exists ) {
987cc577a4SJonathan Peyton             #ifdef KMP_DEBUG
997cc577a4SJonathan Peyton             /* standard out is used only in dev build */
1007cc577a4SJonathan Peyton             HANDLE ho;
1017cc577a4SJonathan Peyton             #endif
1027cc577a4SJonathan Peyton             HANDLE he;
1037cc577a4SJonathan Peyton 
1047cc577a4SJonathan Peyton             __kmp_str_buf_init( &__kmp_console_buf );
1057cc577a4SJonathan Peyton 
1067cc577a4SJonathan Peyton             AllocConsole();
1077cc577a4SJonathan Peyton             // We do not check the result of AllocConsole because
1087cc577a4SJonathan Peyton             //  1. the call is harmless
1097cc577a4SJonathan Peyton             //  2. it is not clear how to communicate failue
1107cc577a4SJonathan Peyton             //  3. we will detect failure later when we get handle(s)
1117cc577a4SJonathan Peyton 
1127cc577a4SJonathan Peyton             #ifdef KMP_DEBUG
1137cc577a4SJonathan Peyton                 ho = GetStdHandle( STD_OUTPUT_HANDLE );
1147cc577a4SJonathan Peyton                 if ( ho == INVALID_HANDLE_VALUE || ho == NULL ) {
1157cc577a4SJonathan Peyton 
1167cc577a4SJonathan Peyton                     DWORD  err = GetLastError();
1177cc577a4SJonathan Peyton                     // TODO: output error somehow (maybe message box)
1187cc577a4SJonathan Peyton                     __kmp_stdout = NULL;
1197cc577a4SJonathan Peyton 
1207cc577a4SJonathan Peyton                 } else {
1217cc577a4SJonathan Peyton 
1227cc577a4SJonathan Peyton                     __kmp_stdout = ho; // temporary code, need new global for ho
1237cc577a4SJonathan Peyton 
1247cc577a4SJonathan Peyton                 }
1257cc577a4SJonathan Peyton             #endif
1267cc577a4SJonathan Peyton             he = GetStdHandle( STD_ERROR_HANDLE );
1277cc577a4SJonathan Peyton             if ( he == INVALID_HANDLE_VALUE || he == NULL ) {
1287cc577a4SJonathan Peyton 
1297cc577a4SJonathan Peyton                 DWORD  err = GetLastError();
1307cc577a4SJonathan Peyton                 // TODO: output error somehow (maybe message box)
1317cc577a4SJonathan Peyton                 __kmp_stderr = NULL;
1327cc577a4SJonathan Peyton 
1337cc577a4SJonathan Peyton             } else {
1347cc577a4SJonathan Peyton 
1357cc577a4SJonathan Peyton                 __kmp_stderr = he; // temporary code, need new global
1367cc577a4SJonathan Peyton             }
1377cc577a4SJonathan Peyton             __kmp_console_exists = TRUE;
1387cc577a4SJonathan Peyton         }
1397cc577a4SJonathan Peyton         __kmp_release_bootstrap_lock( &__kmp_console_lock );
1407cc577a4SJonathan Peyton     }
1417cc577a4SJonathan Peyton 
1427cc577a4SJonathan Peyton #else
1437cc577a4SJonathan Peyton     #define       __kmp_stderr     (stderr)
1447cc577a4SJonathan Peyton #endif /* KMP_OS_WINDOWS */
1457cc577a4SJonathan Peyton 
1467cc577a4SJonathan Peyton void
1477cc577a4SJonathan Peyton __kmp_vprintf( enum kmp_io __kmp_io, char const * format, va_list ap )
1487cc577a4SJonathan Peyton {
1497cc577a4SJonathan Peyton     #if KMP_OS_WINDOWS
1507cc577a4SJonathan Peyton         if( !__kmp_console_exists ) {
1517cc577a4SJonathan Peyton             __kmp_redirect_output();
1527cc577a4SJonathan Peyton         }
1537cc577a4SJonathan Peyton             if( ! __kmp_stderr && __kmp_io == kmp_err ) {
1547cc577a4SJonathan Peyton             return;
1557cc577a4SJonathan Peyton         }
1567cc577a4SJonathan Peyton         #ifdef KMP_DEBUG
1577cc577a4SJonathan Peyton             if( ! __kmp_stdout && __kmp_io == kmp_out ) {
1587cc577a4SJonathan Peyton                 return;
1597cc577a4SJonathan Peyton             }
1607cc577a4SJonathan Peyton         #endif
1617cc577a4SJonathan Peyton     #endif /* KMP_OS_WINDOWS */
1627cc577a4SJonathan Peyton 
1637cc577a4SJonathan Peyton     if ( __kmp_debug_buf && __kmp_debug_buffer != NULL ) {
1647cc577a4SJonathan Peyton 
1657cc577a4SJonathan Peyton         int dc = ( __kmp_debug_buf_atomic ?
1667cc577a4SJonathan Peyton                    KMP_TEST_THEN_INC32( & __kmp_debug_count) : __kmp_debug_count++ )
1677cc577a4SJonathan Peyton                    % __kmp_debug_buf_lines;
1687cc577a4SJonathan Peyton         char *db = & __kmp_debug_buffer[ dc * __kmp_debug_buf_chars ];
1697cc577a4SJonathan Peyton         int chars = 0;
1707cc577a4SJonathan Peyton 
1717cc577a4SJonathan Peyton         #ifdef KMP_DEBUG_PIDS
1727cc577a4SJonathan Peyton             chars = KMP_SNPRINTF( db, __kmp_debug_buf_chars, "pid=%d: ", (kmp_int32)getpid() );
1737cc577a4SJonathan Peyton         #endif
1747cc577a4SJonathan Peyton         chars += KMP_VSNPRINTF( db, __kmp_debug_buf_chars, format, ap );
1757cc577a4SJonathan Peyton 
1767cc577a4SJonathan Peyton         if ( chars + 1 > __kmp_debug_buf_chars ) {
1777cc577a4SJonathan Peyton             if ( chars + 1 > __kmp_debug_buf_warn_chars ) {
1787cc577a4SJonathan Peyton                 #if KMP_OS_WINDOWS
1797cc577a4SJonathan Peyton                     DWORD count;
1807cc577a4SJonathan Peyton                     __kmp_str_buf_print( &__kmp_console_buf,
1817cc577a4SJonathan Peyton                         "OMP warning: Debugging buffer overflow; increase KMP_DEBUG_BUF_CHARS to %d\n",
1827cc577a4SJonathan Peyton                         chars + 1 );
1837cc577a4SJonathan Peyton                     WriteFile( __kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used, &count, NULL );
1847cc577a4SJonathan Peyton                     __kmp_str_buf_clear( &__kmp_console_buf );
1857cc577a4SJonathan Peyton                 #else
1867cc577a4SJonathan Peyton                     fprintf( __kmp_stderr,
1877cc577a4SJonathan Peyton                          "OMP warning: Debugging buffer overflow; increase KMP_DEBUG_BUF_CHARS to %d\n",
1887cc577a4SJonathan Peyton                          chars + 1 );
1897cc577a4SJonathan Peyton                     fflush( __kmp_stderr );
1907cc577a4SJonathan Peyton                 #endif
1917cc577a4SJonathan Peyton                 __kmp_debug_buf_warn_chars = chars + 1;
1927cc577a4SJonathan Peyton             }
1937cc577a4SJonathan Peyton             /* terminate string if overflow occurred */
1947cc577a4SJonathan Peyton             db[ __kmp_debug_buf_chars - 2 ] = '\n';
1957cc577a4SJonathan Peyton             db[ __kmp_debug_buf_chars - 1 ] = '\0';
1967cc577a4SJonathan Peyton         }
1977cc577a4SJonathan Peyton     } else {
1987cc577a4SJonathan Peyton         #if KMP_OS_WINDOWS
1997cc577a4SJonathan Peyton             DWORD count;
2007cc577a4SJonathan Peyton             #ifdef KMP_DEBUG_PIDS
2017cc577a4SJonathan Peyton                 __kmp_str_buf_print( &__kmp_console_buf, "pid=%d: ",
2027cc577a4SJonathan Peyton                   (kmp_int32)getpid() );
2037cc577a4SJonathan Peyton             #endif
2047cc577a4SJonathan Peyton             __kmp_str_buf_vprint( &__kmp_console_buf, format, ap );
2057cc577a4SJonathan Peyton             WriteFile(
2067cc577a4SJonathan Peyton                 __kmp_stderr,
2077cc577a4SJonathan Peyton                 __kmp_console_buf.str,
2087cc577a4SJonathan Peyton                 __kmp_console_buf.used,
2097cc577a4SJonathan Peyton                 &count,
2107cc577a4SJonathan Peyton                 NULL
2117cc577a4SJonathan Peyton             );
2127cc577a4SJonathan Peyton             __kmp_str_buf_clear( &__kmp_console_buf );
2137cc577a4SJonathan Peyton         #else
2147cc577a4SJonathan Peyton             #ifdef KMP_DEBUG_PIDS
2157cc577a4SJonathan Peyton                 fprintf( __kmp_stderr, "pid=%d: ", (kmp_int32)getpid() );
2167cc577a4SJonathan Peyton             #endif
2177cc577a4SJonathan Peyton             vfprintf( __kmp_stderr, format, ap );
2187cc577a4SJonathan Peyton             fflush( __kmp_stderr );
2197cc577a4SJonathan Peyton         #endif
2207cc577a4SJonathan Peyton     }
2217cc577a4SJonathan Peyton }
2227cc577a4SJonathan Peyton 
2237cc577a4SJonathan Peyton void
2247cc577a4SJonathan Peyton __kmp_printf( char const * format, ... )
2257cc577a4SJonathan Peyton {
2267cc577a4SJonathan Peyton     va_list ap;
2277cc577a4SJonathan Peyton     va_start( ap, format );
2287cc577a4SJonathan Peyton 
2297cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & __kmp_stdio_lock );
2307cc577a4SJonathan Peyton     __kmp_vprintf( kmp_err, format, ap );
2317cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & __kmp_stdio_lock );
2327cc577a4SJonathan Peyton 
2337cc577a4SJonathan Peyton     va_end( ap );
2347cc577a4SJonathan Peyton }
2357cc577a4SJonathan Peyton 
2367cc577a4SJonathan Peyton void
2377cc577a4SJonathan Peyton __kmp_printf_no_lock( char const * format, ... )
2387cc577a4SJonathan Peyton {
2397cc577a4SJonathan Peyton     va_list ap;
2407cc577a4SJonathan Peyton     va_start( ap, format );
2417cc577a4SJonathan Peyton 
2427cc577a4SJonathan Peyton     __kmp_vprintf( kmp_err, format, ap );
2437cc577a4SJonathan Peyton 
2447cc577a4SJonathan Peyton     va_end( ap );
2457cc577a4SJonathan Peyton }
2467cc577a4SJonathan Peyton 
2477cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
2487cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
249