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  }