...
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
18static volatile LONG runtime_init_once_gate = 0;
19static volatile LONG runtime_init_once_done = 0;
20
21static CRITICAL_SECTION runtime_init_cs;
22
23static HANDLE runtime_init_wait;
24static int runtime_init_done;
25
26// No pthreads on Windows, these are always zero.
27uintptr_t x_cgo_pthread_key_created;
28void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
29
30// Pre-initialize the runtime synchronization objects
31void
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.
43void
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
59void
60x_cgo_sys_thread_create(unsigned long (__stdcall *func)(void*), void* arg) {
61 _cgo_beginthread(func, arg);
62}
63
64int
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
74uintptr_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.
94void x_cgo_bindm(void* dummy) {
95 fprintf(stderr, "unexpected cgo_bindm on Windows\n");
96 abort();
97}
98
99void
100x_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.
114static void (*cgo_traceback_function)(struct cgoTracebackArg*);
115
116// The context function, used when tracing back C calls into Go.
117static void (*cgo_context_function)(struct cgoContextArg*);
118
119// The symbolizer function, used when symbolizing C frames.
120static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
121
122// Sets the traceback, context, and symbolizer functions. Called from
123// runtime.SetCgoTraceback.
124void 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.
133void (*(_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.
146void 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.
159void (*(_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.
169void (*(_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.
182void 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
193void _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}
View as plain text