...
▽

Text file src/runtime/cgo/gcc_libinit_windows.c

Documentation: runtime/cgo

     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
    27const 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
    33const 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
    40static volatile LONG runtime_init_once_gate = 0;
    41static volatile LONG runtime_init_once_done = 0;
    42
    43static CRITICAL_SECTION runtime_init_cs;
    44
    45static HANDLE runtime_init_wait;
    46static int runtime_init_done;
    47
    48// No pthreads on Windows, these are always zero.
    49uintptr_t x_cgo_pthread_key_created;
    50void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
    51
    52// Pre-initialize the runtime synchronization objects
    53void
    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.
    65void
    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
    81int
    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
    91uintptr_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
   110void
   111x_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.
   125static void (*cgo_traceback_function)(struct cgoTracebackArg*);
   126
   127// The context function, used when tracing back C calls into Go.
   128static void (*cgo_context_function)(struct cgoContextArg*);
   129
   130// The symbolizer function, used when symbolizing C frames.
   131static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
   132
   133// Sets the traceback, context, and symbolizer functions. Called from
   134// runtime.SetCgoTraceback.
   135void 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.
   144void (*(_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.
   157void 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.
   170void (*(_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.
   180void (*(_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.
   193void 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}

View as plain text