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