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