Text file
src/runtime/cgo/gcc_libinit_windows.c
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 WIN32_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 }
126
View as plain text