216 lines · cpp
1/*2 * kmp_io.cpp -- RTL IO3 */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-exception10//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_WIN19#include <sys/types.h>20#endif21 22#include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc23#include "kmp_io.h"24#include "kmp_lock.h"25#include "kmp_os.h"26#include "kmp_str.h"27 28#if KMP_OS_WINDOWS29#if KMP_MSVC_COMPAT30#pragma warning(push)31#pragma warning(disable : 271 310)32#endif33#include <windows.h>34#if KMP_MSVC_COMPAT35#pragma warning(pop)36#endif37#endif38 39/* ------------------------------------------------------------------------ */40 41kmp_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 */45 46#if KMP_OS_WINDOWS47 48static HANDLE __kmp_stdout = NULL;49static HANDLE __kmp_stderr = NULL;50static int __kmp_console_exists = FALSE;51static kmp_str_buf_t __kmp_console_buf;52 53void __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 */66static 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 because77 // 1. the call is harmless78 // 2. it is not clear how to communicate failue79 // 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 ho92 }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 global104 }105 __kmp_console_exists = TRUE;106 }107 __kmp_release_bootstrap_lock(&__kmp_console_lock);108}109 110#else111#define __kmp_stderr (stderr)112#define __kmp_stdout (stdout)113#endif /* KMP_OS_WINDOWS */114 115void __kmp_vprintf(enum kmp_io out_stream, char const *format, va_list ap) {116#if KMP_OS_WINDOWS117 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_PIDS136 chars = KMP_SNPRINTF(db, __kmp_debug_buf_chars,137 "pid=%d: ", (kmp_int32)getpid());138#endif139 chars += KMP_VSNPRINTF(db, __kmp_debug_buf_chars, format, ap);140 141 if (chars + 1 > __kmp_debug_buf_chars) {142 if (chars + 1 > __kmp_debug_buf_warn_chars) {143#if KMP_OS_WINDOWS144 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#else154 fprintf(stream,155 "OMP warning: Debugging buffer overflow; "156 "increase KMP_DEBUG_BUF_CHARS to %d\n",157 chars + 1);158 fflush(stream);159#endif160 __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_WINDOWS168 DWORD count;169#ifdef KMP_DEBUG_PIDS170 __kmp_str_buf_print(&__kmp_console_buf, "pid=%d: ", (kmp_int32)getpid());171#endif172 __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#else177#ifdef KMP_DEBUG_PIDS178 fprintf(stream, "pid=%d: ", (kmp_int32)getpid());179#endif180 vfprintf(stream, format, ap);181 fflush(stream);182#endif183 }184}185 186void __kmp_printf(char const *format, ...) {187 va_list ap;188 va_start(ap, format);189 190 __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);191 __kmp_vprintf(kmp_err, format, ap);192 __kmp_release_bootstrap_lock(&__kmp_stdio_lock);193 194 va_end(ap);195}196 197void __kmp_printf_no_lock(char const *format, ...) {198 va_list ap;199 va_start(ap, format);200 201 __kmp_vprintf(kmp_err, format, ap);202 203 va_end(ap);204}205 206void __kmp_fprintf(enum kmp_io stream, char const *format, ...) {207 va_list ap;208 va_start(ap, format);209 210 __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);211 __kmp_vprintf(stream, format, ap);212 __kmp_release_bootstrap_lock(&__kmp_stdio_lock);213 214 va_end(ap);215}216