kmp_io.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * kmp_io.cpp -- RTL IO
  3. */
  4. //===----------------------------------------------------------------------===//
  5. //
  6. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  7. // See https://llvm.org/LICENSE.txt for license information.
  8. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #include <stdarg.h>
  12. #include <stddef.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #ifndef __ABSOFT_WIN
  17. #include <sys/types.h>
  18. #endif
  19. #include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc
  20. #include "kmp_io.h"
  21. #include "kmp_lock.h"
  22. #include "kmp_os.h"
  23. #include "kmp_str.h"
  24. #if KMP_OS_WINDOWS
  25. #if KMP_MSVC_COMPAT
  26. #pragma warning(push)
  27. #pragma warning(disable : 271 310)
  28. #endif
  29. #include <windows.h>
  30. #if KMP_MSVC_COMPAT
  31. #pragma warning(pop)
  32. #endif
  33. #endif
  34. /* ------------------------------------------------------------------------ */
  35. kmp_bootstrap_lock_t __kmp_stdio_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
  36. __kmp_stdio_lock); /* Control stdio functions */
  37. kmp_bootstrap_lock_t __kmp_console_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(
  38. __kmp_console_lock); /* Control console initialization */
  39. #if KMP_OS_WINDOWS
  40. static HANDLE __kmp_stdout = NULL;
  41. static HANDLE __kmp_stderr = NULL;
  42. static int __kmp_console_exists = FALSE;
  43. static kmp_str_buf_t __kmp_console_buf;
  44. static int is_console(void) {
  45. char buffer[128];
  46. DWORD rc = 0;
  47. DWORD err = 0;
  48. // Try to get console title.
  49. SetLastError(0);
  50. // GetConsoleTitle does not reset last error in case of success or short
  51. // buffer, so we need to clear it explicitly.
  52. rc = GetConsoleTitle(buffer, sizeof(buffer));
  53. if (rc == 0) {
  54. // rc == 0 means getting console title failed. Let us find out why.
  55. err = GetLastError();
  56. // err == 0 means buffer too short (we suppose console exists).
  57. // In Window applications we usually have err == 6 (invalid handle).
  58. }
  59. return rc > 0 || err == 0;
  60. }
  61. void __kmp_close_console(void) {
  62. /* wait until user presses return before closing window */
  63. /* TODO only close if a window was opened */
  64. if (__kmp_console_exists) {
  65. __kmp_stdout = NULL;
  66. __kmp_stderr = NULL;
  67. __kmp_str_buf_free(&__kmp_console_buf);
  68. __kmp_console_exists = FALSE;
  69. }
  70. }
  71. /* For windows, call this before stdout, stderr, or stdin are used.
  72. It opens a console window and starts processing */
  73. static void __kmp_redirect_output(void) {
  74. __kmp_acquire_bootstrap_lock(&__kmp_console_lock);
  75. (void)is_console;
  76. if (!__kmp_console_exists) {
  77. HANDLE ho;
  78. HANDLE he;
  79. __kmp_str_buf_init(&__kmp_console_buf);
  80. AllocConsole();
  81. // We do not check the result of AllocConsole because
  82. // 1. the call is harmless
  83. // 2. it is not clear how to communicate failue
  84. // 3. we will detect failure later when we get handle(s)
  85. ho = GetStdHandle(STD_OUTPUT_HANDLE);
  86. if (ho == INVALID_HANDLE_VALUE || ho == NULL) {
  87. DWORD err = GetLastError();
  88. // TODO: output error somehow (maybe message box)
  89. (void)err;
  90. __kmp_stdout = NULL;
  91. } else {
  92. __kmp_stdout = ho; // temporary code, need new global for ho
  93. }
  94. he = GetStdHandle(STD_ERROR_HANDLE);
  95. if (he == INVALID_HANDLE_VALUE || he == NULL) {
  96. DWORD err = GetLastError();
  97. // TODO: output error somehow (maybe message box)
  98. (void)err;
  99. __kmp_stderr = NULL;
  100. } else {
  101. __kmp_stderr = he; // temporary code, need new global
  102. }
  103. __kmp_console_exists = TRUE;
  104. }
  105. __kmp_release_bootstrap_lock(&__kmp_console_lock);
  106. }
  107. #else
  108. #define __kmp_stderr (stderr)
  109. #define __kmp_stdout (stdout)
  110. #endif /* KMP_OS_WINDOWS */
  111. void __kmp_vprintf(enum kmp_io out_stream, char const *format, va_list ap) {
  112. #if KMP_OS_WINDOWS
  113. if (!__kmp_console_exists) {
  114. __kmp_redirect_output();
  115. }
  116. if (!__kmp_stderr && out_stream == kmp_err) {
  117. return;
  118. }
  119. if (!__kmp_stdout && out_stream == kmp_out) {
  120. return;
  121. }
  122. #endif /* KMP_OS_WINDOWS */
  123. auto stream = ((out_stream == kmp_out) ? __kmp_stdout : __kmp_stderr);
  124. if (__kmp_debug_buf && __kmp_debug_buffer != NULL) {
  125. int dc = __kmp_debug_count++ % __kmp_debug_buf_lines;
  126. char *db = &__kmp_debug_buffer[dc * __kmp_debug_buf_chars];
  127. int chars = 0;
  128. #ifdef KMP_DEBUG_PIDS
  129. chars = KMP_SNPRINTF(db, __kmp_debug_buf_chars,
  130. "pid=%d: ", (kmp_int32)getpid());
  131. #endif
  132. chars += KMP_VSNPRINTF(db, __kmp_debug_buf_chars, format, ap);
  133. if (chars + 1 > __kmp_debug_buf_chars) {
  134. if (chars + 1 > __kmp_debug_buf_warn_chars) {
  135. #if KMP_OS_WINDOWS
  136. DWORD count;
  137. __kmp_str_buf_print(&__kmp_console_buf,
  138. "OMP warning: Debugging buffer "
  139. "overflow; increase "
  140. "KMP_DEBUG_BUF_CHARS to %d\n",
  141. chars + 1);
  142. WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
  143. NULL);
  144. __kmp_str_buf_clear(&__kmp_console_buf);
  145. #else
  146. fprintf(stream,
  147. "OMP warning: Debugging buffer overflow; "
  148. "increase KMP_DEBUG_BUF_CHARS to %d\n",
  149. chars + 1);
  150. fflush(stream);
  151. #endif
  152. __kmp_debug_buf_warn_chars = chars + 1;
  153. }
  154. /* terminate string if overflow occurred */
  155. db[__kmp_debug_buf_chars - 2] = '\n';
  156. db[__kmp_debug_buf_chars - 1] = '\0';
  157. }
  158. } else {
  159. #if KMP_OS_WINDOWS
  160. DWORD count;
  161. #ifdef KMP_DEBUG_PIDS
  162. __kmp_str_buf_print(&__kmp_console_buf, "pid=%d: ", (kmp_int32)getpid());
  163. #endif
  164. __kmp_str_buf_vprint(&__kmp_console_buf, format, ap);
  165. WriteFile(stream, __kmp_console_buf.str, __kmp_console_buf.used, &count,
  166. NULL);
  167. __kmp_str_buf_clear(&__kmp_console_buf);
  168. #else
  169. #ifdef KMP_DEBUG_PIDS
  170. fprintf(stream, "pid=%d: ", (kmp_int32)getpid());
  171. #endif
  172. vfprintf(stream, format, ap);
  173. fflush(stream);
  174. #endif
  175. }
  176. }
  177. void __kmp_printf(char const *format, ...) {
  178. va_list ap;
  179. va_start(ap, format);
  180. __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
  181. __kmp_vprintf(kmp_err, format, ap);
  182. __kmp_release_bootstrap_lock(&__kmp_stdio_lock);
  183. va_end(ap);
  184. }
  185. void __kmp_printf_no_lock(char const *format, ...) {
  186. va_list ap;
  187. va_start(ap, format);
  188. __kmp_vprintf(kmp_err, format, ap);
  189. va_end(ap);
  190. }
  191. void __kmp_fprintf(enum kmp_io stream, char const *format, ...) {
  192. va_list ap;
  193. va_start(ap, format);
  194. __kmp_acquire_bootstrap_lock(&__kmp_stdio_lock);
  195. __kmp_vprintf(stream, format, ap);
  196. __kmp_release_bootstrap_lock(&__kmp_stdio_lock);
  197. va_end(ap);
  198. }