github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 #define WIN32_LEAN_AND_MEAN 6 #include <windows.h> 7 #include <process.h> 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <errno.h> 12 13 #include "libcgo.h" 14 #include "libcgo_windows.h" 15 16 // Ensure there's one symbol marked __declspec(dllexport). 17 // If there are no exported symbols, the unfortunate behavior of 18 // the binutils linker is to also strip the relocations table, 19 // resulting in non-PIE binary. The other option is the 20 // --export-all-symbols flag, but we don't need to export all symbols 21 // and this may overflow the export table (#40795). 22 // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 23 __declspec(dllexport) int _cgo_dummy_export; 24 25 static volatile LONG runtime_init_once_gate = 0; 26 static volatile LONG runtime_init_once_done = 0; 27 28 static CRITICAL_SECTION runtime_init_cs; 29 30 static HANDLE runtime_init_wait; 31 static int runtime_init_done; 32 33 // Pre-initialize the runtime synchronization objects 34 void 35 _cgo_preinit_init() { 36 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL); 37 if (runtime_init_wait == NULL) { 38 fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n"); 39 abort(); 40 } 41 42 InitializeCriticalSection(&runtime_init_cs); 43 } 44 45 // Make sure that the preinit sequence has run. 46 void 47 _cgo_maybe_run_preinit() { 48 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) { 49 if (InterlockedIncrement(&runtime_init_once_gate) == 1) { 50 _cgo_preinit_init(); 51 InterlockedIncrement(&runtime_init_once_done); 52 } else { 53 // Decrement to avoid overflow. 54 InterlockedDecrement(&runtime_init_once_gate); 55 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) { 56 Sleep(0); 57 } 58 } 59 } 60 } 61 62 void 63 x_cgo_sys_thread_create(void (*func)(void*), void* arg) { 64 _cgo_beginthread(func, arg); 65 } 66 67 int 68 _cgo_is_runtime_initialized() { 69 EnterCriticalSection(&runtime_init_cs); 70 int status = runtime_init_done; 71 LeaveCriticalSection(&runtime_init_cs); 72 return status; 73 } 74 75 uintptr_t 76 _cgo_wait_runtime_init_done(void) { 77 void (*pfn)(struct context_arg*); 78 79 _cgo_maybe_run_preinit(); 80 while (!_cgo_is_runtime_initialized()) { 81 WaitForSingleObject(runtime_init_wait, INFINITE); 82 } 83 pfn = _cgo_get_context_function(); 84 if (pfn != nil) { 85 struct context_arg arg; 86 87 arg.Context = 0; 88 (*pfn)(&arg); 89 return arg.Context; 90 } 91 return 0; 92 } 93 94 void 95 x_cgo_notify_runtime_init_done(void* dummy) { 96 _cgo_maybe_run_preinit(); 97 98 EnterCriticalSection(&runtime_init_cs); 99 runtime_init_done = 1; 100 LeaveCriticalSection(&runtime_init_cs); 101 102 if (!SetEvent(runtime_init_wait)) { 103 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n"); 104 abort(); 105 } 106 } 107 108 // The context function, used when tracing back C calls into Go. 109 static void (*cgo_context_function)(struct context_arg*); 110 111 // Sets the context function to call to record the traceback context 112 // when calling a Go function from C code. Called from runtime.SetCgoTraceback. 113 void x_cgo_set_context_function(void (*context)(struct context_arg*)) { 114 EnterCriticalSection(&runtime_init_cs); 115 cgo_context_function = context; 116 LeaveCriticalSection(&runtime_init_cs); 117 } 118 119 // Gets the context function. 120 void (*(_cgo_get_context_function(void)))(struct context_arg*) { 121 void (*ret)(struct context_arg*); 122 123 EnterCriticalSection(&runtime_init_cs); 124 ret = cgo_context_function; 125 LeaveCriticalSection(&runtime_init_cs); 126 return ret; 127 } 128 129 void _cgo_beginthread(void (*func)(void*), void* arg) { 130 int tries; 131 uintptr_t thandle; 132 133 for (tries = 0; tries < 20; tries++) { 134 thandle = _beginthread(func, 0, arg); 135 if (thandle == -1 && errno == EACCES) { 136 // "Insufficient resources", try again in a bit. 137 // 138 // Note that the first Sleep(0) is a yield. 139 Sleep(tries); // milliseconds 140 continue; 141 } else if (thandle == -1) { 142 break; 143 } 144 return; // Success! 145 } 146 147 fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno); 148 abort(); 149 }