375 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <hawk-mtx.h>
 | |
| #include "hawk-prv.h"
 | |
| 
 | |
| #if (!defined(__unix__) && !defined(__unix)) || defined(HAVE_PTHREAD)
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #	include <windows.h>
 | |
| #	include <process.h>
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| #	define INCL_DOSSEMAPHORES
 | |
| #	define INCL_DOSERRORS
 | |
| #	include <os2.h>
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 	/* implement this */
 | |
| 
 | |
| #else
 | |
| #	if !defined(_GNU_SOURCE)
 | |
| #		define _GNU_SOURCE
 | |
| #	endif
 | |
| #	include "syscall.h"
 | |
| #	if defined(AIX) && defined(__GNUC__)
 | |
| 		typedef int crid_t;
 | |
| 		typedef unsigned int class_id_t;
 | |
| #	endif
 | |
| #	include <pthread.h>
 | |
| #endif
 | |
| 
 | |
| hawk_mtx_t* hawk_mtx_open (hawk_gem_t* gem, hawk_oow_t xtnsize)
 | |
| {
 | |
| 	hawk_mtx_t* mtx;
 | |
| 
 | |
| 	mtx = (hawk_mtx_t*)hawk_gem_allocmem(gem, HAWK_SIZEOF(hawk_mtx_t) + xtnsize);
 | |
| 	if (mtx)
 | |
| 	{
 | |
| 		if (hawk_mtx_init(mtx, gem) <= -1)
 | |
| 		{
 | |
| 			hawk_gem_freemem (gem, mtx);
 | |
| 			return HAWK_NULL;
 | |
| 		}
 | |
| 		else HAWK_MEMSET (mtx + 1, 0, xtnsize);
 | |
| 	}
 | |
| 
 | |
| 	return mtx;
 | |
| }
 | |
| 
 | |
| void hawk_mtx_close (hawk_mtx_t* mtx)
 | |
| {
 | |
| 	hawk_mtx_fini (mtx);
 | |
| 	hawk_gem_freemem (mtx->gem, mtx);
 | |
| }
 | |
| 
 | |
| int hawk_mtx_init (hawk_mtx_t* mtx, hawk_gem_t* gem)
 | |
| {
 | |
| 	HAWK_MEMSET (mtx, 0, HAWK_SIZEOF(*mtx));
 | |
| 	mtx->gem = gem;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	mtx->hnd = CreateMutex(HAWK_NULL, FALSE, HAWK_NULL);
 | |
| 	if (mtx->hnd == HAWK_NULL)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 
 | |
| 	{
 | |
| 		APIRET rc;
 | |
| 		HMTX m;
 | |
| 
 | |
| 		rc = DosCreateMutexSem(HAWK_NULL, &m, DC_SEM_SHARED, FALSE);
 | |
| 		if (rc != NO_ERROR)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		mtx->hnd = m;
 | |
| 	}
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 	/* nothing to implement */
 | |
| #else
 | |
| 
 | |
| 	#if (HAWK_SIZEOF_PTHREAD_MUTEX_T <= 0)
 | |
| 		/* nothing to initialize as there is no actual mutex support */
 | |
| 	#else
 | |
| 
 | |
| 	/*
 | |
| 	hawk_ensure (pthread_mutexattr_init (&attr) == 0);
 | |
| 	if (pthread_mutexattr_settype (&attr, type) != 0)
 | |
| 	{
 | |
| 		int num = hawk_geterrno();
 | |
| 		pthread_mutexattr_destroy (&attr);
 | |
| 		if (mtx->__dynamic) hawk_free (mtx);
 | |
| 		hawk_seterrno (num);
 | |
| 		return HAWK_NULL;
 | |
| 	}
 | |
| 	hawk_ensure (pthread_mutex_init (&mtx->hnd, &attr) == 0);
 | |
| 	hawk_ensure (pthread_mutexattr_destroy (&attr) == 0);
 | |
| 	*/
 | |
| 	{
 | |
| 		int n;
 | |
| 		n = pthread_mutex_init((pthread_mutex_t*)&mtx->hnd, HAWK_NULL);
 | |
| 		if (n != 0)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(n));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	#endif
 | |
| #endif
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void hawk_mtx_fini (hawk_mtx_t* mtx)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	CloseHandle (mtx->hnd);
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 	DosCloseMutexSem (mtx->hnd);
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 	/* nothing to destroy as there is no mutex support */
 | |
| 
 | |
| #else
 | |
| 	#if (HAWK_SIZEOF_PTHREAD_MUTEX_T <= 0)
 | |
| 	/* nothing to destroy as there is no actual mutex support */
 | |
| 	#else
 | |
| 	pthread_mutex_destroy ((pthread_mutex_t*)&mtx->hnd);
 | |
| 	#endif
 | |
| #endif
 | |
| }
 | |
| 
 | |
| int hawk_mtx_lock (hawk_mtx_t* mtx, const hawk_ntime_t* waiting_time)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	/*
 | |
| 	 * MSDN
 | |
| 	 *   WAIT_ABANDONED The specified object is a mutex object that was
 | |
| 	 *                  not released by the thread that owned the mutex
 | |
| 	 *                  object before the owning thread terminated.
 | |
| 	 *                  Ownership of the mutex object is granted to the
 | |
| 	 *                  calling thread, and the mutex is set to nonsignaled.
 | |
| 	 *   WAIT_OBJECT_0  The state of the specified object is signaled.
 | |
| 	 *   WAIT_TIMEOUT   The time-out interval elapsed, and the object's
 | |
| 	 *                  state is nonsignaled.
 | |
| 	 *   WAIT_FAILED    An error occurred
 | |
| 	 */
 | |
| 	if (waiting_time)
 | |
| 	{
 | |
| 		DWORD msec, ret;
 | |
| 		msec = HAWK_SECNSEC_TO_MSEC(waiting_time->sec, waiting_time->nsec);
 | |
| 		ret = WaitForSingleObject(mtx->hnd, msec);
 | |
| 		if (ret == WAIT_TIMEOUT)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, HAWK_ETMOUT);
 | |
| 			return -1;
 | |
| 		}
 | |
| 		else if (ret == WAIT_ABANDONED)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, HAWK_ESYSERR);
 | |
| 			return -1;
 | |
| 		}
 | |
| 		else if (ret != WAIT_OBJECT_0)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (WaitForSingleObject(mtx->hnd, INFINITE) == WAIT_FAILED)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 	if (waiting_time)
 | |
| 	{
 | |
| 		ULONG msec;
 | |
| 		APIRET rc;
 | |
| 		msec = HAWK_SECNSEC_TO_MSEC(waiting_time->sec, waiting_time->nsec);
 | |
| 		rc = DosRequestMutexSem(mtx->hnd, msec);
 | |
| 		if (rc != NO_ERROR)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		APIRET rc;
 | |
| 		rc = DosRequestMutexSem(mtx->hnd, SEM_INDEFINITE_WAIT);
 | |
| 		if (rc != NO_ERROR)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 
 | |
| 	/* nothing to do */
 | |
| 
 | |
| #else
 | |
| 	#if (HAWK_SIZEOF_PTHREAD_MUTEX_T <= 0)
 | |
| 		/* nothing to do as there is no actual mutex support */
 | |
| 	#else
 | |
| 
 | |
| 	/* if pthread_mutex_timedlock() isn't available, don't honor the waiting time. */
 | |
| 	#if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
 | |
| 	if (waiting_time)
 | |
| 	{
 | |
| 		hawk_ntime_t t;
 | |
| 		struct timespec ts;
 | |
| 		int n;
 | |
| 
 | |
| 		hawk_get_ntime (&t);
 | |
| 		hawk_add_ntime (&t, waiting_time, &t);
 | |
| 
 | |
| 		ts.tv_sec = t.sec;
 | |
| 		ts.tv_nsec = t.nsec;
 | |
| 		n = pthread_mutex_timedlock((pthread_mutex_t*)&mtx->hnd, &ts);
 | |
| 		if (n != 0)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(n));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	#endif
 | |
| 		int n;
 | |
| 		n = pthread_mutex_lock((pthread_mutex_t*)&mtx->hnd);
 | |
| 		if (n != 0)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(n));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	#if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
 | |
| 	}
 | |
| 	#endif
 | |
| 
 | |
| 	#endif
 | |
| #endif
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hawk_mtx_unlock (hawk_mtx_t* mtx)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	if (ReleaseMutex(mtx->hnd) == FALSE)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 	APIRET rc;
 | |
| 	rc = DosReleaseMutexSem(mtx->hnd);
 | |
| 	if (rc != NO_ERROR)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 
 | |
| 	/* nothing to do */
 | |
| 
 | |
| #else
 | |
| 	#if (HAWK_SIZEOF_PTHREAD_MUTEX_T <= 0)
 | |
| 		/* nothing to do as there is no actual mutex support */
 | |
| 	#else
 | |
| 
 | |
| 	int n;
 | |
| 	n = pthread_mutex_unlock((pthread_mutex_t*)&mtx->hnd);
 | |
| 	if (n != 0)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(n));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	#endif
 | |
| #endif
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hawk_mtx_trylock (hawk_mtx_t* mtx)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	if (WaitForSingleObject(mtx->hnd, 0) != WAIT_OBJECT_0)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 		return -1;
 | |
| 	}
 | |
| #elif defined(__OS2__)
 | |
| 	APIRET rc;
 | |
| 	rc = DosRequestMutexSem(mtx->hnd, 0);
 | |
| 	if (rc != NO_ERROR)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(rc));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 	/* nothing to do */
 | |
| 
 | |
| #else
 | |
| 
 | |
| 	#if (HAWK_SIZEOF_PTHREAD_MUTEX_T <= 0)
 | |
| 		/* nothing to do as there is no actual mutex support */
 | |
| 	#else
 | |
| 	/* -------------------------------------------------- */
 | |
| 	int n;
 | |
| 	#if defined(HAVE_PTHREAD_MUTEX_TRYLOCK)
 | |
| 	n = pthread_mutex_trylock((pthread_mutex_t*)&mtx->hnd);
 | |
| 	#elif defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
 | |
| 	hawk_ntime_t t;
 | |
| 	struct timespec ts;
 | |
| 	hawk_get_ntime (&t);
 | |
| 	ts.tv_sec = t.sec;
 | |
| 	ts.tv_nsec = t.nsec;
 | |
| 	n = pthread_mutex_timedlock((pthread_mutex_t*)&mtx->hnd, &ts);
 | |
| 	#else
 | |
| 	/* not supported. fallback to normal pthread_mutex_lock(). <--- is this really desirable? */
 | |
| 	n = pthread_mutex_lock((pthread_mutex_t*)&mtx->hnd);
 | |
| 	#endif
 | |
| 	if (n != 0)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (mtx->gem, HAWK_NULL, hawk_syserr_to_errnum(n));
 | |
| 		return -1;
 | |
| 	}
 | |
| 	/* -------------------------------------------------- */
 | |
| 	#endif
 | |
| 
 | |
| #endif
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #endif
 |