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