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