...
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
31static volatile LONG runtime_init_once_gate = 0;
32static volatile LONG runtime_init_once_done = 0;
33
34static CRITICAL_SECTION runtime_init_cs;
35
36static HANDLE runtime_init_wait;
37static int runtime_init_done;
38
39uintptr_t x_cgo_pthread_key_created;
40void (*x_crosscall2_ptr)(void (*fn)(void *), void *, int, size_t);
41
42// Pre-initialize the runtime synchronization objects
43void
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.
55void
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
71void
72x_cgo_sys_thread_create(void (*func)(void*), void* arg) {
73 _cgo_beginthread(func, arg);
74}
75
76int
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
86uintptr_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.
106void x_cgo_bindm(void* dummy) {
107 fprintf(stderr, "unexpected cgo_bindm on Windows\n");
108 abort();
109}
110
111void
112x_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.
126static 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.
130void 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.
137void (*(_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
146void _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