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
17 #define IMAGE_GUARD_SECURITY_COOKIE_UNUSED 0x00000800
18 // With modern mingw, we can use the normal struct:
19 //
20 // const IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
21 // .Size = sizeof(_load_config_used),
22 // .GuardFlags = IMAGE_GUARD_SECURITY_COOKIE_UNUSED
23 // };
24 //
25 // But we support older toolchains, so instead, fix the offsets:
26 #ifdef _WIN64
27 const ULONGLONG _load_config_used[40] = {
28 sizeof(_load_config_used),
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30 IMAGE_GUARD_SECURITY_COOKIE_UNUSED
31 };
32 #else
33 const DWORD _load_config_used[48] = {
34 sizeof(_load_config_used),
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 IMAGE_GUARD_SECURITY_COOKIE_UNUSED
37 };
38 #endif
39
40 static volatile LONG runtime_init_once_gate = 0;
41 static volatile LONG runtime_init_once_done = 0;
42
43 static CRITICAL_SECTION runtime_init_cs;
44
45 static HANDLE runtime_init_wait;
46 static int runtime_init_done;
47
48 // No pthreads on Windows, these are always zero.
49 uintptr_t x_cgo_pthread_key_created;
50 void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
51 void (*_cgo_init)(G*, void (*)(void*), void **, void **);
52 void (*_cgo_thread_start)(ThreadStart *);
53 void (*_cgo_sys_thread_create)(void* (*func)(void*));
54 void (*_cgo_getstackbound)(uintptr[2]);
55 void (*_cgo_bindm)(void*);
56
57 // Pre-initialize the runtime synchronization objects
58 void
59 _cgo_preinit_init() {
60 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
61 if (runtime_init_wait == NULL) {
62 fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
63 abort();
64 }
65
66 InitializeCriticalSection(&runtime_init_cs);
67 }
68
69 // Make sure that the preinit sequence has run.
70 void
71 _cgo_maybe_run_preinit() {
72 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
73 if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
74 _cgo_preinit_init();
75 InterlockedIncrement(&runtime_init_once_done);
76 } else {
77 // Decrement to avoid overflow.
78 InterlockedDecrement(&runtime_init_once_gate);
79 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
80 Sleep(0);
81 }
82 }
83 }
84 }
85
86 int
87 _cgo_is_runtime_initialized() {
88 int status;
89
90 EnterCriticalSection(&runtime_init_cs);
91 status = runtime_init_done;
92 LeaveCriticalSection(&runtime_init_cs);
93 return status;
94 }
95
96 uintptr_t
97 _cgo_wait_runtime_init_done(void) {
98 void (*pfn)(struct cgoContextArg*);
99
100 _cgo_maybe_run_preinit();
101 while (!_cgo_is_runtime_initialized()) {
102 WaitForSingleObject(runtime_init_wait, INFINITE);
103 }
104 pfn = _cgo_get_context_function();
105 if (pfn != nil) {
106 struct cgoContextArg arg;
107
108 arg.Context = 0;
109 (*pfn)(&arg);
110 return arg.Context;
111 }
112 return 0;
113 }
114
115 void
116 x_cgo_notify_runtime_init_done(void* dummy) {
117 _cgo_maybe_run_preinit();
118
119 EnterCriticalSection(&runtime_init_cs);
120 runtime_init_done = 1;
121 LeaveCriticalSection(&runtime_init_cs);
122
123 if (!SetEvent(runtime_init_wait)) {
124 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
125 abort();
126 }
127 }
128
129 // The traceback function, used when tracing C calls.
130 static void (*cgo_traceback_function)(struct cgoTracebackArg*);
131
132 // The context function, used when tracing back C calls into Go.
133 static void (*cgo_context_function)(struct cgoContextArg*);
134
135 // The symbolizer function, used when symbolizing C frames.
136 static void (*cgo_symbolizer_function)(struct cgoSymbolizerArg*);
137
138 // Sets the traceback, context, and symbolizer functions. Called from
139 // runtime.SetCgoTraceback.
140 void x_cgo_set_traceback_functions(struct cgoSetTracebackFunctionsArg* arg) {
141 EnterCriticalSection(&runtime_init_cs);
142 cgo_traceback_function = arg->Traceback;
143 cgo_context_function = arg->Context;
144 cgo_symbolizer_function = arg->Symbolizer;
145 LeaveCriticalSection(&runtime_init_cs);
146 }
147
148 // Gets the traceback function to call to trace C calls.
149 void (*(_cgo_get_traceback_function(void)))(struct cgoTracebackArg*) {
150 void (*ret)(struct cgoTracebackArg*);
151
152 EnterCriticalSection(&runtime_init_cs);
153 ret = cgo_traceback_function;
154 LeaveCriticalSection(&runtime_init_cs);
155 return ret;
156 }
157
158 // Call the traceback function registered with x_cgo_set_traceback_functions.
159 //
160 // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
161 // no C/C++ TSAN.
162 void x_cgo_call_traceback_function(struct cgoTracebackArg* arg) {
163 void (*pfn)(struct cgoTracebackArg*);
164
165 pfn = _cgo_get_traceback_function();
166 if (pfn == nil) {
167 return;
168 }
169
170 (*pfn)(arg);
171 }
172
173 // Gets the context function to call to record the traceback context
174 // when calling a Go function from C code.
175 void (*(_cgo_get_context_function(void)))(struct cgoContextArg*) {
176 void (*ret)(struct cgoContextArg*);
177
178 EnterCriticalSection(&runtime_init_cs);
179 ret = cgo_context_function;
180 LeaveCriticalSection(&runtime_init_cs);
181 return ret;
182 }
183
184 // Gets the symbolizer function to call to symbolize C frames.
185 void (*(_cgo_get_symbolizer_function(void)))(struct cgoSymbolizerArg*) {
186 void (*ret)(struct cgoSymbolizerArg*);
187
188 EnterCriticalSection(&runtime_init_cs);
189 ret = cgo_symbolizer_function;
190 LeaveCriticalSection(&runtime_init_cs);
191 return ret;
192 }
193
194 // Call the symbolizer function registered with x_cgo_set_symbolizer_functions.
195 //
196 // On other platforms, this coordinates with C/C++ TSAN. On Windows, there is
197 // no C/C++ TSAN.
198 void x_cgo_call_symbolizer_function(struct cgoSymbolizerArg* arg) {
199 void (*pfn)(struct cgoSymbolizerArg*);
200
201 pfn = _cgo_get_symbolizer_function();
202 if (pfn == nil) {
203 return;
204 }
205
206 (*pfn)(arg);
207 }
208
View as plain text