github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/runtime/cgo/gcc_libinit_windows.c (about) 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 // +build cgo 6 #define WIN64_LEAN_AND_MEAN 7 #include <windows.h> 8 #include <process.h> 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <errno.h> 13 14 #include "libcgo.h" 15 16 static volatile LONG runtime_init_once_gate = 0; 17 static volatile LONG runtime_init_once_done = 0; 18 19 static CRITICAL_SECTION runtime_init_cs; 20 21 static HANDLE runtime_init_wait; 22 static int runtime_init_done; 23 24 // Pre-initialize the runtime synchronization objects 25 void 26 _cgo_preinit_init() { 27 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL); 28 if (runtime_init_wait == NULL) { 29 fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n"); 30 abort(); 31 } 32 33 InitializeCriticalSection(&runtime_init_cs); 34 } 35 36 // Make sure that the preinit sequence has run. 37 void 38 _cgo_maybe_run_preinit() { 39 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) { 40 if (InterlockedIncrement(&runtime_init_once_gate) == 1) { 41 _cgo_preinit_init(); 42 InterlockedIncrement(&runtime_init_once_done); 43 } else { 44 // Decrement to avoid overflow. 45 InterlockedDecrement(&runtime_init_once_gate); 46 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) { 47 Sleep(0); 48 } 49 } 50 } 51 } 52 53 void 54 x_cgo_sys_thread_create(void (*func)(void*), void* arg) { 55 uintptr_t thandle; 56 57 thandle = _beginthread(func, 0, arg); 58 if(thandle == -1) { 59 fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno); 60 abort(); 61 } 62 } 63 64 int 65 _cgo_is_runtime_initialized() { 66 EnterCriticalSection(&runtime_init_cs); 67 int status = runtime_init_done; 68 LeaveCriticalSection(&runtime_init_cs); 69 return status; 70 } 71 72 uintptr_t 73 _cgo_wait_runtime_init_done(void) { 74 void (*pfn)(struct context_arg*); 75 76 _cgo_maybe_run_preinit(); 77 while (!_cgo_is_runtime_initialized()) { 78 WaitForSingleObject(runtime_init_wait, INFINITE); 79 } 80 pfn = _cgo_get_context_function(); 81 if (pfn != nil) { 82 struct context_arg arg; 83 84 arg.Context = 0; 85 (*pfn)(&arg); 86 return arg.Context; 87 } 88 return 0; 89 } 90 91 void 92 x_cgo_notify_runtime_init_done(void* dummy) { 93 _cgo_maybe_run_preinit(); 94 95 EnterCriticalSection(&runtime_init_cs); 96 runtime_init_done = 1; 97 LeaveCriticalSection(&runtime_init_cs); 98 99 if (!SetEvent(runtime_init_wait)) { 100 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n"); 101 abort(); 102 } 103 } 104 105 // The context function, used when tracing back C calls into Go. 106 static void (*cgo_context_function)(struct context_arg*); 107 108 // Sets the context function to call to record the traceback context 109 // when calling a Go function from C code. Called from runtime.SetCgoTraceback. 110 void x_cgo_set_context_function(void (*context)(struct context_arg*)) { 111 EnterCriticalSection(&runtime_init_cs); 112 cgo_context_function = context; 113 LeaveCriticalSection(&runtime_init_cs); 114 } 115 116 // Gets the context function. 117 void (*(_cgo_get_context_function(void)))(struct context_arg*) { 118 void (*ret)(struct context_arg*); 119 120 EnterCriticalSection(&runtime_init_cs); 121 ret = cgo_context_function; 122 LeaveCriticalSection(&runtime_init_cs); 123 return ret; 124 }