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