blob: 4e6ea6a38a33ef81ce82e66f4d62a07b1562a9f0 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
Jonathan Peytonde4749b2016-12-14 23:01:24 +00002 * kmp_io.cpp -- RTL IO
Jim Cownie5e8470a2013-09-27 10:38:44 +00003 */
4
Jim Cownie5e8470a2013-09-27 10:38:44 +00005//===----------------------------------------------------------------------===//
6//
Chandler Carruth57b08b02019-01-19 10:56:40 +00007// 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
Jim Cownie5e8470a2013-09-27 10:38:44 +000010//
11//===----------------------------------------------------------------------===//
12
Jonathan Peyton30419822017-05-12 18:01:32 +000013#include <stdarg.h>
14#include <stddef.h>
Jim Cownie5e8470a2013-09-27 10:38:44 +000015#include <stdio.h>
16#include <stdlib.h>
Jim Cownie5e8470a2013-09-27 10:38:44 +000017#include <string.h>
18#ifndef __ABSOFT_WIN
Jonathan Peyton30419822017-05-12 18:01:32 +000019#include <sys/types.h>
Jim Cownie5e8470a2013-09-27 10:38:44 +000020#endif
21
Jim Cownie5e8470a2013-09-27 10:38:44 +000022#include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc
Jonathan Peyton30419822017-05-12 18:01:32 +000023#include "kmp_io.h"
24#include "kmp_lock.h"
25#include "kmp_os.h"
26#include "kmp_str.h"
Jim Cownie5e8470a2013-09-27 10:38:44 +000027
28#if KMP_OS_WINDOWS
Andrey Churbanovf700e9e2018-12-10 13:45:00 +000029#if KMP_MSVC_COMPAT
Jonathan Peyton30419822017-05-12 18:01:32 +000030#pragma warning(push)
31#pragma warning(disable : 271 310)
Andrey Churbanovf700e9e2018-12-10 13:45:00 +000032#endif
Jonathan Peyton30419822017-05-12 18:01:32 +000033#include <windows.h>
Andrey Churbanovf700e9e2018-12-10 13:45:00 +000034#if KMP_MSVC_COMPAT
Jonathan Peyton30419822017-05-12 18:01:32 +000035#pragma warning(pop)
Jim Cownie5e8470a2013-09-27 10:38:44 +000036#endif
Andrey Churbanovf700e9e2018-12-10 13:45:00 +000037#endif
Jim Cownie5e8470a2013-09-27 10:38:44 +000038
39/* ------------------------------------------------------------------------ */
Jim Cownie5e8470a2013-09-27 10:38:44 +000040
Jonathan Peyton30419822017-05-12 18:01:32 +000041kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
42 __kmp_stdio_lock); /* Control stdio functions */
43kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
44 __kmp_console_lock); /* Control console initialization */
Jim Cownie5e8470a2013-09-27 10:38:44 +000045
46#if KMP_OS_WINDOWS
47
Jonathan Peyton30419822017-05-12 18:01:32 +000048static HANDLE __kmp_stdout = NULL;
Jonathan Peyton30419822017-05-12 18:01:32 +000049static HANDLE __kmp_stderr = NULL;
50static int __kmp_console_exists = FALSE;
51static kmp_str_buf_t __kmp_console_buf;
Jim Cownie5e8470a2013-09-27 10:38:44 +000052
Jonathan Peyton30419822017-05-12 18:01:32 +000053static 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).
Jonathan Peytonbd3a7632017-09-27 20:36:27 +000067 }
Jonathan Peyton30419822017-05-12 18:01:32 +000068 return rc > 0 || err == 0;
69}
70
71void __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) {
Jonathan Peyton30419822017-05-12 18:01:32 +000075 __kmp_stdout = NULL;
Jonathan Peyton30419822017-05-12 18:01:32 +000076 __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 */
84static void __kmp_redirect_output(void) {
85 __kmp_acquire_bootstrap_lock(&__kmp_console_lock);
86
87 if (!__kmp_console_exists) {
Jonathan Peyton30419822017-05-12 18:01:32 +000088 HANDLE ho;
Jonathan Peyton30419822017-05-12 18:01:32 +000089 HANDLE he;
90
91 __kmp_str_buf_init(&__kmp_console_buf);
92
93 AllocConsole();
Jonathan Peyton6d88e042018-12-13 23:14:24 +000094 // 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)
Jonathan Peyton30419822017-05-12 18:01:32 +000098
Jonathan Peyton30419822017-05-12 18:01:32 +000099 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000109 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000110 he = GetStdHandle(STD_ERROR_HANDLE);
111 if (he == INVALID_HANDLE_VALUE || he == NULL) {
Jim Cownie5e8470a2013-09-27 10:38:44 +0000112
Jonathan Peyton30419822017-05-12 18:01:32 +0000113 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
Jim Cownie5e8470a2013-09-27 10:38:44 +0000120 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000121 __kmp_console_exists = TRUE;
122 }
123 __kmp_release_bootstrap_lock(&__kmp_console_lock);
124}
Jim Cownie5e8470a2013-09-27 10:38:44 +0000125
126#else
Jonathan Peyton30419822017-05-12 18:01:32 +0000127#define __kmp_stderr (stderr)
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000128#define __kmp_stdout (stdout)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000129#endif /* KMP_OS_WINDOWS */
130
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000131void __kmp_vprintf(enum kmp_io out_stream, char const *format, va_list ap) {
Jonathan Peyton30419822017-05-12 18:01:32 +0000132#if KMP_OS_WINDOWS
133 if (!__kmp_console_exists) {
134 __kmp_redirect_output();
135 }
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000136 if (!__kmp_stderr && out_stream == kmp_err) {
Jonathan Peyton30419822017-05-12 18:01:32 +0000137 return;
138 }
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000139 if (!__kmp_stdout && out_stream == kmp_out) {
Jonathan Peyton30419822017-05-12 18:01:32 +0000140 return;
141 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000142#endif /* KMP_OS_WINDOWS */
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000143 auto stream = ((out_stream == kmp_out) ? __kmp_stdout : __kmp_stderr);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000144
Jonathan Peyton30419822017-05-12 18:01:32 +0000145 if (__kmp_debug_buf && __kmp_debug_buffer != NULL) {
Jim Cownie5e8470a2013-09-27 10:38:44 +0000146
Jonathan Peyton37e2ef52018-07-09 17:36:22 +0000147 int dc = __kmp_debug_count++ % __kmp_debug_buf_lines;
Jonathan Peyton30419822017-05-12 18:01:32 +0000148 char *db = &__kmp_debug_buffer[dc * __kmp_debug_buf_chars];
149 int chars = 0;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000150
Jonathan Peyton30419822017-05-12 18:01:32 +0000151#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);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000156
Jonathan Peyton30419822017-05-12 18:01:32 +0000157 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);
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000165 WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
166 NULL);
Jonathan Peyton30419822017-05-12 18:01:32 +0000167 __kmp_str_buf_clear(&__kmp_console_buf);
168#else
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000169 fprintf(stream, "OMP warning: Debugging buffer overflow; "
170 "increase KMP_DEBUG_BUF_CHARS to %d\n",
Jonathan Peyton30419822017-05-12 18:01:32 +0000171 chars + 1);
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000172 fflush(stream);
Jonathan Peyton30419822017-05-12 18:01:32 +0000173#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';
Jim Cownie5e8470a2013-09-27 10:38:44 +0000179 }
Jonathan Peyton30419822017-05-12 18:01:32 +0000180 } 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);
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000187 WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
188 NULL);
Jonathan Peyton30419822017-05-12 18:01:32 +0000189 __kmp_str_buf_clear(&__kmp_console_buf);
190#else
191#ifdef KMP_DEBUG_PIDS
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000192 fprintf(stream, "pid=%d: ", (kmp_int32)getpid());
Jonathan Peyton30419822017-05-12 18:01:32 +0000193#endif
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000194 vfprintf(stream, format, ap);
195 fflush(stream);
Jonathan Peyton30419822017-05-12 18:01:32 +0000196#endif
197 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000198}
199
Jonathan Peyton30419822017-05-12 18:01:32 +0000200void __kmp_printf(char const *format, ...) {
201 va_list ap;
202 va_start(ap, format);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000203
Jonathan Peyton30419822017-05-12 18:01:32 +0000204 __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
205 __kmp_vprintf(kmp_err, format, ap);
206 __kmp_release_bootstrap_lock(&__kmp_stdio_lock);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000207
Jonathan Peyton30419822017-05-12 18:01:32 +0000208 va_end(ap);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000209}
210
Jonathan Peyton30419822017-05-12 18:01:32 +0000211void __kmp_printf_no_lock(char const *format, ...) {
212 va_list ap;
213 va_start(ap, format);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000214
Jonathan Peyton30419822017-05-12 18:01:32 +0000215 __kmp_vprintf(kmp_err, format, ap);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000216
Jonathan Peyton30419822017-05-12 18:01:32 +0000217 va_end(ap);
Jim Cownie5e8470a2013-09-27 10:38:44 +0000218}
Jonathan Peyton6d88e042018-12-13 23:14:24 +0000219
220void __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}