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 }
231