LLVM OpenMP* Runtime Library
kmp_io.c
1 /*
2  * KMP_IO.c -- 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 /* ------------------------------------------------------------------------ */