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  
    17  #define IMAGE_GUARD_SECURITY_COOKIE_UNUSED 0x00000800
    18  // With modern mingw, we can use the normal struct:
    19  //
    20  // const IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
    21  // 	.Size = sizeof(_load_config_used),
    22  // 	.GuardFlags = IMAGE_GUARD_SECURITY_COOKIE_UNUSED
    23  // };
    24  //
    25  // But we support older toolchains, so instead, fix the offsets:
    26  #ifdef _WIN64
    27  const ULONGLONG _load_config_used[40] = {
    28  	sizeof(_load_config_used),
    29  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    30  	IMAGE_GUARD_SECURITY_COOKIE_UNUSED
    31  };
    32  #else
    33  const DWORD _load_config_used[48] = {
    34  	sizeof(_load_config_used),
    35  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    36  	IMAGE_GUARD_SECURITY_COOKIE_UNUSED
    37  };
    38  #endif
    39  
    40  static volatile LONG runtime_init_once_gate = 0;
    41  static volatile LONG runtime_init_once_done = 0;
    42  
    43  static CRITICAL_SECTION runtime_init_cs;
    44  
    45  static HANDLE runtime_init_wait;
    46  static int runtime_init_done;
    47  
    48  // No pthreads on Windows, these are always zero.
    49  uintptr_t x_cgo_pthread_key_created;
    50  void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
    51  
    52  // Pre-initialize the runtime synchronization objects
    53  void
    54  _cgo_preinit_init() {
    55  	 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
    56  	 if (runtime_init_wait == NULL) {
    57  		fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
    58  		abort();
    59  	 }
    60  
    61  	 InitializeCriticalSection(&runtime_init_cs);
    62  }
    63  
    64  // Make sure that the preinit sequence has run.
    65  void
    66  _cgo_maybe_run_preinit() {
    67  	 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
    68  			if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
    69  				 _cgo_preinit_init();
    70  				 InterlockedIncrement(&runtime_init_once_done);
    71  			} else {
    72  				 // Decrement to avoid overflow.
    73  				 InterlockedDecrement(&runtime_init_once_gate);
    74  				 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
    75  						Sleep(0);
    76  				 }
    77  			}
    78  	 }
    79  }
    80  
    81  int
    82  _cgo_is_runtime_initialized() {
    83  	 int status;
    84  
    85  	 EnterCriticalSection(&runtime_init_cs);
    86  	 status = runtime_init_done;
    87  	 LeaveCriticalSection(&runtime_init_cs);
    88  	 return status;
    89  }
    90  
    91  uintptr_t
    92  _cgo_wait_runtime_init_done(void) {
    93  	void (*pfn)(struct cgoContextArg*);
    94  
    95  	 _cgo_maybe_run_preinit();
    96  	while (!_cgo_is_runtime_initialized()) {
    97  			WaitForSingleObject(runtime_init_wait, INFINITE);
    98  	}
    99  	pfn = _cgo_get_context_function();
   100  	if (pfn != nil) {
   101  		struct cgoContextArg arg;
   102  
   103  		arg.Context = 0;
   104  		(*pfn)(&arg);
   105  		return arg.Context;
   106  	}
   107  	return 0;
   108  }
   109  
   110  void
   111  x_cgo_notify_runtime_init_done(void* dummy) {
   112  	 _cgo_maybe_run_preinit();
   113  
   114  	 EnterCriticalSection(&runtime_init_cs);
   115  	runtime_init_done = 1;
   116  	 LeaveCriticalSection(&runtime_init_cs);
   117  
   118  	 if (!SetEvent(runtime_init_wait)) {
   119  		fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
   120  		abort();
   121  	}
   122  }
   123  
   124  // The traceback function, used when tracing C calls.
   125  static void (*cgo_traceback_function)(struct cgoTracebackArg*);
   126  
   127  // The context function, used when tracing back C calls into Go.
   128  static void (*cgo_context_function)(struct cgoContextArg*);
   129  
   130  // The symbolizer function, used when symbolizing C frames.
   131  static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
   132  
   133  // Sets the traceback, context, and symbolizer functions. Called from
   134  // runtime.SetCgoTraceback.
   135  void x_cgo_set_traceback_functions(struct cgoSetTracebackFunctionsArg* arg) {
   136  	EnterCriticalSection(&runtime_init_cs);
   137  	cgo_traceback_function = arg->Traceback;
   138  	cgo_context_function = arg->Context;
   139  	cgo_symbolizer_function = arg->Symbolizer;
   140  	LeaveCriticalSection(&runtime_init_cs);
   141  }
   142  
   143  // Gets the traceback function to call to trace C calls.
   144  void (*(_cgo_get_traceback_function(void)))(struct cgoTracebackArg*) {
   145  	void (*ret)(struct cgoTracebackArg*);
   146  
   147  	EnterCriticalSection(&runtime_init_cs);
   148  	ret = cgo_traceback_function;
   149  	LeaveCriticalSection(&runtime_init_cs);
   150  	return ret;
   151  }
   152  
   153  // Call the traceback function registered with x_cgo_set_traceback_functions.
   154  //
   155  // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
   156  // no C/C++ TSAN.
   157  void x_cgo_call_traceback_function(struct cgoTracebackArg* arg) {
   158  	void (*pfn)(struct cgoTracebackArg*);
   159  
   160  	pfn = _cgo_get_traceback_function();
   161  	if (pfn == nil) {
   162  		return;
   163  	}
   164  
   165  	(*pfn)(arg);
   166  }
   167  
   168  // Gets the context function to call to record the traceback context
   169  // when calling a Go function from C code.
   170  void (*(_cgo_get_context_function(void)))(struct cgoContextArg*) {
   171  	void (*ret)(struct cgoContextArg*);
   172  
   173  	EnterCriticalSection(&runtime_init_cs);
   174  	ret = cgo_context_function;
   175  	LeaveCriticalSection(&runtime_init_cs);
   176  	return ret;
   177  }
   178  
   179  // Gets the symbolizer function to call to symbolize C frames.
   180  void (*(_cgo_get_symbolizer_function(void)))(struct cgoSymbolizerArg*) {
   181  	void (*ret)(struct cgoSymbolizerArg*);
   182  
   183  	EnterCriticalSection(&runtime_init_cs);
   184  	ret = cgo_symbolizer_function;
   185  	LeaveCriticalSection(&runtime_init_cs);
   186  	return ret;
   187  }
   188  
   189  // Call the symbolizer function registered with x_cgo_set_symbolizer_functions.
   190  //
   191  // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
   192  // no C/C++ TSAN.
   193  void x_cgo_call_symbolizer_function(struct cgoSymbolizerArg* arg) {
   194  	void (*pfn)(struct cgoSymbolizerArg*);
   195  
   196  	pfn = _cgo_get_symbolizer_function();
   197  	if (pfn == nil) {
   198  		return;
   199  	}
   200  
   201  	(*pfn)(arg);
   202  }
   203  

View as plain text