to reflect the new license. These used slightly different spellings that defeated my regular expressions. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351648
230 lines
6.4 KiB
C++
230 lines
6.4 KiB
C++
/*
|
|
* kmp_io.cpp -- RTL IO
|
|
*/
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef __ABSOFT_WIN
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc
|
|
#include "kmp_io.h"
|
|
#include "kmp_lock.h"
|
|
#include "kmp_os.h"
|
|
#include "kmp_str.h"
|
|
|
|
#if KMP_OS_WINDOWS
|
|
#if KMP_MSVC_COMPAT
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 271 310)
|
|
#endif
|
|
#include <windows.h>
|
|
#if KMP_MSVC_COMPAT
|
|
#pragma warning(pop)
|
|
#endif
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
|
|
__kmp_stdio_lock); /* Control stdio functions */
|
|
kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
|
|
__kmp_console_lock); /* Control console initialization */
|
|
|
|
#if KMP_OS_WINDOWS
|
|
|
|
static HANDLE __kmp_stdout = NULL;
|
|
static HANDLE __kmp_stderr = NULL;
|
|
static int __kmp_console_exists = FALSE;
|
|
static kmp_str_buf_t __kmp_console_buf;
|
|
|
|
static int is_console(void) {
|
|
char buffer[128];
|
|
DWORD rc = 0;
|
|
DWORD err = 0;
|
|
// Try to get console title.
|
|
SetLastError(0);
|
|
// GetConsoleTitle does not reset last error in case of success or short
|
|
// buffer, so we need to clear it explicitly.
|
|
rc = GetConsoleTitle(buffer, sizeof(buffer));
|
|
if (rc == 0) {
|
|
// rc == 0 means getting console title failed. Let us find out why.
|
|
err = GetLastError();
|
|
// err == 0 means buffer too short (we suppose console exists).
|
|
// In Window applications we usually have err == 6 (invalid handle).
|
|
}
|
|
return rc > 0 || err == 0;
|
|
}
|
|
|
|
void __kmp_close_console(void) {
|
|
/* wait until user presses return before closing window */
|
|
/* TODO only close if a window was opened */
|
|
if (__kmp_console_exists) {
|
|
__kmp_stdout = NULL;
|
|
__kmp_stderr = NULL;
|
|
__kmp_str_buf_free(&__kmp_console_buf);
|
|
__kmp_console_exists = FALSE;
|
|
}
|
|
}
|
|
|
|
/* For windows, call this before stdout, stderr, or stdin are used.
|
|
It opens a console window and starts processing */
|
|
static void __kmp_redirect_output(void) {
|
|
__kmp_acquire_bootstrap_lock(&__kmp_console_lock);
|
|
|
|
if (!__kmp_console_exists) {
|
|
HANDLE ho;
|
|
HANDLE he;
|
|
|
|
__kmp_str_buf_init(&__kmp_console_buf);
|
|
|
|
AllocConsole();
|
|
// We do not check the result of AllocConsole because
|
|
// 1. the call is harmless
|
|
// 2. it is not clear how to communicate failue
|
|
// 3. we will detect failure later when we get handle(s)
|
|
|
|
ho = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (ho == INVALID_HANDLE_VALUE || ho == NULL) {
|
|
|
|
DWORD err = GetLastError();
|
|
// TODO: output error somehow (maybe message box)
|
|
__kmp_stdout = NULL;
|
|
|
|
} else {
|
|
|
|
__kmp_stdout = ho; // temporary code, need new global for ho
|
|
}
|
|
he = GetStdHandle(STD_ERROR_HANDLE);
|
|
if (he == INVALID_HANDLE_VALUE || he == NULL) {
|
|
|
|
DWORD err = GetLastError();
|
|
// TODO: output error somehow (maybe message box)
|
|
__kmp_stderr = NULL;
|
|
|
|
} else {
|
|
|
|
__kmp_stderr = he; // temporary code, need new global
|
|
}
|
|
__kmp_console_exists = TRUE;
|
|
}
|
|
__kmp_release_bootstrap_lock(&__kmp_console_lock);
|
|
}
|
|
|
|
#else
|
|
#define __kmp_stderr (stderr)
|
|
#define __kmp_stdout (stdout)
|
|
#endif /* KMP_OS_WINDOWS */
|
|
|
|
void __kmp_vprintf(enum kmp_io out_stream, char const *format, va_list ap) {
|
|
#if KMP_OS_WINDOWS
|
|
if (!__kmp_console_exists) {
|
|
__kmp_redirect_output();
|
|
}
|
|
if (!__kmp_stderr && out_stream == kmp_err) {
|
|
return;
|
|
}
|
|
if (!__kmp_stdout && out_stream == kmp_out) {
|
|
return;
|
|
}
|
|
#endif /* KMP_OS_WINDOWS */
|
|
auto stream = ((out_stream == kmp_out) ? __kmp_stdout : __kmp_stderr);
|
|
|
|
if (__kmp_debug_buf && __kmp_debug_buffer != NULL) {
|
|
|
|
int dc = __kmp_debug_count++ % __kmp_debug_buf_lines;
|
|
char *db = &__kmp_debug_buffer[dc * __kmp_debug_buf_chars];
|
|
int chars = 0;
|
|
|
|
#ifdef KMP_DEBUG_PIDS
|
|
chars = KMP_SNPRINTF(db, __kmp_debug_buf_chars, "pid=%d: ",
|
|
(kmp_int32)getpid());
|
|
#endif
|
|
chars += KMP_VSNPRINTF(db, __kmp_debug_buf_chars, format, ap);
|
|
|
|
if (chars + 1 > __kmp_debug_buf_chars) {
|
|
if (chars + 1 > __kmp_debug_buf_warn_chars) {
|
|
#if KMP_OS_WINDOWS
|
|
DWORD count;
|
|
__kmp_str_buf_print(&__kmp_console_buf, "OMP warning: Debugging buffer "
|
|
"overflow; increase "
|
|
"KMP_DEBUG_BUF_CHARS to %d\n",
|
|
chars + 1);
|
|
WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
|
|
NULL);
|
|
__kmp_str_buf_clear(&__kmp_console_buf);
|
|
#else
|
|
fprintf(stream, "OMP warning: Debugging buffer overflow; "
|
|
"increase KMP_DEBUG_BUF_CHARS to %d\n",
|
|
chars + 1);
|
|
fflush(stream);
|
|
#endif
|
|
__kmp_debug_buf_warn_chars = chars + 1;
|
|
}
|
|
/* terminate string if overflow occurred */
|
|
db[__kmp_debug_buf_chars - 2] = '\n';
|
|
db[__kmp_debug_buf_chars - 1] = '\0';
|
|
}
|
|
} else {
|
|
#if KMP_OS_WINDOWS
|
|
DWORD count;
|
|
#ifdef KMP_DEBUG_PIDS
|
|
__kmp_str_buf_print(&__kmp_console_buf, "pid=%d: ", (kmp_int32)getpid());
|
|
#endif
|
|
__kmp_str_buf_vprint(&__kmp_console_buf, format, ap);
|
|
WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
|
|
NULL);
|
|
__kmp_str_buf_clear(&__kmp_console_buf);
|
|
#else
|
|
#ifdef KMP_DEBUG_PIDS
|
|
fprintf(stream, "pid=%d: ", (kmp_int32)getpid());
|
|
#endif
|
|
vfprintf(stream, format, ap);
|
|
fflush(stream);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void __kmp_printf(char const *format, ...) {
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
|
|
__kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
|
|
__kmp_vprintf(kmp_err, format, ap);
|
|
__kmp_release_bootstrap_lock(&__kmp_stdio_lock);
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
void __kmp_printf_no_lock(char const *format, ...) {
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
|
|
__kmp_vprintf(kmp_err, format, ap);
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
void __kmp_fprintf(enum kmp_io stream, char const *format, ...) {
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
|
|
__kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
|
|
__kmp_vprintf(stream, format, ap);
|
|
__kmp_release_bootstrap_lock(&__kmp_stdio_lock);
|
|
|
|
va_end(ap);
|
|
}
|