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