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 #ifdef __CYGWIN__
6 #error "don't use the cygwin compiler to build native Windows programs; use MinGW instead"
7 #endif
8
9 #define WIN32_LEAN_AND_MEAN
10 #include <windows.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include "libcgo.h"
16 #include "libcgo_windows.h"
17
18 static volatile LONG runtime_init_once_gate = 0;
19 static volatile LONG runtime_init_once_done = 0;
20
21 static CRITICAL_SECTION runtime_init_cs;
22
23 static HANDLE runtime_init_wait;
24 static int runtime_init_done;
25
26 // No pthreads on Windows, these are always zero.
27 uintptr_t x_cgo_pthread_key_created;
28 void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
29
30 // Pre-initialize the runtime synchronization objects
31 void
32 _cgo_preinit_init() {
33 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
34 if (runtime_init_wait == NULL) {
35 fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
36 abort();
37 }
38
39 InitializeCriticalSection(&runtime_init_cs);
40 }
41
42 // Make sure that the preinit sequence has run.
43 void
44 _cgo_maybe_run_preinit() {
45 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
46 if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
47 _cgo_preinit_init();
48 InterlockedIncrement(&runtime_init_once_done);
49 } else {
50 // Decrement to avoid overflow.
51 InterlockedDecrement(&runtime_init_once_gate);
52 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
53 Sleep(0);
54 }
55 }
56 }
57 }
58
59 void
60 x_cgo_sys_thread_create(unsigned long (__stdcall *func)(void*), void* arg) {
61 _cgo_beginthread(func, arg);
62 }
63
64 int
65 _cgo_is_runtime_initialized() {
66 int status;
67
68 EnterCriticalSection(&runtime_init_cs);
69 status = runtime_init_done;
70 LeaveCriticalSection(&runtime_init_cs);
71 return status;
72 }
73
74 uintptr_t
75 _cgo_wait_runtime_init_done(void) {
76 void (*pfn)(struct cgoContextArg*);
77
78 _cgo_maybe_run_preinit();
79 while (!_cgo_is_runtime_initialized()) {
80 WaitForSingleObject(runtime_init_wait, INFINITE);
81 }
82 pfn = _cgo_get_context_function();
83 if (pfn != nil) {
84 struct cgoContextArg arg;
85
86 arg.Context = 0;
87 (*pfn)(&arg);
88 return arg.Context;
89 }
90 return 0;
91 }
92
93 // Should not be used since x_cgo_pthread_key_created will always be zero.
94 void x_cgo_bindm(void* dummy) {
95 fprintf(stderr, "unexpected cgo_bindm on Windows\n");
96 abort();
97 }
98
99 void
100 x_cgo_notify_runtime_init_done(void* dummy) {
101 _cgo_maybe_run_preinit();
102
103 EnterCriticalSection(&runtime_init_cs);
104 runtime_init_done = 1;
105 LeaveCriticalSection(&runtime_init_cs);
106
107 if (!SetEvent(runtime_init_wait)) {
108 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
109 abort();
110 }
111 }
112
113 // The traceback function, used when tracing C calls.
114 static void (*cgo_traceback_function)(struct cgoTracebackArg*);
115
116 // The context function, used when tracing back C calls into Go.
117 static void (*cgo_context_function)(struct cgoContextArg*);
118
119 // The symbolizer function, used when symbolizing C frames.
120 static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
121
122 // Sets the traceback, context, and symbolizer functions. Called from
123 // runtime.SetCgoTraceback.
124 void x_cgo_set_traceback_functions(struct cgoSetTracebackFunctionsArg* arg) {
125 EnterCriticalSection(&runtime_init_cs);
126 cgo_traceback_function = arg->Traceback;
127 cgo_context_function = arg->Context;
128 cgo_symbolizer_function = arg->Symbolizer;
129 LeaveCriticalSection(&runtime_init_cs);
130 }
131
132 // Gets the traceback function to call to trace C calls.
133 void (*(_cgo_get_traceback_function(void)))(struct cgoTracebackArg*) {
134 void (*ret)(struct cgoTracebackArg*);
135
136 EnterCriticalSection(&runtime_init_cs);
137 ret = cgo_traceback_function;
138 LeaveCriticalSection(&runtime_init_cs);
139 return ret;
140 }
141
142 // Call the traceback function registered with x_cgo_set_traceback_functions.
143 //
144 // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
145 // no C/C++ TSAN.
146 void x_cgo_call_traceback_function(struct cgoTracebackArg* arg) {
147 void (*pfn)(struct cgoTracebackArg*);
148
149 pfn = _cgo_get_traceback_function();
150 if (pfn == nil) {
151 return;
152 }
153
154 (*pfn)(arg);
155 }
156
157 // Gets the context function to call to record the traceback context
158 // when calling a Go function from C code.
159 void (*(_cgo_get_context_function(void)))(struct cgoContextArg*) {
160 void (*ret)(struct cgoContextArg*);
161
162 EnterCriticalSection(&runtime_init_cs);
163 ret = cgo_context_function;
164 LeaveCriticalSection(&runtime_init_cs);
165 return ret;
166 }
167
168 // Gets the symbolizer function to call to symbolize C frames.
169 void (*(_cgo_get_symbolizer_function(void)))(struct cgoSymbolizerArg*) {
170 void (*ret)(struct cgoSymbolizerArg*);
171
172 EnterCriticalSection(&runtime_init_cs);
173 ret = cgo_symbolizer_function;
174 LeaveCriticalSection(&runtime_init_cs);
175 return ret;
176 }
177
178 // Call the symbolizer function registered with x_cgo_set_symbolizer_functions.
179 //
180 // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
181 // no C/C++ TSAN.
182 void x_cgo_call_symbolizer_function(struct cgoSymbolizerArg* arg) {
183 void (*pfn)(struct cgoSymbolizerArg*);
184
185 pfn = _cgo_get_symbolizer_function();
186 if (pfn == nil) {
187 return;
188 }
189
190 (*pfn)(arg);
191 }
192
193 void _cgo_beginthread(unsigned long (__stdcall *func)(void*), void* arg) {
194 int tries;
195 HANDLE thandle;
196
197 for (tries = 0; tries < 20; tries++) {
198 thandle = CreateThread(NULL, 0, func, arg, 0, NULL);
199 if (thandle == 0 && GetLastError() == ERROR_ACCESS_DENIED) {
200 // "Insufficient resources", try again in a bit.
201 //
202 // Note that the first Sleep(0) is a yield.
203 Sleep(tries); // milliseconds
204 continue;
205 } else if (thandle == 0) {
206 break;
207 }
208 CloseHandle(thandle);
209 return; // Success!
210 }
211
212 fprintf(stderr, "runtime: failed to create new OS thread (%lu)\n", GetLastError());
213 abort();
214 }
215
View as plain text