summaryrefslogtreecommitdiffstats
path: root/openmp/runtime/src/kmp_io.c
blob: 23b60816317005872fc650cb2baf415829635452 (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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/*
 * kmp_io.c -- RTL IO
 * $Revision: 42150 $
 * $Date: 2013-03-15 15:40:38 -0500 (Fri, 15 Mar 2013) $
 */


//===----------------------------------------------------------------------===//
//
//                     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 <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#ifndef __ABSOFT_WIN
# include <sys/types.h>
#endif

#include "kmp_os.h"
#include "kmp_lock.h"
#include "kmp_str.h"
#include "kmp_io.h"
#include "kmp.h" // KMP_GTID_DNE, __kmp_debug_buf, etc

#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).
        }; // if
        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 = sprintf( db, "pid=%d: ", getpid() );
        #endif
        chars += vsprintf( db, 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: ", 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: ", 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 );
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
OpenPOWER on IntegriCloud