blob: 88a2c15377c2da69d85e0d4851d2b9fa772387e4 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
Jonathan Peytonde4749b2016-12-14 23:01:24 +00002 * kmp_io.cpp -- RTL IO
Jim Cownie5e8470a2013-09-27 10:38:44 +00003 */
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
41kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_stdio_lock ); /* Control stdio functions */
42kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_console_lock ); /* Control console initialization */
43
44#if KMP_OS_WINDOWS
45
Jonathan Peyton61118492016-05-20 19:03:38 +000046 # ifdef KMP_DEBUG
Jim Cownie5e8470a2013-09-27 10:38:44 +000047 /* __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 ) {
Jonathan Peyton61118492016-05-20 19:03:38 +000080 #ifdef KMP_DEBUG
Jim Cownie5e8470a2013-09-27 10:38:44 +000081 /* 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 ) {
Jonathan Peyton61118492016-05-20 19:03:38 +000098 #ifdef KMP_DEBUG
Jim Cownie5e8470a2013-09-27 10:38:44 +000099 /* 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
146void
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
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000172 chars = KMP_SNPRINTF( db, __kmp_debug_buf_chars, "pid=%d: ", (kmp_int32)getpid() );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000173 #endif
Andrey Churbanov74bf17b2015-04-02 13:27:08 +0000174 chars += KMP_VSNPRINTF( db, __kmp_debug_buf_chars, format, ap );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000175
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
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000201 __kmp_str_buf_print( &__kmp_console_buf, "pid=%d: ",
202 (kmp_int32)getpid() );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000203 #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
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000215 fprintf( __kmp_stderr, "pid=%d: ", (kmp_int32)getpid() );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000216 #endif
217 vfprintf( __kmp_stderr, format, ap );
218 fflush( __kmp_stderr );
219 #endif
220 }
221}
222
223void
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
236void
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/* ------------------------------------------------------------------------ */