Intel® OpenMP* Runtime Library
 All Classes Functions Variables Typedefs Enumerations Enumerator Groups Pages
kmp_io.c
1 /*
2  * KMP_IO.c -- RTL IO
3  */
4 
5 /* <copyright>
6  Copyright (c) 1997-2015 Intel Corporation. All Rights Reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions
10  are met:
11 
12  * Redistributions of source code must retain the above copyright
13  notice, this list of conditions and the following disclaimer.
14  * Redistributions in binary form must reproduce the above copyright
15  notice, this list of conditions and the following disclaimer in the
16  documentation and/or other materials provided with the distribution.
17  * Neither the name of Intel Corporation nor the names of its
18  contributors may be used to endorse or promote products derived
19  from this software without specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 </copyright> */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #ifndef __ABSOFT_WIN
41 # include <sys/types.h>
42 #endif
43 
44 #include "kmp_os.h"
45 #include "kmp_lock.h"
46 #include "kmp_str.h"
47 #include "kmp_io.h"
48 #include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc
49 
50 #if KMP_OS_WINDOWS
51 # pragma warning( push )
52 # pragma warning( disable: 271 310 )
53 # include <windows.h>
54 # pragma warning( pop )
55 #endif
56 
57 /* ------------------------------------------------------------------------ */
58 /* ------------------------------------------------------------------------ */
59 
60 kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_stdio_lock ); /* Control stdio functions */
61 kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_console_lock ); /* Control console initialization */
62 
63 #if KMP_OS_WINDOWS
64 
65  # ifdef KMP_DEBUG
66  /* __kmp_stdout is used only for dev build */
67  static HANDLE __kmp_stdout = NULL;
68  # endif
69  static HANDLE __kmp_stderr = NULL;
70  static int __kmp_console_exists = FALSE;
71  static kmp_str_buf_t __kmp_console_buf;
72 
73  static int
74  is_console( void )
75  {
76  char buffer[ 128 ];
77  DWORD rc = 0;
78  DWORD err = 0;
79  // Try to get console title.
80  SetLastError( 0 );
81  // GetConsoleTitle does not reset last error in case of success or short buffer,
82  // so we need to clear it explicitly.
83  rc = GetConsoleTitle( buffer, sizeof( buffer ) );
84  if ( rc == 0 ) {
85  // rc == 0 means getting console title failed. Let us find out why.
86  err = GetLastError();
87  // err == 0 means buffer too short (we suppose console exists).
88  // In Window applications we usually have err == 6 (invalid handle).
89  }; // if
90  return rc > 0 || err == 0;
91  }
92 
93  void
94  __kmp_close_console( void )
95  {
96  /* wait until user presses return before closing window */
97  /* TODO only close if a window was opened */
98  if( __kmp_console_exists ) {
99  #ifdef KMP_DEBUG
100  /* standard out is used only in dev build */
101  __kmp_stdout = NULL;
102  #endif
103  __kmp_stderr = NULL;
104  __kmp_str_buf_free( &__kmp_console_buf );
105  __kmp_console_exists = FALSE;
106  }
107  }
108 
109  /* For windows, call this before stdout, stderr, or stdin are used.
110  * It opens a console window and starts processing */
111  static void
112  __kmp_redirect_output( void )
113  {
114  __kmp_acquire_bootstrap_lock( &__kmp_console_lock );
115 
116  if( ! __kmp_console_exists ) {
117  #ifdef KMP_DEBUG
118  /* standard out is used only in dev build */
119  HANDLE ho;
120  #endif
121  HANDLE he;
122 
123  __kmp_str_buf_init( &__kmp_console_buf );
124 
125  AllocConsole();
126  // We do not check the result of AllocConsole because
127  // 1. the call is harmless
128  // 2. it is not clear how to communicate failue
129  // 3. we will detect failure later when we get handle(s)
130 
131  #ifdef KMP_DEBUG
132  ho = GetStdHandle( STD_OUTPUT_HANDLE );
133  if ( ho == INVALID_HANDLE_VALUE || ho == NULL ) {
134 
135  DWORD err = GetLastError();
136  // TODO: output error somehow (maybe message box)
137  __kmp_stdout = NULL;
138 
139  } else {
140 
141  __kmp_stdout = ho; // temporary code, need new global for ho
142 
143  }
144  #endif
145  he = GetStdHandle( STD_ERROR_HANDLE );
146  if ( he == INVALID_HANDLE_VALUE || he == NULL ) {
147 
148  DWORD err = GetLastError();
149  // TODO: output error somehow (maybe message box)
150  __kmp_stderr = NULL;
151 
152  } else {
153 
154  __kmp_stderr = he; // temporary code, need new global
155  }
156  __kmp_console_exists = TRUE;
157  }
158  __kmp_release_bootstrap_lock( &__kmp_console_lock );
159  }
160 
161 #else
162  #define __kmp_stderr (stderr)
163 #endif /* KMP_OS_WINDOWS */
164 
165 void
166 __kmp_vprintf( enum kmp_io __kmp_io, char const * format, va_list ap )
167 {
168  #if KMP_OS_WINDOWS
169  if( !__kmp_console_exists ) {
170  __kmp_redirect_output();
171  }
172  if( ! __kmp_stderr && __kmp_io == kmp_err ) {
173  return;
174  }
175  #ifdef KMP_DEBUG
176  if( ! __kmp_stdout && __kmp_io == kmp_out ) {
177  return;
178  }
179  #endif
180  #endif /* KMP_OS_WINDOWS */
181 
182  if ( __kmp_debug_buf && __kmp_debug_buffer != NULL ) {
183 
184  int dc = ( __kmp_debug_buf_atomic ?
185  KMP_TEST_THEN_INC32( & __kmp_debug_count) : __kmp_debug_count++ )
186  % __kmp_debug_buf_lines;
187  char *db = & __kmp_debug_buffer[ dc * __kmp_debug_buf_chars ];
188  int chars = 0;
189 
190  #ifdef KMP_DEBUG_PIDS
191  chars = KMP_SNPRINTF( db, __kmp_debug_buf_chars, "pid=%d: ", (kmp_int32)getpid() );
192  #endif
193  chars += KMP_VSNPRINTF( db, __kmp_debug_buf_chars, format, ap );
194 
195  if ( chars + 1 > __kmp_debug_buf_chars ) {
196  if ( chars + 1 > __kmp_debug_buf_warn_chars ) {
197  #if KMP_OS_WINDOWS
198  DWORD count;
199  __kmp_str_buf_print( &__kmp_console_buf,
200  "OMP warning: Debugging buffer overflow; increase KMP_DEBUG_BUF_CHARS to %d\n",
201  chars + 1 );
202  WriteFile( __kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used, &count, NULL );
203  __kmp_str_buf_clear( &__kmp_console_buf );
204  #else
205  fprintf( __kmp_stderr,
206  "OMP warning: Debugging buffer overflow; increase KMP_DEBUG_BUF_CHARS to %d\n",
207  chars + 1 );
208  fflush( __kmp_stderr );
209  #endif
210  __kmp_debug_buf_warn_chars = chars + 1;
211  }
212  /* terminate string if overflow occurred */
213  db[ __kmp_debug_buf_chars - 2 ] = '\n';
214  db[ __kmp_debug_buf_chars - 1 ] = '\0';
215  }
216  } else {
217  #if KMP_OS_WINDOWS
218  DWORD count;
219  #ifdef KMP_DEBUG_PIDS
220  __kmp_str_buf_print( &__kmp_console_buf, "pid=%d: ",
221  (kmp_int32)getpid() );
222  #endif
223  __kmp_str_buf_vprint( &__kmp_console_buf, format, ap );
224  WriteFile(
225  __kmp_stderr,
226  __kmp_console_buf.str,
227  __kmp_console_buf.used,
228  &count,
229  NULL
230  );
231  __kmp_str_buf_clear( &__kmp_console_buf );
232  #else
233  #ifdef KMP_DEBUG_PIDS
234  fprintf( __kmp_stderr, "pid=%d: ", (kmp_int32)getpid() );
235  #endif
236  vfprintf( __kmp_stderr, format, ap );
237  fflush( __kmp_stderr );
238  #endif
239  }
240 }
241 
242 void
243 __kmp_printf( char const * format, ... )
244 {
245  va_list ap;
246  va_start( ap, format );
247 
248  __kmp_acquire_bootstrap_lock( & __kmp_stdio_lock );
249  __kmp_vprintf( kmp_err, format, ap );
250  __kmp_release_bootstrap_lock( & __kmp_stdio_lock );
251 
252  va_end( ap );
253 }
254 
255 void
256 __kmp_printf_no_lock( char const * format, ... )
257 {
258  va_list ap;
259  va_start( ap, format );
260 
261  __kmp_vprintf( kmp_err, format, ap );
262 
263  va_end( ap );
264 }
265 
266 /* ------------------------------------------------------------------------ */
267 /* ------------------------------------------------------------------------ */