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 | void __kmp_close_console(void) { |
54 | /* wait until user presses return before closing window */ |
55 | /* TODO only close if a window was opened */ |
56 | if (__kmp_console_exists) { |
57 | __kmp_stdout = NULL; |
58 | __kmp_stderr = NULL; |
59 | __kmp_str_buf_free(&__kmp_console_buf); |
60 | __kmp_console_exists = FALSE; |
61 | } |
62 | } |
63 | |
64 | /* For windows, call this before stdout, stderr, or stdin are used. |
65 | It opens a console window and starts processing */ |
66 | static void __kmp_redirect_output(void) { |
67 | __kmp_acquire_bootstrap_lock(&__kmp_console_lock); |
68 | |
69 | if (!__kmp_console_exists) { |
70 | HANDLE ho; |
71 | HANDLE he; |
72 | |
73 | __kmp_str_buf_init(&__kmp_console_buf); |
74 | |
75 | AllocConsole(); |
76 | // We do not check the result of AllocConsole because |
77 | // 1. the call is harmless |
78 | // 2. it is not clear how to communicate failue |
79 | // 3. we will detect failure later when we get handle(s) |
80 | |
81 | ho = GetStdHandle(STD_OUTPUT_HANDLE); |
82 | if (ho == INVALID_HANDLE_VALUE || ho == NULL) { |
83 | |
84 | DWORD err = GetLastError(); |
85 | // TODO: output error somehow (maybe message box) |
86 | (void)err; |
87 | __kmp_stdout = NULL; |
88 | |
89 | } else { |
90 | |
91 | __kmp_stdout = ho; // temporary code, need new global for ho |
92 | } |
93 | he = GetStdHandle(STD_ERROR_HANDLE); |
94 | if (he == INVALID_HANDLE_VALUE || he == NULL) { |
95 | |
96 | DWORD err = GetLastError(); |
97 | // TODO: output error somehow (maybe message box) |
98 | (void)err; |
99 | __kmp_stderr = NULL; |
100 | |
101 | } else { |
102 | |
103 | __kmp_stderr = he; // temporary code, need new global |
104 | } |
105 | __kmp_console_exists = TRUE; |
106 | } |
107 | __kmp_release_bootstrap_lock(&__kmp_console_lock); |
108 | } |
109 | |
110 | #else |
111 | #define __kmp_stderr (stderr) |
112 | #define __kmp_stdout (stdout) |
113 | #endif /* KMP_OS_WINDOWS */ |
114 | |
115 | void __kmp_vprintf(enum kmp_io out_stream, char const *format, va_list ap) { |
116 | #if KMP_OS_WINDOWS |
117 | if (!__kmp_console_exists) { |
118 | __kmp_redirect_output(); |
119 | } |
120 | if (!__kmp_stderr && out_stream == kmp_err) { |
121 | return; |
122 | } |
123 | if (!__kmp_stdout && out_stream == kmp_out) { |
124 | return; |
125 | } |
126 | #endif /* KMP_OS_WINDOWS */ |
127 | auto stream = ((out_stream == kmp_out) ? __kmp_stdout : __kmp_stderr); |
128 | |
129 | if (__kmp_debug_buf && __kmp_debug_buffer != NULL) { |
130 | |
131 | int dc = __kmp_debug_count++ % __kmp_debug_buf_lines; |
132 | char *db = &__kmp_debug_buffer[dc * __kmp_debug_buf_chars]; |
133 | int chars = 0; |
134 | |
135 | #ifdef KMP_DEBUG_PIDS |
136 | chars = KMP_SNPRINTF(db, __kmp_debug_buf_chars, |
137 | "pid=%d: " , (kmp_int32)getpid()); |
138 | #endif |
139 | chars += KMP_VSNPRINTF(s: db, maxlen: __kmp_debug_buf_chars, format: format, arg: ap); |
140 | |
141 | if (chars + 1 > __kmp_debug_buf_chars) { |
142 | if (chars + 1 > __kmp_debug_buf_warn_chars) { |
143 | #if KMP_OS_WINDOWS |
144 | DWORD count; |
145 | __kmp_str_buf_print(&__kmp_console_buf, |
146 | "OMP warning: Debugging buffer " |
147 | "overflow; increase " |
148 | "KMP_DEBUG_BUF_CHARS to %d\n" , |
149 | chars + 1); |
150 | WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count, |
151 | NULL); |
152 | __kmp_str_buf_clear(&__kmp_console_buf); |
153 | #else |
154 | fprintf(stream: stream, |
155 | format: "OMP warning: Debugging buffer overflow; " |
156 | "increase KMP_DEBUG_BUF_CHARS to %d\n" , |
157 | chars + 1); |
158 | fflush(stream: stream); |
159 | #endif |
160 | __kmp_debug_buf_warn_chars = chars + 1; |
161 | } |
162 | /* terminate string if overflow occurred */ |
163 | db[__kmp_debug_buf_chars - 2] = '\n'; |
164 | db[__kmp_debug_buf_chars - 1] = '\0'; |
165 | } |
166 | } else { |
167 | #if KMP_OS_WINDOWS |
168 | DWORD count; |
169 | #ifdef KMP_DEBUG_PIDS |
170 | __kmp_str_buf_print(&__kmp_console_buf, "pid=%d: " , (kmp_int32)getpid()); |
171 | #endif |
172 | __kmp_str_buf_vprint(&__kmp_console_buf, format, ap); |
173 | WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count, |
174 | NULL); |
175 | __kmp_str_buf_clear(&__kmp_console_buf); |
176 | #else |
177 | #ifdef KMP_DEBUG_PIDS |
178 | fprintf(stream, "pid=%d: " , (kmp_int32)getpid()); |
179 | #endif |
180 | vfprintf(s: stream, format: format, arg: ap); |
181 | fflush(stream: stream); |
182 | #endif |
183 | } |
184 | } |
185 | |
186 | void __kmp_printf(char const *format, ...) { |
187 | va_list ap; |
188 | va_start(ap, format); |
189 | |
190 | __kmp_acquire_bootstrap_lock(lck: &__kmp_stdio_lock); |
191 | __kmp_vprintf(out_stream: kmp_err, format, ap); |
192 | __kmp_release_bootstrap_lock(lck: &__kmp_stdio_lock); |
193 | |
194 | va_end(ap); |
195 | } |
196 | |
197 | void __kmp_printf_no_lock(char const *format, ...) { |
198 | va_list ap; |
199 | va_start(ap, format); |
200 | |
201 | __kmp_vprintf(out_stream: kmp_err, format, ap); |
202 | |
203 | va_end(ap); |
204 | } |
205 | |
206 | void __kmp_fprintf(enum kmp_io stream, char const *format, ...) { |
207 | va_list ap; |
208 | va_start(ap, format); |
209 | |
210 | __kmp_acquire_bootstrap_lock(lck: &__kmp_stdio_lock); |
211 | __kmp_vprintf(out_stream: stream, format, ap); |
212 | __kmp_release_bootstrap_lock(lck: &__kmp_stdio_lock); |
213 | |
214 | va_end(ap); |
215 | } |
216 | |