summaryrefslogtreecommitdiff
path: root/semaphore.c
diff options
context:
space:
mode:
authorrpj <rpj>2002-01-31 06:56:03 +0000
committerrpj <rpj>2002-01-31 06:56:03 +0000
commit75f8ad67d45d48b9cdde5a298083881790c76c73 (patch)
tree0d793e00b40a3292f1fee2b302eb6eccdf15d113 /semaphore.c
parent30a1e9738593302fa26e0a668f517bc7f5800190 (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.c330
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