summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1996-09-17 21:29:51 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1996-09-17 21:29:51 +0000
commit9093c3c29be6de81cae21d6d8e4f73d276c79bd2 (patch)
tree5fef594fbd0edc112a754a2d92705e428509820b
parentadded prototype for _POSIX_Timespec_subtract (diff)
downloadrtems-9093c3c29be6de81cae21d6d8e4f73d276c79bd2.tar.bz2
Corrected implementation of timed wait on condition variables. First
the timeout is given as a wall-time not an interval as was previously implemented. Second, the interpretation of ETIMEDOUT behavior was incorrect as all possible error cases needed to be checked before this error was returned. This caused problems when the wall-time specified was in the past.
-rw-r--r--c/src/exec/posix/src/cond.c81
-rw-r--r--cpukit/posix/src/cond.c81
2 files changed, 104 insertions, 58 deletions
diff --git a/c/src/exec/posix/src/cond.c b/c/src/exec/posix/src/cond.c
index e9ff4711dc..c480422f19 100644
--- a/c/src/exec/posix/src/cond.c
+++ b/c/src/exec/posix/src/cond.c
@@ -363,12 +363,14 @@ int pthread_cond_broadcast(
int _POSIX_Condition_variables_Wait_support(
pthread_cond_t *cond,
pthread_mutex_t *mutex,
- Watchdog_Interval timeout
+ Watchdog_Interval timeout,
+ boolean already_timedout
)
{
register POSIX_Condition_variables_Control *the_cond;
Objects_Locations location;
int status;
+ int mutex_status;
if ( !_POSIX_Mutex_Get( mutex, &location ) ) {
return EINVAL;
@@ -391,38 +393,44 @@ int _POSIX_Condition_variables_Wait_support(
return EINVAL;
}
- the_cond->Mutex = *mutex;
-
- status = pthread_mutex_unlock( mutex );
-/* XXX ignore this for now
- if ( status ) {
+ (void) pthread_mutex_unlock( mutex );
+/* XXX ignore this for now since behavior is undefined
+ if ( mutex_status ) {
_Thread_Enable_dispatch();
return EINVAL;
}
*/
+
+ if ( !already_timedout ) {
+ the_cond->Mutex = *mutex;
- _Thread_queue_Enter_critical_section( &the_cond->Wait_queue );
- _Thread_Executing->Wait.return_code = 0;
- _Thread_Executing->Wait.queue = &the_cond->Wait_queue;
- _Thread_Executing->Wait.id = *cond;
+ _Thread_queue_Enter_critical_section( &the_cond->Wait_queue );
+ _Thread_Executing->Wait.return_code = 0;
+ _Thread_Executing->Wait.queue = &the_cond->Wait_queue;
+ _Thread_Executing->Wait.id = *cond;
- _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout );
+ _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout );
- _Thread_Enable_dispatch();
+ _Thread_Enable_dispatch();
- /*
- * Switch ourself out because we blocked as a result of the
- * _Thread_queue_Enqueue.
- */
+ /*
+ * Switch ourself out because we blocked as a result of the
+ * _Thread_queue_Enqueue.
+ */
- if ( _Thread_Executing->Wait.return_code )
- return _Thread_Executing->Wait.return_code;
+ status = _Thread_Executing->Wait.return_code;
+ if ( status && status != ETIMEDOUT )
+ return status;
- status = pthread_mutex_lock( mutex );
- if ( status )
+ }
+ else
+ status = ETIMEDOUT;
+
+ mutex_status = pthread_mutex_lock( mutex );
+ if ( mutex_status )
return EINVAL;
- return _Thread_Executing->Wait.return_code;
+ return status;
}
return POSIX_BOTTOM_REACHED();
}
@@ -440,7 +448,8 @@ int pthread_cond_wait(
return _POSIX_Condition_variables_Wait_support(
cond,
mutex,
- THREAD_QUEUE_WAIT_FOREVER
+ THREAD_QUEUE_WAIT_FOREVER,
+ FALSE
);
}
@@ -455,20 +464,34 @@ int pthread_cond_timedwait(
const struct timespec *abstime
)
{
+ Watchdog_Interval timeout;
+ struct timespec current_time;
+ struct timespec difference;
+ boolean already_timedout = FALSE;
+
if ( !abstime )
return EINVAL;
-/* XXX need to fully address an error occuring in the total timespec */
+ /*
+ * The abstime is a walltime. We turn it into an interval.
+ */
- if ( abstime->tv_sec < 0 || abstime->tv_nsec < 0 )
- return EINVAL;
+ (void) clock_gettime( CLOCK_REALTIME, &current_time );
+
+ /* XXX probably some error checking should go here */
+
+ _POSIX_Timespec_subtract( &current_time, abstime, &difference );
+
+ if ( ( difference.tv_sec < 0 ) || ( ( difference.tv_sec == 0 ) &&
+ ( difference.tv_nsec < 0 ) ) )
+ already_timedout = TRUE;
+
+ timeout = _POSIX_Timespec_to_interval( &difference );
- if ( abstime->tv_nsec >= TOD_NANOSECONDS_PER_SECOND )
- return EINVAL;
-
return _POSIX_Condition_variables_Wait_support(
cond,
mutex,
- _POSIX_Timespec_to_interval( abstime )
+ timeout,
+ already_timedout
);
}
diff --git a/cpukit/posix/src/cond.c b/cpukit/posix/src/cond.c
index e9ff4711dc..c480422f19 100644
--- a/cpukit/posix/src/cond.c
+++ b/cpukit/posix/src/cond.c
@@ -363,12 +363,14 @@ int pthread_cond_broadcast(
int _POSIX_Condition_variables_Wait_support(
pthread_cond_t *cond,
pthread_mutex_t *mutex,
- Watchdog_Interval timeout
+ Watchdog_Interval timeout,
+ boolean already_timedout
)
{
register POSIX_Condition_variables_Control *the_cond;
Objects_Locations location;
int status;
+ int mutex_status;
if ( !_POSIX_Mutex_Get( mutex, &location ) ) {
return EINVAL;
@@ -391,38 +393,44 @@ int _POSIX_Condition_variables_Wait_support(
return EINVAL;
}
- the_cond->Mutex = *mutex;
-
- status = pthread_mutex_unlock( mutex );
-/* XXX ignore this for now
- if ( status ) {
+ (void) pthread_mutex_unlock( mutex );
+/* XXX ignore this for now since behavior is undefined
+ if ( mutex_status ) {
_Thread_Enable_dispatch();
return EINVAL;
}
*/
+
+ if ( !already_timedout ) {
+ the_cond->Mutex = *mutex;
- _Thread_queue_Enter_critical_section( &the_cond->Wait_queue );
- _Thread_Executing->Wait.return_code = 0;
- _Thread_Executing->Wait.queue = &the_cond->Wait_queue;
- _Thread_Executing->Wait.id = *cond;
+ _Thread_queue_Enter_critical_section( &the_cond->Wait_queue );
+ _Thread_Executing->Wait.return_code = 0;
+ _Thread_Executing->Wait.queue = &the_cond->Wait_queue;
+ _Thread_Executing->Wait.id = *cond;
- _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout );
+ _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout );
- _Thread_Enable_dispatch();
+ _Thread_Enable_dispatch();
- /*
- * Switch ourself out because we blocked as a result of the
- * _Thread_queue_Enqueue.
- */
+ /*
+ * Switch ourself out because we blocked as a result of the
+ * _Thread_queue_Enqueue.
+ */
- if ( _Thread_Executing->Wait.return_code )
- return _Thread_Executing->Wait.return_code;
+ status = _Thread_Executing->Wait.return_code;
+ if ( status && status != ETIMEDOUT )
+ return status;
- status = pthread_mutex_lock( mutex );
- if ( status )
+ }
+ else
+ status = ETIMEDOUT;
+
+ mutex_status = pthread_mutex_lock( mutex );
+ if ( mutex_status )
return EINVAL;
- return _Thread_Executing->Wait.return_code;
+ return status;
}
return POSIX_BOTTOM_REACHED();
}
@@ -440,7 +448,8 @@ int pthread_cond_wait(
return _POSIX_Condition_variables_Wait_support(
cond,
mutex,
- THREAD_QUEUE_WAIT_FOREVER
+ THREAD_QUEUE_WAIT_FOREVER,
+ FALSE
);
}
@@ -455,20 +464,34 @@ int pthread_cond_timedwait(
const struct timespec *abstime
)
{
+ Watchdog_Interval timeout;
+ struct timespec current_time;
+ struct timespec difference;
+ boolean already_timedout = FALSE;
+
if ( !abstime )
return EINVAL;
-/* XXX need to fully address an error occuring in the total timespec */
+ /*
+ * The abstime is a walltime. We turn it into an interval.
+ */
- if ( abstime->tv_sec < 0 || abstime->tv_nsec < 0 )
- return EINVAL;
+ (void) clock_gettime( CLOCK_REALTIME, &current_time );
+
+ /* XXX probably some error checking should go here */
+
+ _POSIX_Timespec_subtract( &current_time, abstime, &difference );
+
+ if ( ( difference.tv_sec < 0 ) || ( ( difference.tv_sec == 0 ) &&
+ ( difference.tv_nsec < 0 ) ) )
+ already_timedout = TRUE;
+
+ timeout = _POSIX_Timespec_to_interval( &difference );
- if ( abstime->tv_nsec >= TOD_NANOSECONDS_PER_SECOND )
- return EINVAL;
-
return _POSIX_Condition_variables_Wait_support(
cond,
mutex,
- _POSIX_Timespec_to_interval( abstime )
+ timeout,
+ already_timedout
);
}