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  void (*_cgo_init)(G*, void (*)(void*), void **, void **);
    52  void (*_cgo_thread_start)(ThreadStart *);
    53  void (*_cgo_sys_thread_create)(void* (*func)(void*));
    54  void (*_cgo_getstackbound)(uintptr[2]);
    55  void (*_cgo_bindm)(void*);
    56  
    57  // Pre-initialize the runtime synchronization objects
    58  void
    59  _cgo_preinit_init() {
    60  	 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
    61  	 if (runtime_init_wait == NULL) {
    62  		fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
    63  		abort();
    64  	 }
    65  
    66  	 InitializeCriticalSection(&runtime_init_cs);
    67  }
    68  
    69  // Make sure that the preinit sequence has run.
    70  void
    71  _cgo_maybe_run_preinit() {
    72  	 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
    73  			if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
    74  				 _cgo_preinit_init();
    75  				 InterlockedIncrement(&runtime_init_once_done);
    76  			} else {
    77  				 // Decrement to avoid overflow.
    78  				 InterlockedDecrement(&runtime_init_once_gate);
    79  				 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
    80  						Sleep(0);
    81  				 }
    82  			}
    83  	 }
    84  }
    85  
    86  int
    87  _cgo_is_runtime_initialized() {
    88  	 int status;
    89  
    90  	 EnterCriticalSection(&runtime_init_cs);
    91  	 status = runtime_init_done;
    92  	 LeaveCriticalSection(&runtime_init_cs);
    93  	 return status;
    94  }
    95  
    96  uintptr_t
    97  _cgo_wait_runtime_init_done(void) {
    98  	void (*pfn)(struct cgoContextArg*);
    99  
   100  	 _cgo_maybe_run_preinit();
   101  	while (!_cgo_is_runtime_initialized()) {
   102  			WaitForSingleObject(runtime_init_wait, INFINITE);
   103  	}
   104  	pfn = _cgo_get_context_function();
   105  	if (pfn != nil) {
   106  		struct cgoContextArg arg;
   107  
   108  		arg.Context = 0;
   109  		(*pfn)(&arg);
   110  		return arg.Context;
   111  	}
   112  	return 0;
   113  }
   114  
   115  void
   116  x_cgo_notify_runtime_init_done(void* dummy) {
   117  	 _cgo_maybe_run_preinit();
   118  
   119  	 EnterCriticalSection(&runtime_init_cs);
   120  	runtime_init_done = 1;
   121  	 LeaveCriticalSection(&runtime_init_cs);
   122  
   123  	 if (!SetEvent(runtime_init_wait)) {
   124  		fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
   125  		abort();
   126  	}
   127  }
   128  
   129  // The traceback function, used when tracing C calls.
   130  static void (*cgo_traceback_function)(struct cgoTracebackArg*);
   131  
   132  // The context function, used when tracing back C calls into Go.
   133  static void (*cgo_context_function)(struct cgoContextArg*);
   134  
   135  // The symbolizer function, used when symbolizing C frames.
   136  static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
   137  
   138  // Sets the traceback, context, and symbolizer functions. Called from
   139  // runtime.SetCgoTraceback.
   140  void x_cgo_set_traceback_functions(struct cgoSetTracebackFunctionsArg* arg) {
   141  	EnterCriticalSection(&runtime_init_cs);
   142  	cgo_traceback_function = arg->Traceback;
   143  	cgo_context_function = arg->Context;
   144  	cgo_symbolizer_function = arg->Symbolizer;
   145  	LeaveCriticalSection(&runtime_init_cs);
   146  }
   147  
   148  // Gets the traceback function to call to trace C calls.
   149  void (*(_cgo_get_traceback_function(void)))(struct cgoTracebackArg*) {
   150  	void (*ret)(struct cgoTracebackArg*);
   151  
   152  	EnterCriticalSection(&runtime_init_cs);
   153  	ret = cgo_traceback_function;
   154  	LeaveCriticalSection(&runtime_init_cs);
   155  	return ret;
   156  }
   157  
   158  // Call the traceback function registered with x_cgo_set_traceback_functions.
   159  //
   160  // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
   161  // no C/C++ TSAN.
   162  void x_cgo_call_traceback_function(struct cgoTracebackArg* arg) {
   163  	void (*pfn)(struct cgoTracebackArg*);
   164  
   165  	pfn = _cgo_get_traceback_function();
   166  	if (pfn == nil) {
   167  		return;
   168  	}
   169  
   170  	(*pfn)(arg);
   171  }
   172  
   173  // Gets the context function to call to record the traceback context
   174  // when calling a Go function from C code.
   175  void (*(_cgo_get_context_function(void)))(struct cgoContextArg*) {
   176  	void (*ret)(struct cgoContextArg*);
   177  
   178  	EnterCriticalSection(&runtime_init_cs);
   179  	ret = cgo_context_function;
   180  	LeaveCriticalSection(&runtime_init_cs);
   181  	return ret;
   182  }
   183  
   184  // Gets the symbolizer function to call to symbolize C frames.
   185  void (*(_cgo_get_symbolizer_function(void)))(struct cgoSymbolizerArg*) {
   186  	void (*ret)(struct cgoSymbolizerArg*);
   187  
   188  	EnterCriticalSection(&runtime_init_cs);
   189  	ret = cgo_symbolizer_function;
   190  	LeaveCriticalSection(&runtime_init_cs);
   191  	return ret;
   192  }
   193  
   194  // Call the symbolizer function registered with x_cgo_set_symbolizer_functions.
   195  //
   196  // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
   197  // no C/C++ TSAN.
   198  void x_cgo_call_symbolizer_function(struct cgoSymbolizerArg* arg) {
   199  	void (*pfn)(struct cgoSymbolizerArg*);
   200  
   201  	pfn = _cgo_get_symbolizer_function();
   202  	if (pfn == nil) {
   203  		return;
   204  	}
   205  
   206  	(*pfn)(arg);
   207  }
   208  

View as plain text