github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-thread.c (about) 1 /* 2 * jit-thread.c - Internal thread management routines for libjit. 3 * 4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd. 5 * 6 * This file is part of the libjit library. 7 * 8 * The libjit library is free software: you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation, either version 2.1 of 11 * the License, or (at your option) any later version. 12 * 13 * The libjit library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with the libjit library. If not, see 20 * <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "jit-internal.h" 24 25 #if TIME_WITH_SYS_TIME 26 # include <sys/time.h> 27 # include <time.h> 28 #else 29 # if HAVE_SYS_TIME_H 30 # include <sys/time.h> 31 # elif !defined(__palmos__) 32 # include <time.h> 33 # endif 34 #endif 35 #ifdef HAVE_SYS_TYPES_H 36 # include <sys/types.h> 37 #endif 38 #include <errno.h> 39 40 /* 41 * Mutex that synchronizes global data initialization. 42 */ 43 jit_mutex_t _jit_global_lock; 44 45 #if defined(JIT_THREADS_PTHREAD) 46 47 /* 48 * The thread-specific key to use to fetch the control object. 49 */ 50 static pthread_key_t control_key; 51 52 /* 53 * Initialize the pthread support routines. Only called once. 54 */ 55 static void init_pthread(void) 56 { 57 jit_mutex_create(&_jit_global_lock); 58 59 /* Allocate a thread-specific variable for the JIT's thread 60 control object, and arrange for it to be freed when the 61 thread exits or is otherwise terminated */ 62 pthread_key_create(&control_key, jit_free); 63 } 64 65 #elif defined(JIT_THREADS_WIN32) 66 67 /* 68 * The thread-specific key to use to fetch the control object. 69 */ 70 static DWORD control_key; 71 72 /* 73 * Initialize the Win32 thread support routines. Only called once. 74 */ 75 static void init_win32_thread(void) 76 { 77 jit_mutex_create(&_jit_global_lock); 78 79 control_key = TlsAlloc(); 80 } 81 82 jit_thread_id_t _jit_thread_self(void) 83 { 84 HANDLE new_handle; 85 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), 86 GetCurrentProcess(), &new_handle, 87 0, 0, DUPLICATE_SAME_ACCESS); 88 return new_handle; 89 } 90 91 #else /* No thread package */ 92 93 /* 94 * The control object for the only thread in the system. 95 */ 96 static void *control_object = 0; 97 98 #endif /* No thread package */ 99 100 void _jit_thread_init(void) 101 { 102 #if defined(JIT_THREADS_PTHREAD) 103 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 104 pthread_once(&once_control, init_pthread); 105 #elif defined(JIT_THREADS_WIN32) 106 static LONG volatile once_control = 0; 107 switch(InterlockedCompareExchange(&once_control, 1, 0)) 108 { 109 case 0: 110 init_win32_thread(); 111 InterlockedExchange(&once_control, 2); 112 break; 113 case 1: 114 while(InterlockedCompareExchange(&once_control, 2, 2) != 2) 115 { 116 } 117 break; 118 } 119 #endif 120 } 121 122 static void *get_raw_control(void) 123 { 124 _jit_thread_init(); 125 #if defined(JIT_THREADS_PTHREAD) 126 return pthread_getspecific(control_key); 127 #elif defined(JIT_THREADS_WIN32) 128 return (void *)(TlsGetValue(control_key)); 129 #else 130 return control_object; 131 #endif 132 } 133 134 static void set_raw_control(void *obj) 135 { 136 _jit_thread_init(); 137 #if defined(JIT_THREADS_PTHREAD) 138 pthread_setspecific(control_key, obj); 139 #elif defined(JIT_THREADS_WIN32) 140 TlsSetValue(control_key, obj); 141 #else 142 control_object = obj; 143 #endif 144 } 145 146 jit_thread_control_t _jit_thread_get_control(void) 147 { 148 jit_thread_control_t control; 149 control = (jit_thread_control_t)get_raw_control(); 150 if(!control) 151 { 152 control = jit_cnew(struct jit_thread_control); 153 if(control) 154 { 155 set_raw_control(control); 156 } 157 } 158 return control; 159 } 160 161 jit_thread_id_t _jit_thread_current_id(void) 162 { 163 #if defined(JIT_THREADS_PTHREAD) 164 return pthread_self(); 165 #elif defined(JIT_THREADS_WIN32) 166 return GetCurrentThread(); 167 #else 168 /* There is only one thread, so lets give it an identifier of 1 */ 169 return 1; 170 #endif 171 } 172 173 int _jit_monitor_wait(jit_monitor_t *mon, jit_int timeout) 174 { 175 #if defined(JIT_THREADS_PTHREAD) 176 if(timeout < 0) 177 { 178 pthread_cond_wait(&(mon->_cond), &(mon->_mutex)); 179 return 1; 180 } 181 else 182 { 183 struct timeval tv; 184 struct timespec ts; 185 int result; 186 187 gettimeofday(&tv, 0); 188 ts.tv_sec = tv.tv_sec + (long)(timeout / 1000); 189 ts.tv_nsec = (tv.tv_usec + (long)((timeout % 1000) * 1000)) * 1000L; 190 if(ts.tv_nsec >= 1000000000L) 191 { 192 ++(ts.tv_sec); 193 ts.tv_nsec -= 1000000000L; 194 } 195 196 /* Wait until we are signalled or the timeout expires */ 197 do 198 { 199 result = pthread_cond_timedwait(&(mon->_cond), &(mon->_mutex), &ts); 200 } 201 while(result == EINTR); 202 return ((result == 0) ? 1 : 0); 203 } 204 #elif defined(JIT_THREADS_WIN32) 205 DWORD result; 206 ++(mon->_waiting); 207 if(timeout >= 0) 208 { 209 result = SignalObjectAndWait(mon->_mutex, mon->_cond, (DWORD)timeout, FALSE); 210 } 211 else 212 { 213 result = SignalObjectAndWait(mon->_mutex, mon->_cond, INFINITE, FALSE); 214 } 215 WaitForSingleObject(mon->_mutex, INFINITE); 216 return (result == WAIT_OBJECT_0); 217 #else 218 return 0; 219 #endif 220 }