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