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 #else
8 // Exclude the following code from Cygwin builds.
9 // Cygwin doesn't implement process.h nor does it support _beginthread.
10
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
13 #include <process.h>
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <errno.h>
18
19 #include "libcgo.h"
20 #include "libcgo_windows.h"
21
22 // Ensure there's one symbol marked __declspec(dllexport).
23 // If there are no exported symbols, the unfortunate behavior of
24 // the binutils linker is to also strip the relocations table,
25 // resulting in non-PIE binary. The other option is the
26 // --export-all-symbols flag, but we don't need to export all symbols
27 // and this may overflow the export table (#40795).
28 // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
29 __declspec(dllexport) int _cgo_dummy_export;
30
31 static volatile LONG runtime_init_once_gate = 0;
32 static volatile LONG runtime_init_once_done = 0;
33
34 static CRITICAL_SECTION runtime_init_cs;
35
36 static HANDLE runtime_init_wait;
37 static int runtime_init_done;
38
39 uintptr_t x_cgo_pthread_key_created;
40 void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
41
42 // Pre-initialize the runtime synchronization objects
43 void
44 _cgo_preinit_init() {
45 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
46 if (runtime_init_wait == NULL) {
47 fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
48 abort();
49 }
50
51 InitializeCriticalSection(&runtime_init_cs);
52 }
53
54 // Make sure that the preinit sequence has run.
55 void
56 _cgo_maybe_run_preinit() {
57 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
58 if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
59 _cgo_preinit_init();
60 InterlockedIncrement(&runtime_init_once_done);
61 } else {
62 // Decrement to avoid overflow.
63 InterlockedDecrement(&runtime_init_once_gate);
64 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
65 Sleep(0);
66 }
67 }
68 }
69 }
70
71 void
72 x_cgo_sys_thread_create(void (*func)(void*), void* arg) {
73 _cgo_beginthread(func, arg);
74 }
75
76 int
77 _cgo_is_runtime_initialized() {
78 int status;
79
80 EnterCriticalSection(&runtime_init_cs);
81 status = runtime_init_done;
82 LeaveCriticalSection(&runtime_init_cs);
83 return status;
84 }
85
86 uintptr_t
87 _cgo_wait_runtime_init_done(void) {
88 void (*pfn)(struct context_arg*);
89
90 _cgo_maybe_run_preinit();
91 while (!_cgo_is_runtime_initialized()) {
92 WaitForSingleObject(runtime_init_wait, INFINITE);
93 }
94 pfn = _cgo_get_context_function();
95 if (pfn != nil) {
96 struct context_arg arg;
97
98 arg.Context = 0;
99 (*pfn)(&arg);
100 return arg.Context;
101 }
102 return 0;
103 }
104
105 // Should not be used since x_cgo_pthread_key_created will always be zero.
106 void x_cgo_bindm(void* dummy) {
107 fprintf(stderr, "unexpected cgo_bindm on Windows\n");
108 abort();
109 }
110
111 void
112 x_cgo_notify_runtime_init_done(void* dummy) {
113 _cgo_maybe_run_preinit();
114
115 EnterCriticalSection(&runtime_init_cs);
116 runtime_init_done = 1;
117 LeaveCriticalSection(&runtime_init_cs);
118
119 if (!SetEvent(runtime_init_wait)) {
120 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
121 abort();
122 }
123 }
124
125 // The context function, used when tracing back C calls into Go.
126 static void (*cgo_context_function)(struct context_arg*);
127
128 // Sets the context function to call to record the traceback context
129 // when calling a Go function from C code. Called from runtime.SetCgoTraceback.
130 void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
131 EnterCriticalSection(&runtime_init_cs);
132 cgo_context_function = context;
133 LeaveCriticalSection(&runtime_init_cs);
134 }
135
136 // Gets the context function.
137 void (*(_cgo_get_context_function(void)))(struct context_arg*) {
138 void (*ret)(struct context_arg*);
139
140 EnterCriticalSection(&runtime_init_cs);
141 ret = cgo_context_function;
142 LeaveCriticalSection(&runtime_init_cs);
143 return ret;
144 }
145
146 void _cgo_beginthread(void (*func)(void*), void* arg) {
147 int tries;
148 uintptr_t thandle;
149
150 for (tries = 0; tries < 20; tries++) {
151 thandle = _beginthread(func, 0, arg);
152 if (thandle == -1 && errno == EACCES) {
153 // "Insufficient resources", try again in a bit.
154 //
155 // Note that the first Sleep(0) is a yield.
156 Sleep(tries); // milliseconds
157 continue;
158 } else if (thandle == -1) {
159 break;
160 }
161 return; // Success!
162 }
163
164 fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
165 abort();
166 }
167
168 #endif // __CYGWIN__
View as plain text