aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/kmp_io.cpp
blob: 609dd18e0bb0afb65e0179ea282ec87c70511bb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
 * kmp_io.cpp -- RTL IO
 */


//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//


#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
#pragma warning(push)
#pragma warning(disable : 271 310)
#include <windows.h>
#pragma warning(pop)
#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

#ifdef KMP_DEBUG
/* __kmp_stdout is used only for dev build */
static HANDLE __kmp_stdout = NULL;
#endif
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) {
#ifdef KMP_DEBUG
    /* standard out is used only in dev build */
    __kmp_stdout = NULL;
#endif
    __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) {
#ifdef KMP_DEBUG
    /* standard out is used only in dev build */
    HANDLE ho;
#endif
    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)

#ifdef KMP_DEBUG
    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
    }
#endif
    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)
#endif /* KMP_OS_WINDOWS */

void __kmp_vprintf(enum kmp_io __kmp_io, char const *format, va_list ap) {
#if KMP_OS_WINDOWS
  if (!__kmp_console_exists) {
    __kmp_redirect_output();
  }
  if (!__kmp_stderr && __kmp_io == kmp_err) {
    return;
  }
#ifdef KMP_DEBUG
  if (!__kmp_stdout && __kmp_io == kmp_out) {
    return;
  }
#endif
#endif /* KMP_OS_WINDOWS */

  if (__kmp_debug_buf && __kmp_debug_buffer != NULL) {

    int dc = (__kmp_debug_buf_atomic ? KMP_TEST_THEN_INC32(&__kmp_debug_count)
                                     : __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(__kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used,
                  &count, NULL);
        __kmp_str_buf_clear(&__kmp_console_buf);
#else
        fprintf(__kmp_stderr, "OMP warning: Debugging buffer overflow; "
                              "increase KMP_DEBUG_BUF_CHARS to %d\n",
                chars + 1);
        fflush(__kmp_stderr);
#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(__kmp_stderr, __kmp_console_buf.str, __kmp_console_buf.used,
              &count, NULL);
    __kmp_str_buf_clear(&__kmp_console_buf);
#else
#ifdef KMP_DEBUG_PIDS
    fprintf(__kmp_stderr, "pid=%d: ", (kmp_int32)getpid());
#endif
    vfprintf(__kmp_stderr, format, ap);
    fflush(__kmp_stderr);
#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);
}