LLVM OpenMP* Runtime Library
kmp_io.cpp
1 /*
2  * kmp_io.cpp -- 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 <stdarg.h>
17 #include <stddef.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #ifndef __ABSOFT_WIN
22 #include <sys/types.h>
23 #endif
24 
25 #include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc
26 #include "kmp_io.h"
27 #include "kmp_lock.h"
28 #include "kmp_os.h"
29 #include "kmp_str.h"
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 kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
41  __kmp_stdio_lock); /* Control stdio functions */
42 kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
43  __kmp_console_lock); /* Control console initialization */
44 
45 #if KMP_OS_WINDOWS
46 
47 #ifdef KMP_DEBUG
48 /* __kmp_stdout is used only for dev build */
49 static HANDLE __kmp_stdout = NULL;
50 #endif
51 static HANDLE __kmp_stderr = NULL;
52 static int __kmp_console_exists = FALSE;
53 static kmp_str_buf_t __kmp_console_buf;
54 
55 static int is_console(void) {
56  char buffer[128];
57  DWORD rc = 0;
58  DWORD err = 0;
59  // Try to get console title.
60  SetLastError(0);
61  // GetConsoleTitle does not reset last error in case of success or short
62  // buffer, so we need to clear it explicitly.
63  rc = GetConsoleTitle(buffer, sizeof(buffer));
64  if (rc == 0) {
65  // rc == 0 means getting console title failed. Let us find out why.
66  err = GetLastError();
67  // err == 0 means buffer too short (we suppose console exists).
68  // In Window applications we usually have err == 6 (invalid handle).
69  }; // if
70  return rc > 0 || err == 0;
71 }
72 
73 void __kmp_close_console(void) {
74  /* wait until user presses return before closing window */
75  /* TODO only close if a window was opened */
76  if (__kmp_console_exists) {
77 #ifdef KMP_DEBUG
78  /* standard out is used only in dev build */
79  __kmp_stdout = NULL;
80 #endif
81  __kmp_stderr = NULL;
82  __kmp_str_buf_free(&__kmp_console_buf);
83  __kmp_console_exists = FALSE;
84  }
85 }
86 
87 /* For windows, call this before stdout, stderr, or stdin are used.
88  It opens a console window and starts processing */
89 static void __kmp_redirect_output(void) {
90  __kmp_acquire_bootstrap_lock(&__kmp_console_lock);
91 
92  if (!__kmp_console_exists) {
93 #ifdef KMP_DEBUG
94  /* standard out is used only in dev build */
95  HANDLE ho;
96 #endif
97  HANDLE he;
98 
99  __kmp_str_buf_init(&__kmp_console_buf);
100 
101  AllocConsole();
102 // We do not check the result of AllocConsole because
103 // 1. the call is harmless
104 // 2. it is not clear how to communicate failue
105 // 3. we will detect failure later when we get handle(s)
106 
107 #ifdef KMP_DEBUG
108  ho = GetStdHandle(STD_OUTPUT_HANDLE);
109  if (ho == INVALID_HANDLE_VALUE || ho == NULL) {
110 
111  DWORD err = GetLastError();
112  // TODO: output error somehow (maybe message box)
113  __kmp_stdout = NULL;
114 
115  } else {
116 
117  __kmp_stdout = ho; // temporary code, need new global for ho
118  }
119 #endif
120  he = GetStdHandle(STD_ERROR_HANDLE);
121  if (he == INVALID_HANDLE_VALUE || he == NULL) {
122 
123  DWORD err = GetLastError();
124  // TODO: output error somehow (maybe message box)
125  __kmp_stderr = NULL;
126 
127  } else {
128 
129  __kmp_stderr = he; // temporary code, need new global
130  }
131  __kmp_console_exists = TRUE;
132  }
133  __kmp_release_bootstrap_lock(&__kmp_console_lock);
134 }
135 
136 #else
137 #define __kmp_stderr (stderr)
138 #endif /* KMP_OS_WINDOWS */
139 
140 void __kmp_vprintf(enum kmp_io __kmp_io, char const *format, va_list ap) {
141 #if KMP_OS_WINDOWS
142  if (!__kmp_console_exists) {
143  __kmp_redirect_output();
144  }
145  if (!__kmp_stderr && __kmp_io == kmp_err) {
146  return;
147  }
148 #ifdef KMP_DEBUG
149  if (!__kmp_stdout && __kmp_io == kmp_out) {
150  return;
151  }
152 #endif
153 #endif /* KMP_OS_WINDOWS */
154 
155  if (__kmp_debug_buf && __kmp_debug_buffer != NULL) {
156 
157  int dc = (__kmp_debug_buf_atomic ? KMP_TEST_THEN_INC32(&__kmp_debug_count)
158  : __kmp_debug_count++) %
159  __kmp_debug_buf_lines;
160  char *db = &__kmp_debug_buffer[dc * __kmp_debug_buf_chars];
161  int chars = 0;
162 
163 #ifdef KMP_DEBUG_PIDS
164  chars = KMP_SNPRINTF(db, __kmp_debug_buf_chars, "pid=%d: ",
165  (kmp_int32)getpid());
166 #endif
167  chars += KMP_VSNPRINTF(db, __kmp_debug_buf_chars, format, ap);
168 
169  if (chars + 1 > __kmp_debug_buf_chars) {
170  if (chars + 1 > __kmp_debug_buf_warn_chars) {
171 #if KMP_OS_WINDOWS
172  DWORD count;
173  __kmp_str_buf_print(&__kmp_console_buf, "OMP warning: Debugging buffer "
174  "overflow; increase "
175  "KMP_DEBUG_BUF_CHARS to %d\n",
176  chars + 1);
177  WriteFile(__kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used,
178  &count, NULL);
179  __kmp_str_buf_clear(&__kmp_console_buf);
180 #else
181  fprintf(__kmp_stderr, "OMP warning: Debugging buffer overflow; "
182  "increase KMP_DEBUG_BUF_CHARS to %d\n",
183  chars + 1);
184  fflush(__kmp_stderr);
185 #endif
186  __kmp_debug_buf_warn_chars = chars + 1;
187  }
188  /* terminate string if overflow occurred */
189  db[__kmp_debug_buf_chars - 2] = '\n';
190  db[__kmp_debug_buf_chars - 1] = '\0';
191  }
192  } else {
193 #if KMP_OS_WINDOWS
194  DWORD count;
195 #ifdef KMP_DEBUG_PIDS
196  __kmp_str_buf_print(&__kmp_console_buf, "pid=%d: ", (kmp_int32)getpid());
197 #endif
198  __kmp_str_buf_vprint(&__kmp_console_buf, format, ap);
199  WriteFile(__kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used,
200  &count, NULL);
201  __kmp_str_buf_clear(&__kmp_console_buf);
202 #else
203 #ifdef KMP_DEBUG_PIDS
204  fprintf(__kmp_stderr, "pid=%d: ", (kmp_int32)getpid());
205 #endif
206  vfprintf(__kmp_stderr, format, ap);
207  fflush(__kmp_stderr);
208 #endif
209  }
210 }
211 
212 void __kmp_printf(char const *format, ...) {
213  va_list ap;
214  va_start(ap, format);
215 
216  __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
217  __kmp_vprintf(kmp_err, format, ap);
218  __kmp_release_bootstrap_lock(&__kmp_stdio_lock);
219 
220  va_end(ap);
221 }
222 
223 void __kmp_printf_no_lock(char const *format, ...) {
224  va_list ap;
225  va_start(ap, format);
226 
227  __kmp_vprintf(kmp_err, format, ap);
228 
229  va_end(ap);
230 }