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 EnterCriticalSection(&runtime_init_cs);
79 int status = runtime_init_done;
80 LeaveCriticalSection(&runtime_init_cs);
81 return status;
82 }
83
84 uintptr_t
85 _cgo_wait_runtime_init_done(void) {
86 void (*pfn)(struct context_arg*);
87
88 _cgo_maybe_run_preinit();
89 while (!_cgo_is_runtime_initialized()) {
90 WaitForSingleObject(runtime_init_wait, INFINITE);
91 }
92 pfn = _cgo_get_context_function();
93 if (pfn != nil) {
94 struct context_arg arg;
95
96 arg.Context = 0;
97 (*pfn)(&arg);
98 return arg.Context;
99 }
100 return 0;
101 }
102
103 // Should not be used since x_cgo_pthread_key_created will always be zero.
104 void x_cgo_bindm(void* dummy) {
105 fprintf(stderr, "unexpected cgo_bindm on Windows\n");
106 abort();
107 }
108
109 void
110 x_cgo_notify_runtime_init_done(void* dummy) {
111 _cgo_maybe_run_preinit();
112
113 EnterCriticalSection(&runtime_init_cs);
114 runtime_init_done = 1;
115 LeaveCriticalSection(&runtime_init_cs);
116
117 if (!SetEvent(runtime_init_wait)) {
118 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
119 abort();
120 }
121 }
122
123 // The context function, used when tracing back C calls into Go.
124 static void (*cgo_context_function)(struct context_arg*);
125
126 // Sets the context function to call to record the traceback context
127 // when calling a Go function from C code. Called from runtime.SetCgoTraceback.
128 void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
129 EnterCriticalSection(&runtime_init_cs);
130 cgo_context_function = context;
131 LeaveCriticalSection(&runtime_init_cs);
132 }
133
134 // Gets the context function.
135 void (*(_cgo_get_context_function(void)))(struct context_arg*) {
136 void (*ret)(struct context_arg*);
137
138 EnterCriticalSection(&runtime_init_cs);
139 ret = cgo_context_function;
140 LeaveCriticalSection(&runtime_init_cs);
141 return ret;
142 }
143
144 void _cgo_beginthread(void (*func)(void*), void* arg) {
145 int tries;
146 uintptr_t thandle;
147
148 for (tries = 0; tries < 20; tries++) {
149 thandle = _beginthread(func, 0, arg);
150 if (thandle == -1 && errno == EACCES) {
151 // "Insufficient resources", try again in a bit.
152 //
153 // Note that the first Sleep(0) is a yield.
154 Sleep(tries); // milliseconds
155 continue;
156 } else if (thandle == -1) {
157 break;
158 }
159 return; // Success!
160 }
161
162 fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
163 abort();
164 }
165
166 #endif // __CYGWIN__
View as plain text