diff options
author | rpj <rpj> | 2002-01-31 06:56:03 +0000 |
---|---|---|
committer | rpj <rpj> | 2002-01-31 06:56:03 +0000 |
commit | 75f8ad67d45d48b9cdde5a298083881790c76c73 (patch) | |
tree | 0d793e00b40a3292f1fee2b302eb6eccdf15d113 /semaphore.c | |
parent | 30a1e9738593302fa26e0a668f517bc7f5800190 (diff) |
2002-01-27 Ross Johnson <rpj@special.ise.canberra.edu.au>
* mutex.c (pthread_mutex_timedlock): New function suggested by
Alexander Terekhov. The logic required to implement this
properly came from Alexander, with some collaboration
with Thomas Pfaff.
(pthread_mutex_unlock): Wrap the waiters check and sema
post in a critical section to prevent a race with
pthread_mutex_timedlock.
(ptw32_timed_semwait): New function;
returns a special result if the absolute timeout parameter
represents a time already passed when called; used by
pthread_mutex_timedwait(). Have deliberately not reused
the name "ptw32_sem_timedwait" because they are not the same
routine.
* condvar.c (ptw32_cond_timedwait): Use the new sem_timedwait()
instead of ptw32_sem_timedwait(), which now has a different
function. See previous.
* implement.h: Remove prototype for ptw32_sem_timedwait.
See next.
(pthread_mutex_t_): Add critical section element for access
to lock_idx during mutex post-timeout processing.
* semaphore.h (sem_timedwait): See next.
* semaphore.c (sem_timedwait): See next.
* private.c (ptw32_sem_timedwait): Move to semaphore.c
and rename as sem_timedwait().
2002-01-18 Ross Johnson <rpj@special.ise.canberra.edu.au>
* sync.c (pthread_join): Was getting the exit code from the
calling thread rather than the joined thread if
defined(__MINGW32__) && !defined(__MSVCRT__).
2002-01-15 Ross Johnson <rpj@special.ise.canberra.edu.au>
* pthread.h: Unless the build explicitly defines __CLEANUP_SEH,
__CLEANUP_CXX, or __CLEANUP_C, then the build defaults to
__CLEANUP_C style cleanup. This style uses setjmp/longjmp
in the cancelation and thread exit implementations and therefore
won't do stack unwinding if linked to applications that have it
(e.g. C++ apps). This is currently consistent with most/all
commercial Unix POSIX threads implementations.
* spin.c (pthread_spin_init): Edit renamed function call.
* nonportable.c (pthread_num_processors_np): New.
(pthread_getprocessors_np): Renamed to ptw32_getprocessors
and moved to private.c.
* private.c (pthread_getprocessors): Moved here from
nonportable.c.
* pthread.def (pthread_getprocessors_np): Removed
from export list.
* rwlock.c (pthread_rwlockattr_init): New.
(pthread_rwlockattr_destroy): New.
(pthread_rwlockattr_getpshared): New.
(pthread_rwlockattr_setpshared): New.
Diffstat (limited to 'semaphore.c')
-rw-r--r-- | semaphore.c | 330 |
1 files changed, 240 insertions, 90 deletions
diff --git a/semaphore.c b/semaphore.c index 8232300..54005db 100644 --- a/semaphore.c +++ b/semaphore.c @@ -4,10 +4,10 @@ * Module: semaphore.c * * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: * - * POSIX 1003.1b-1993 (POSIX.1b) + * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * @@ -38,6 +38,12 @@ #pragma warning( disable : 4100 ) #endif +#ifndef _UWIN +# include <process.h> +#endif +#ifndef NEED_FTIME +#include <sys/timeb.h> +#endif #include "pthread.h" #include "semaphore.h" #include "implement.h" @@ -52,29 +58,29 @@ sem_init (sem_t * sem, int pshared, unsigned int value) * * PARAMETERS * sem - * pointer to an instance of sem_t + * pointer to an instance of sem_t * * pshared - * if zero, this semaphore may only be shared between - * threads in the same process. - * if nonzero, the semaphore can be shared between - * processes + * if zero, this semaphore may only be shared between + * threads in the same process. + * if nonzero, the semaphore can be shared between + * processes * * value - * initial value of the semaphore counter + * initial value of the semaphore counter * * DESCRIPTION * This function initializes an unnamed semaphore. The * initial value of the semaphore is set to 'value'. * * RESULTS - * 0 successfully created semaphore, - * -1 failed, error in errno + * 0 successfully created semaphore, + * -1 failed, error in errno * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSPC a required resource has been exhausted, - * ENOSYS semaphores are not supported, - * EPERM the process lacks appropriate privilege + * EINVAL 'sem' is not a valid semaphore, + * ENOSPC a required resource has been exhausted, + * ENOSYS semaphores are not supported, + * EPERM the process lacks appropriate privilege * * ------------------------------------------------------ */ @@ -97,40 +103,40 @@ sem_init (sem_t * sem, int pshared, unsigned int value) s = (sem_t) calloc (1, sizeof (*s)); if (NULL == s) - { - result = ENOMEM; - } + { + result = ENOMEM; + } #ifdef NEED_SEM else - { - s->value = value; - s->event = CreateEvent (NULL, - FALSE, /* manual reset */ - FALSE, /* initial state */ - NULL); - if (0 == s->event) - { - result = ENOSPC; - } - else - { - if (value != 0) - { - SetEvent(s->event); - } - - InitializeCriticalSection(&s->sem_lock_cs); - } - } + { + s->value = value; + s->event = CreateEvent (NULL, + FALSE, /* manual reset */ + FALSE, /* initial state */ + NULL); + if (0 == s->event) + { + result = ENOSPC; + } + else + { + if (value != 0) + { + SetEvent(s->event); + } + + InitializeCriticalSection(&s->sem_lock_cs); + } + } #else /* NEED_SEM */ - s->sem = CreateSemaphore (NULL, /* Always NULL */ - value, /* Initial value */ - 0x7FFFFFFFL, /* Maximum value */ - NULL); /* Name */ + s->sem = CreateSemaphore (NULL, /* Always NULL */ + value, /* Initial value */ + 0x7FFFFFFFL, /* Maximum value */ + NULL); /* Name */ if (0 == s->sem) { @@ -163,19 +169,19 @@ sem_destroy (sem_t * sem) * * PARAMETERS * sem - * pointer to an instance of sem_t + * pointer to an instance of sem_t * * DESCRIPTION * This function destroys an unnamed semaphore. * * RESULTS - * 0 successfully destroyed semaphore, - * -1 failed, error in errno + * 0 successfully destroyed semaphore, + * -1 failed, error in errno * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EBUSY threads (or processes) are currently - * blocked on 'sem' + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EBUSY threads (or processes) are currently + * blocked on 'sem' * * ------------------------------------------------------ */ @@ -195,22 +201,22 @@ sem_destroy (sem_t * sem) #ifdef NEED_SEM if (! CloseHandle(s->event)) - { - *sem = s; - result = EINVAL; - } + { + *sem = s; + result = EINVAL; + } else - { - DeleteCriticalSection(&s->sem_lock_cs); - } + { + DeleteCriticalSection(&s->sem_lock_cs); + } #else /* NEED_SEM */ if (! CloseHandle (s->sem)) - { - *sem = s; - result = EINVAL; - } + { + *sem = s; + result = EINVAL; + } #endif /* NEED_SEM */ @@ -238,7 +244,7 @@ sem_trywait (sem_t * sem) * * PARAMETERS * sem - * pointer to an instance of sem_t + * pointer to an instance of sem_t * * DESCRIPTION * This function tries to wait on a semaphore. If the @@ -247,14 +253,14 @@ sem_trywait (sem_t * sem) * this function returns immediately with the error EAGAIN * * RESULTS - * 0 successfully decreased semaphore, - * -1 failed, error in errno + * 0 successfully decreased semaphore, + * -1 failed, error in errno * ERRNO - * EAGAIN the semaphore was already locked, - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EINTR the function was interrupted by a signal, - * EDEADLK a deadlock condition was detected. + * EAGAIN the semaphore was already locked, + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ @@ -306,9 +312,9 @@ ptw32_decrease_semaphore(sem_t * sem) { s->value--; if (s->value != 0) - { - SetEvent(s->event); - } + { + SetEvent(s->event); + } } else { @@ -352,7 +358,7 @@ sem_wait (sem_t * sem) * * PARAMETERS * sem - * pointer to an instance of sem_t + * pointer to an instance of sem_t * * DESCRIPTION * This function waits on a semaphore. If the @@ -363,13 +369,13 @@ sem_wait (sem_t * sem) * a signal. * * RESULTS - * 0 successfully decreased semaphore, - * -1 failed, error in errno + * 0 successfully decreased semaphore, + * -1 failed, error in errno * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EINTR the function was interrupted by a signal, - * EDEADLK a deadlock condition was detected. + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ @@ -413,6 +419,150 @@ sem_wait (sem_t * sem) int +sem_timedwait (sem_t * sem, const struct timespec * abstime) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a semaphore possibly until + * 'abstime' time. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * abstime + * pointer to an instance of struct timespec + * + * DESCRIPTION + * This function waits on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until interrupted by + * a signal. + * + * If 'abstime' is a NULL pointer then this function will + * block until it can successfully decrease the value or + * until interrupted by a signal. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * ETIMEDOUT abstime elapsed before success. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + +#ifdef NEED_FTIME + + struct timespec currSysTime; + +#else /* NEED_FTIME */ + + struct _timeb currSysTime; + +#endif /* NEED_FTIME */ + + const DWORD NANOSEC_PER_MILLISEC = 1000000; + const DWORD MILLISEC_PER_SEC = 1000; + DWORD milliseconds; + + if (sem == NULL) + { + result = EINVAL; + } + else + { + if (abstime == NULL) + { + milliseconds = INFINITE; + } + else + { + /* + * Calculate timeout as milliseconds from current system time. + */ + + /* get current system time */ + +#ifdef NEED_FTIME + + { + FILETIME ft; + SYSTEMTIME st; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + /* + * GetSystemTimeAsFileTime(&ft); would be faster, + * but it does not exist on WinCE + */ + + filetime_to_timespec(&ft, &currSysTime); + } + + /* + * subtract current system time from abstime + */ + milliseconds = (abstime->tv_sec - currSysTime.tv_sec) * MILLISEC_PER_SEC; + milliseconds += ((abstime->tv_nsec - currSysTime.tv_nsec) + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; + +#else /* NEED_FTIME */ + _ftime(&currSysTime); + + /* + * subtract current system time from abstime + */ + milliseconds = (abstime->tv_sec - currSysTime.time) * MILLISEC_PER_SEC; + milliseconds += ((abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC) - + currSysTime.millitm; + +#endif /* NEED_FTIME */ + + + if (((int) milliseconds) < 0) + milliseconds = 0; + } + +#ifdef NEED_SEM + + result = (pthreadCancelableTimedWait ((*sem)->event, milliseconds)); + +#else /* NEED_SEM */ + + result = (pthreadCancelableTimedWait ((*sem)->sem, milliseconds)); + +#endif + + } + + if (result != 0) + { + + errno = result; + return -1; + + } + +#ifdef NEED_SEM + + ptw32_decrease_semaphore(sem); + +#endif /* NEED_SEM */ + + return 0; + +} /* sem_timedwait */ + + +int sem_post (sem_t * sem) /* * ------------------------------------------------------ @@ -421,7 +571,7 @@ sem_post (sem_t * sem) * * PARAMETERS * sem - * pointer to an instance of sem_t + * pointer to an instance of sem_t * * DESCRIPTION * This function posts a wakeup to a semaphore. If there @@ -429,11 +579,11 @@ sem_post (sem_t * sem) * otherwise, the semaphore value is incremented by one. * * RESULTS - * 0 successfully posted semaphore, - * -1 failed, error in errno + * 0 successfully posted semaphore, + * -1 failed, error in errno * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, * * ------------------------------------------------------ */ @@ -479,10 +629,10 @@ sem_post_multiple (sem_t * sem, int count ) * * PARAMETERS * sem - * pointer to an instance of sem_t + * pointer to an instance of sem_t * * count - * counter, must be greater than zero. + * counter, must be greater than zero. * * DESCRIPTION * This function posts multiple wakeups to a semaphore. If there @@ -490,11 +640,11 @@ sem_post_multiple (sem_t * sem, int count ) * the semaphore value is incremented by count - n. * * RESULTS - * 0 successfully posted semaphore, - * -1 failed, error in errno + * 0 successfully posted semaphore, + * -1 failed, error in errno * ERRNO - * EINVAL 'sem' is not a valid semaphore - * or count is less than or equal to zero. + * EINVAL 'sem' is not a valid semaphore + * or count is less than or equal to zero. * * ------------------------------------------------------ */ @@ -528,7 +678,7 @@ sem_post_multiple (sem_t * sem, int count ) return 0; -} /* sem_post_multiple */ +} /* sem_post_multiple */ int |