Text file src/runtime/cgo/gcc_libinit_windows.c

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #ifdef __CYGWIN__
     6  #error "don't use the cygwin compiler to build native Windows programs; use MinGW instead"
     7  #endif
     8  
     9  #define WIN32_LEAN_AND_MEAN
    10  #include <windows.h>
    11  
    12  #include <stdio.h>
    13  #include <stdlib.h>
    14  
    15  #include "libcgo.h"
    16  #include "libcgo_windows.h"
    17  
    18  static volatile LONG runtime_init_once_gate = 0;
    19  static volatile LONG runtime_init_once_done = 0;
    20  
    21  static CRITICAL_SECTION runtime_init_cs;
    22  
    23  static HANDLE runtime_init_wait;
    24  static int runtime_init_done;
    25  
    26  // No pthreads on Windows, these are always zero.
    27  uintptr_t x_cgo_pthread_key_created;
    28  void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
    29  
    30  // Pre-initialize the runtime synchronization objects
    31  void
    32  _cgo_preinit_init() {
    33  	 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
    34  	 if (runtime_init_wait == NULL) {
    35  		fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
    36  		abort();
    37  	 }
    38  
    39  	 InitializeCriticalSection(&runtime_init_cs);
    40  }
    41  
    42  // Make sure that the preinit sequence has run.
    43  void
    44  _cgo_maybe_run_preinit() {
    45  	 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
    46  			if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
    47  				 _cgo_preinit_init();
    48  				 InterlockedIncrement(&runtime_init_once_done);
    49  			} else {
    50  				 // Decrement to avoid overflow.
    51  				 InterlockedDecrement(&runtime_init_once_gate);
    52  				 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
    53  						Sleep(0);
    54  				 }
    55  			}
    56  	 }
    57  }
    58  
    59  void
    60  x_cgo_sys_thread_create(unsigned long (__stdcall *func)(void*), void* arg) {
    61  	_cgo_beginthread(func, arg);
    62  }
    63  
    64  int
    65  _cgo_is_runtime_initialized() {
    66  	 int status;
    67  
    68  	 EnterCriticalSection(&runtime_init_cs);
    69  	 status = runtime_init_done;
    70  	 LeaveCriticalSection(&runtime_init_cs);
    71  	 return status;
    72  }
    73  
    74  uintptr_t
    75  _cgo_wait_runtime_init_done(void) {
    76  	void (*pfn)(struct cgoContextArg*);
    77  
    78  	 _cgo_maybe_run_preinit();
    79  	while (!_cgo_is_runtime_initialized()) {
    80  			WaitForSingleObject(runtime_init_wait, INFINITE);
    81  	}
    82  	pfn = _cgo_get_context_function();
    83  	if (pfn != nil) {
    84  		struct cgoContextArg arg;
    85  
    86  		arg.Context = 0;
    87  		(*pfn)(&arg);
    88  		return arg.Context;
    89  	}
    90  	return 0;
    91  }
    92  
    93  // Should not be used since x_cgo_pthread_key_created will always be zero.
    94  void x_cgo_bindm(void* dummy) {
    95  	fprintf(stderr, "unexpected cgo_bindm on Windows\n");
    96  	abort();
    97  }
    98  
    99  void
   100  x_cgo_notify_runtime_init_done(void* dummy) {
   101  	 _cgo_maybe_run_preinit();
   102  
   103  	 EnterCriticalSection(&runtime_init_cs);
   104  	runtime_init_done = 1;
   105  	 LeaveCriticalSection(&runtime_init_cs);
   106  
   107  	 if (!SetEvent(runtime_init_wait)) {
   108  		fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
   109  		abort();
   110  	}
   111  }
   112  
   113  // The traceback function, used when tracing C calls.
   114  static void (*cgo_traceback_function)(struct cgoTracebackArg*);
   115  
   116  // The context function, used when tracing back C calls into Go.
   117  static void (*cgo_context_function)(struct cgoContextArg*);
   118  
   119  // The symbolizer function, used when symbolizing C frames.
   120  static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
   121  
   122  // Sets the traceback, context, and symbolizer functions. Called from
   123  // runtime.SetCgoTraceback.
   124  void x_cgo_set_traceback_functions(struct cgoSetTracebackFunctionsArg* arg) {
   125  	EnterCriticalSection(&runtime_init_cs);
   126  	cgo_traceback_function = arg->Traceback;
   127  	cgo_context_function = arg->Context;
   128  	cgo_symbolizer_function = arg->Symbolizer;
   129  	LeaveCriticalSection(&runtime_init_cs);
   130  }
   131  
   132  // Gets the traceback function to call to trace C calls.
   133  void (*(_cgo_get_traceback_function(void)))(struct cgoTracebackArg*) {
   134  	void (*ret)(struct cgoTracebackArg*);
   135  
   136  	EnterCriticalSection(&runtime_init_cs);
   137  	ret = cgo_traceback_function;
   138  	LeaveCriticalSection(&runtime_init_cs);
   139  	return ret;
   140  }
   141  
   142  // Call the traceback function registered with x_cgo_set_traceback_functions.
   143  //
   144  // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
   145  // no C/C++ TSAN.
   146  void x_cgo_call_traceback_function(struct cgoTracebackArg* arg) {
   147  	void (*pfn)(struct cgoTracebackArg*);
   148  
   149  	pfn = _cgo_get_traceback_function();
   150  	if (pfn == nil) {
   151  		return;
   152  	}
   153  
   154  	(*pfn)(arg);
   155  }
   156  
   157  // Gets the context function to call to record the traceback context
   158  // when calling a Go function from C code.
   159  void (*(_cgo_get_context_function(void)))(struct cgoContextArg*) {
   160  	void (*ret)(struct cgoContextArg*);
   161  
   162  	EnterCriticalSection(&runtime_init_cs);
   163  	ret = cgo_context_function;
   164  	LeaveCriticalSection(&runtime_init_cs);
   165  	return ret;
   166  }
   167  
   168  // Gets the symbolizer function to call to symbolize C frames.
   169  void (*(_cgo_get_symbolizer_function(void)))(struct cgoSymbolizerArg*) {
   170  	void (*ret)(struct cgoSymbolizerArg*);
   171  
   172  	EnterCriticalSection(&runtime_init_cs);
   173  	ret = cgo_symbolizer_function;
   174  	LeaveCriticalSection(&runtime_init_cs);
   175  	return ret;
   176  }
   177  
   178  // Call the symbolizer function registered with x_cgo_set_symbolizer_functions.
   179  //
   180  // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
   181  // no C/C++ TSAN.
   182  void x_cgo_call_symbolizer_function(struct cgoSymbolizerArg* arg) {
   183  	void (*pfn)(struct cgoSymbolizerArg*);
   184  
   185  	pfn = _cgo_get_symbolizer_function();
   186  	if (pfn == nil) {
   187  		return;
   188  	}
   189  
   190  	(*pfn)(arg);
   191  }
   192  
   193  void _cgo_beginthread(unsigned long (__stdcall *func)(void*), void* arg) {
   194  	int tries;
   195  	HANDLE thandle;
   196  
   197  	for (tries = 0; tries < 20; tries++) {
   198  		thandle = CreateThread(NULL, 0, func, arg, 0, NULL);
   199  		if (thandle == 0 && GetLastError() == ERROR_ACCESS_DENIED) {
   200  			// "Insufficient resources", try again in a bit.
   201  			//
   202  			// Note that the first Sleep(0) is a yield.
   203  			Sleep(tries); // milliseconds
   204  			continue;
   205  		} else if (thandle == 0) {
   206  			break;
   207  		}
   208  		CloseHandle(thandle);
   209  		return; // Success!
   210  	}
   211  
   212  	fprintf(stderr, "runtime: failed to create new OS thread (%lu)\n", GetLastError());
   213  	abort();
   214  }
   215  

View as plain text