...
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 // +build cgo
6 #define WIN64_LEAN_AND_MEAN
7 #include <windows.h>
8 #include <process.h>
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <errno.h>
13
14 #include "libcgo.h"
15
16 static volatile LONG runtime_init_once_gate = 0;
17 static volatile LONG runtime_init_once_done = 0;
18
19 static CRITICAL_SECTION runtime_init_cs;
20
21 static HANDLE runtime_init_wait;
22 static int runtime_init_done;
23
24 // Pre-initialize the runtime synchronization objects
25 void
26 _cgo_preinit_init() {
27 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
28 if (runtime_init_wait == NULL) {
29 fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
30 abort();
31 }
32
33 InitializeCriticalSection(&runtime_init_cs);
34 }
35
36 // Make sure that the preinit sequence has run.
37 void
38 _cgo_maybe_run_preinit() {
39 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
40 if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
41 _cgo_preinit_init();
42 InterlockedIncrement(&runtime_init_once_done);
43 } else {
44 // Decrement to avoid overflow.
45 InterlockedDecrement(&runtime_init_once_gate);
46 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
47 Sleep(0);
48 }
49 }
50 }
51 }
52
53 void
54 x_cgo_sys_thread_create(void (*func)(void*), void* arg) {
55 uintptr_t thandle;
56
57 thandle = _beginthread(func, 0, arg);
58 if(thandle == -1) {
59 fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
60 abort();
61 }
62 }
63
64 int
65 _cgo_is_runtime_initialized() {
66 EnterCriticalSection(&runtime_init_cs);
67 int status = runtime_init_done;
68 LeaveCriticalSection(&runtime_init_cs);
69 return status;
70 }
71
72 uintptr_t
73 _cgo_wait_runtime_init_done(void) {
74 void (*pfn)(struct context_arg*);
75
76 _cgo_maybe_run_preinit();
77 while (!_cgo_is_runtime_initialized()) {
78 WaitForSingleObject(runtime_init_wait, INFINITE);
79 }
80 pfn = _cgo_get_context_function();
81 if (pfn != nil) {
82 struct context_arg arg;
83
84 arg.Context = 0;
85 (*pfn)(&arg);
86 return arg.Context;
87 }
88 return 0;
89 }
90
91 void
92 x_cgo_notify_runtime_init_done(void* dummy) {
93 _cgo_maybe_run_preinit();
94
95 EnterCriticalSection(&runtime_init_cs);
96 runtime_init_done = 1;
97 LeaveCriticalSection(&runtime_init_cs);
98
99 if (!SetEvent(runtime_init_wait)) {
100 fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
101 abort();
102 }
103 }
104
105 // The context function, used when tracing back C calls into Go.
106 static void (*cgo_context_function)(struct context_arg*);
107
108 // Sets the context function to call to record the traceback context
109 // when calling a Go function from C code. Called from runtime.SetCgoTraceback.
110 void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
111 EnterCriticalSection(&runtime_init_cs);
112 cgo_context_function = context;
113 LeaveCriticalSection(&runtime_init_cs);
114 }
115
116 // Gets the context function.
117 void (*(_cgo_get_context_function(void)))(struct context_arg*) {
118 void (*ret)(struct context_arg*);
119
120 EnterCriticalSection(&runtime_init_cs);
121 ret = cgo_context_function;
122 LeaveCriticalSection(&runtime_init_cs);
123 return ret;
124 }
View as plain text