(root)/
xz-5.4.5/
src/
common/
mythread.h
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       mythread.h
       4  /// \brief      Some threading related helper macros and functions
       5  //
       6  //  Author:     Lasse Collin
       7  //
       8  //  This file has been put into the public domain.
       9  //  You can do whatever you want with this file.
      10  //
      11  ///////////////////////////////////////////////////////////////////////////////
      12  
      13  #ifndef MYTHREAD_H
      14  #define MYTHREAD_H
      15  
      16  #include "sysdefs.h"
      17  
      18  // If any type of threading is enabled, #define MYTHREAD_ENABLED.
      19  #if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \
      20  		|| defined(MYTHREAD_VISTA)
      21  #	define MYTHREAD_ENABLED 1
      22  #endif
      23  
      24  
      25  #ifdef MYTHREAD_ENABLED
      26  
      27  ////////////////////////////////////////
      28  // Shared between all threading types //
      29  ////////////////////////////////////////
      30  
      31  // Locks a mutex for a duration of a block.
      32  //
      33  // Perform mythread_mutex_lock(&mutex) in the beginning of a block
      34  // and mythread_mutex_unlock(&mutex) at the end of the block. "break"
      35  // may be used to unlock the mutex and jump out of the block.
      36  // mythread_sync blocks may be nested.
      37  //
      38  // Example:
      39  //
      40  //     mythread_sync(mutex) {
      41  //         foo();
      42  //         if (some_error)
      43  //             break; // Skips bar()
      44  //         bar();
      45  //     }
      46  //
      47  // At least GCC optimizes the loops completely away so it doesn't slow
      48  // things down at all compared to plain mythread_mutex_lock(&mutex)
      49  // and mythread_mutex_unlock(&mutex) calls.
      50  //
      51  #define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__)
      52  #define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line)
      53  #define mythread_sync_helper2(mutex, line) \
      54  	for (unsigned int mythread_i_ ## line = 0; \
      55  			mythread_i_ ## line \
      56  				? (mythread_mutex_unlock(&(mutex)), 0) \
      57  				: (mythread_mutex_lock(&(mutex)), 1); \
      58  			mythread_i_ ## line = 1) \
      59  		for (unsigned int mythread_j_ ## line = 0; \
      60  				!mythread_j_ ## line; \
      61  				mythread_j_ ## line = 1)
      62  #endif
      63  
      64  
      65  #if !defined(MYTHREAD_ENABLED)
      66  
      67  //////////////////
      68  // No threading //
      69  //////////////////
      70  
      71  // Calls the given function once. This isn't thread safe.
      72  #define mythread_once(func) \
      73  do { \
      74  	static bool once_ = false; \
      75  	if (!once_) { \
      76  		func(); \
      77  		once_ = true; \
      78  	} \
      79  } while (0)
      80  
      81  
      82  #if !(defined(_WIN32) && !defined(__CYGWIN__)) && !defined(__wasm__)
      83  // Use sigprocmask() to set the signal mask in single-threaded programs.
      84  #include <signal.h>
      85  
      86  static inline void
      87  mythread_sigmask(int how, const sigset_t *restrict set,
      88  		sigset_t *restrict oset)
      89  {
      90  	int ret = sigprocmask(how, set, oset);
      91  	assert(ret == 0);
      92  	(void)ret;
      93  }
      94  #endif
      95  
      96  
      97  #elif defined(MYTHREAD_POSIX)
      98  
      99  ////////////////////
     100  // Using pthreads //
     101  ////////////////////
     102  
     103  #include <pthread.h>
     104  #include <signal.h>
     105  #include <time.h>
     106  #include <errno.h>
     107  
     108  // If clock_gettime() isn't available, use gettimeofday() from <sys/time.h>
     109  // as a fallback. gettimeofday() is in SUSv2 and thus is supported on all
     110  // relevant POSIX systems.
     111  #ifndef HAVE_CLOCK_GETTIME
     112  #	include <sys/time.h>
     113  #endif
     114  
     115  #define MYTHREAD_RET_TYPE void *
     116  #define MYTHREAD_RET_VALUE NULL
     117  
     118  typedef pthread_t mythread;
     119  typedef pthread_mutex_t mythread_mutex;
     120  
     121  typedef struct {
     122  	pthread_cond_t cond;
     123  #ifdef HAVE_CLOCK_GETTIME
     124  	// Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
     125  	// the condition variable.
     126  	clockid_t clk_id;
     127  #endif
     128  } mythread_cond;
     129  
     130  typedef struct timespec mythread_condtime;
     131  
     132  
     133  // Calls the given function once in a thread-safe way.
     134  #define mythread_once(func) \
     135  	do { \
     136  		static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
     137  		pthread_once(&once_, &func); \
     138  	} while (0)
     139  
     140  
     141  // Use pthread_sigmask() to set the signal mask in multi-threaded programs.
     142  // Do nothing on OpenVMS since it lacks pthread_sigmask().
     143  static inline void
     144  mythread_sigmask(int how, const sigset_t *restrict set,
     145  		sigset_t *restrict oset)
     146  {
     147  #ifdef __VMS
     148  	(void)how;
     149  	(void)set;
     150  	(void)oset;
     151  #else
     152  	int ret = pthread_sigmask(how, set, oset);
     153  	assert(ret == 0);
     154  	(void)ret;
     155  #endif
     156  }
     157  
     158  
     159  // Creates a new thread with all signals blocked. Returns zero on success
     160  // and non-zero on error.
     161  static inline int
     162  mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
     163  {
     164  	sigset_t old;
     165  	sigset_t all;
     166  	sigfillset(&all);
     167  
     168  	mythread_sigmask(SIG_SETMASK, &all, &old);
     169  	const int ret = pthread_create(thread, NULL, func, arg);
     170  	mythread_sigmask(SIG_SETMASK, &old, NULL);
     171  
     172  	return ret;
     173  }
     174  
     175  // Joins a thread. Returns zero on success and non-zero on error.
     176  static inline int
     177  mythread_join(mythread thread)
     178  {
     179  	return pthread_join(thread, NULL);
     180  }
     181  
     182  
     183  // Initiatlizes a mutex. Returns zero on success and non-zero on error.
     184  static inline int
     185  mythread_mutex_init(mythread_mutex *mutex)
     186  {
     187  	return pthread_mutex_init(mutex, NULL);
     188  }
     189  
     190  static inline void
     191  mythread_mutex_destroy(mythread_mutex *mutex)
     192  {
     193  	int ret = pthread_mutex_destroy(mutex);
     194  	assert(ret == 0);
     195  	(void)ret;
     196  }
     197  
     198  static inline void
     199  mythread_mutex_lock(mythread_mutex *mutex)
     200  {
     201  	int ret = pthread_mutex_lock(mutex);
     202  	assert(ret == 0);
     203  	(void)ret;
     204  }
     205  
     206  static inline void
     207  mythread_mutex_unlock(mythread_mutex *mutex)
     208  {
     209  	int ret = pthread_mutex_unlock(mutex);
     210  	assert(ret == 0);
     211  	(void)ret;
     212  }
     213  
     214  
     215  // Initializes a condition variable.
     216  //
     217  // Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
     218  // timeout in pthread_cond_timedwait() work correctly also if system time
     219  // is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
     220  // everywhere while the default CLOCK_REALTIME is, so the default is
     221  // used if CLOCK_MONOTONIC isn't available.
     222  //
     223  // If clock_gettime() isn't available at all, gettimeofday() will be used.
     224  static inline int
     225  mythread_cond_init(mythread_cond *mycond)
     226  {
     227  #ifdef HAVE_CLOCK_GETTIME
     228  #	if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
     229  		defined(HAVE_CLOCK_MONOTONIC)
     230  	struct timespec ts;
     231  	pthread_condattr_t condattr;
     232  
     233  	// POSIX doesn't seem to *require* that pthread_condattr_setclock()
     234  	// will fail if given an unsupported clock ID. Test that
     235  	// CLOCK_MONOTONIC really is supported using clock_gettime().
     236  	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
     237  			&& pthread_condattr_init(&condattr) == 0) {
     238  		int ret = pthread_condattr_setclock(
     239  				&condattr, CLOCK_MONOTONIC);
     240  		if (ret == 0)
     241  			ret = pthread_cond_init(&mycond->cond, &condattr);
     242  
     243  		pthread_condattr_destroy(&condattr);
     244  
     245  		if (ret == 0) {
     246  			mycond->clk_id = CLOCK_MONOTONIC;
     247  			return 0;
     248  		}
     249  	}
     250  
     251  	// If anything above fails, fall back to the default CLOCK_REALTIME.
     252  	// POSIX requires that all implementations of clock_gettime() must
     253  	// support at least CLOCK_REALTIME.
     254  #	endif
     255  
     256  	mycond->clk_id = CLOCK_REALTIME;
     257  #endif
     258  
     259  	return pthread_cond_init(&mycond->cond, NULL);
     260  }
     261  
     262  static inline void
     263  mythread_cond_destroy(mythread_cond *cond)
     264  {
     265  	int ret = pthread_cond_destroy(&cond->cond);
     266  	assert(ret == 0);
     267  	(void)ret;
     268  }
     269  
     270  static inline void
     271  mythread_cond_signal(mythread_cond *cond)
     272  {
     273  	int ret = pthread_cond_signal(&cond->cond);
     274  	assert(ret == 0);
     275  	(void)ret;
     276  }
     277  
     278  static inline void
     279  mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
     280  {
     281  	int ret = pthread_cond_wait(&cond->cond, mutex);
     282  	assert(ret == 0);
     283  	(void)ret;
     284  }
     285  
     286  // Waits on a condition or until a timeout expires. If the timeout expires,
     287  // non-zero is returned, otherwise zero is returned.
     288  static inline int
     289  mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
     290  		const mythread_condtime *condtime)
     291  {
     292  	int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
     293  	assert(ret == 0 || ret == ETIMEDOUT);
     294  	return ret;
     295  }
     296  
     297  // Sets condtime to the absolute time that is timeout_ms milliseconds
     298  // in the future. The type of the clock to use is taken from cond.
     299  static inline void
     300  mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
     301  		uint32_t timeout_ms)
     302  {
     303  	condtime->tv_sec = (time_t)(timeout_ms / 1000);
     304  	condtime->tv_nsec = (long)((timeout_ms % 1000) * 1000000);
     305  
     306  #ifdef HAVE_CLOCK_GETTIME
     307  	struct timespec now;
     308  	int ret = clock_gettime(cond->clk_id, &now);
     309  	assert(ret == 0);
     310  	(void)ret;
     311  
     312  	condtime->tv_sec += now.tv_sec;
     313  	condtime->tv_nsec += now.tv_nsec;
     314  #else
     315  	(void)cond;
     316  
     317  	struct timeval now;
     318  	gettimeofday(&now, NULL);
     319  
     320  	condtime->tv_sec += now.tv_sec;
     321  	condtime->tv_nsec += now.tv_usec * 1000L;
     322  #endif
     323  
     324  	// tv_nsec must stay in the range [0, 999_999_999].
     325  	if (condtime->tv_nsec >= 1000000000L) {
     326  		condtime->tv_nsec -= 1000000000L;
     327  		++condtime->tv_sec;
     328  	}
     329  }
     330  
     331  
     332  #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
     333  
     334  /////////////////////
     335  // Windows threads //
     336  /////////////////////
     337  
     338  #define WIN32_LEAN_AND_MEAN
     339  #ifdef MYTHREAD_VISTA
     340  #	undef _WIN32_WINNT
     341  #	define _WIN32_WINNT 0x0600
     342  #endif
     343  #include <windows.h>
     344  #include <process.h>
     345  
     346  #define MYTHREAD_RET_TYPE unsigned int __stdcall
     347  #define MYTHREAD_RET_VALUE 0
     348  
     349  typedef HANDLE mythread;
     350  typedef CRITICAL_SECTION mythread_mutex;
     351  
     352  #ifdef MYTHREAD_WIN95
     353  typedef HANDLE mythread_cond;
     354  #else
     355  typedef CONDITION_VARIABLE mythread_cond;
     356  #endif
     357  
     358  typedef struct {
     359  	// Tick count (milliseconds) in the beginning of the timeout.
     360  	// NOTE: This is 32 bits so it wraps around after 49.7 days.
     361  	// Multi-day timeouts may not work as expected.
     362  	DWORD start;
     363  
     364  	// Length of the timeout in milliseconds. The timeout expires
     365  	// when the current tick count minus "start" is equal or greater
     366  	// than "timeout".
     367  	DWORD timeout;
     368  } mythread_condtime;
     369  
     370  
     371  // mythread_once() is only available with Vista threads.
     372  #ifdef MYTHREAD_VISTA
     373  #define mythread_once(func) \
     374  	do { \
     375  		static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
     376  		BOOL pending_; \
     377  		if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
     378  			abort(); \
     379  		if (pending_) { \
     380  			func(); \
     381  			if (!InitOnceComplete(&once_, 0, NULL)) \
     382  				abort(); \
     383  		} \
     384  	} while (0)
     385  #endif
     386  
     387  
     388  // mythread_sigmask() isn't available on Windows. Even a dummy version would
     389  // make no sense because the other POSIX signal functions are missing anyway.
     390  
     391  
     392  static inline int
     393  mythread_create(mythread *thread,
     394  		unsigned int (__stdcall *func)(void *arg), void *arg)
     395  {
     396  	uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
     397  	if (ret == 0)
     398  		return -1;
     399  
     400  	*thread = (HANDLE)ret;
     401  	return 0;
     402  }
     403  
     404  static inline int
     405  mythread_join(mythread thread)
     406  {
     407  	int ret = 0;
     408  
     409  	if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
     410  		ret = -1;
     411  
     412  	if (!CloseHandle(thread))
     413  		ret = -1;
     414  
     415  	return ret;
     416  }
     417  
     418  
     419  static inline int
     420  mythread_mutex_init(mythread_mutex *mutex)
     421  {
     422  	InitializeCriticalSection(mutex);
     423  	return 0;
     424  }
     425  
     426  static inline void
     427  mythread_mutex_destroy(mythread_mutex *mutex)
     428  {
     429  	DeleteCriticalSection(mutex);
     430  }
     431  
     432  static inline void
     433  mythread_mutex_lock(mythread_mutex *mutex)
     434  {
     435  	EnterCriticalSection(mutex);
     436  }
     437  
     438  static inline void
     439  mythread_mutex_unlock(mythread_mutex *mutex)
     440  {
     441  	LeaveCriticalSection(mutex);
     442  }
     443  
     444  
     445  static inline int
     446  mythread_cond_init(mythread_cond *cond)
     447  {
     448  #ifdef MYTHREAD_WIN95
     449  	*cond = CreateEvent(NULL, FALSE, FALSE, NULL);
     450  	return *cond == NULL ? -1 : 0;
     451  #else
     452  	InitializeConditionVariable(cond);
     453  	return 0;
     454  #endif
     455  }
     456  
     457  static inline void
     458  mythread_cond_destroy(mythread_cond *cond)
     459  {
     460  #ifdef MYTHREAD_WIN95
     461  	CloseHandle(*cond);
     462  #else
     463  	(void)cond;
     464  #endif
     465  }
     466  
     467  static inline void
     468  mythread_cond_signal(mythread_cond *cond)
     469  {
     470  #ifdef MYTHREAD_WIN95
     471  	SetEvent(*cond);
     472  #else
     473  	WakeConditionVariable(cond);
     474  #endif
     475  }
     476  
     477  static inline void
     478  mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
     479  {
     480  #ifdef MYTHREAD_WIN95
     481  	LeaveCriticalSection(mutex);
     482  	WaitForSingleObject(*cond, INFINITE);
     483  	EnterCriticalSection(mutex);
     484  #else
     485  	BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
     486  	assert(ret);
     487  	(void)ret;
     488  #endif
     489  }
     490  
     491  static inline int
     492  mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
     493  		const mythread_condtime *condtime)
     494  {
     495  #ifdef MYTHREAD_WIN95
     496  	LeaveCriticalSection(mutex);
     497  #endif
     498  
     499  	DWORD elapsed = GetTickCount() - condtime->start;
     500  	DWORD timeout = elapsed >= condtime->timeout
     501  			? 0 : condtime->timeout - elapsed;
     502  
     503  #ifdef MYTHREAD_WIN95
     504  	DWORD ret = WaitForSingleObject(*cond, timeout);
     505  	assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
     506  
     507  	EnterCriticalSection(mutex);
     508  
     509  	return ret == WAIT_TIMEOUT;
     510  #else
     511  	BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
     512  	assert(ret || GetLastError() == ERROR_TIMEOUT);
     513  	return !ret;
     514  #endif
     515  }
     516  
     517  static inline void
     518  mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
     519  		uint32_t timeout)
     520  {
     521  	(void)cond;
     522  	condtime->start = GetTickCount();
     523  	condtime->timeout = timeout;
     524  }
     525  
     526  #endif
     527  
     528  #endif