score: Avoid Giant lock for CORE rwlock

Update #2555.
This commit is contained in:
Sebastian Huber
2016-04-22 09:25:09 +02:00
parent f27383a518
commit 84a5398853
14 changed files with 381 additions and 539 deletions
@@ -23,6 +23,7 @@
#include <rtems/score/corerwlockimpl.h>
#include <rtems/score/objectimpl.h>
#include <errno.h>
#include <pthread.h>
#ifdef __cplusplus
@@ -86,8 +87,8 @@ RTEMS_INLINE_ROUTINE void _POSIX_RWLock_Free (
}
POSIX_RWLock_Control *_POSIX_RWLock_Get(
pthread_rwlock_t *rwlock,
Objects_Locations *location
pthread_rwlock_t *rwlock,
ISR_lock_Context *lock_context
);
#ifdef __cplusplus
+26 -52
View File
@@ -17,68 +17,42 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/threadqimpl.h>
/**
* This directive allows a thread to delete a rwlock specified by
* the rwlock id. The rwlock is freed back to the inactive
* rwlock chain.
*
* @param[in] rwlock is the rwlock id
*
* @return This method returns 0 if there was not an
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
int pthread_rwlock_destroy(
pthread_rwlock_t *rwlock
)
{
POSIX_RWLock_Control *the_rwlock = NULL;
Objects_Locations location;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
_Objects_Allocator_lock();
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
/*
* If there is at least one thread waiting, then do not delete it.
*/
if (
_Thread_queue_First(
&the_rwlock->RWLock.Wait_queue,
CORE_RWLOCK_TQ_OPERATIONS
) != NULL
) {
_Objects_Put( &the_rwlock->Object );
_Objects_Allocator_unlock();
return EBUSY;
}
/*
* POSIX doesn't require behavior when it is locked.
*/
_Objects_Close( &_POSIX_RWLock_Information, &the_rwlock->Object );
_Objects_Put( &the_rwlock->Object );
_POSIX_RWLock_Free( the_rwlock );
_Objects_Allocator_unlock();
return 0;
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
_Objects_Allocator_unlock();
return EINVAL;
}
_Objects_Allocator_unlock();
_CORE_RWLock_Acquire_critical( &the_rwlock->RWLock, &lock_context );
return EINVAL;
/*
* If there is at least one thread waiting, then do not delete it.
*/
if ( !_Thread_queue_Is_empty( &the_rwlock->RWLock.Wait_queue.Queue ) ) {
_CORE_RWLock_Release( &the_rwlock->RWLock, &lock_context );
_Objects_Allocator_unlock();
return EBUSY;
}
/*
* POSIX doesn't require behavior when it is locked.
*/
_Objects_Close( &_POSIX_RWLock_Information, &the_rwlock->Object );
_CORE_RWLock_Release( &the_rwlock->RWLock, &lock_context );
_POSIX_RWLock_Free( the_rwlock );
_Objects_Allocator_unlock();
return 0;
}
+7 -15
View File
@@ -20,20 +20,14 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/apimutex.h>
static bool _POSIX_RWLock_Check_id_and_auto_init(
pthread_mutex_t *rwlock,
Objects_Locations *location
pthread_mutex_t *rwlock
)
{
if ( rwlock == NULL ) {
*location = OBJECTS_ERROR;
return false;
}
@@ -51,8 +45,6 @@ static bool _POSIX_RWLock_Check_id_and_auto_init(
_Once_Unlock();
if ( eno != 0 ) {
*location = OBJECTS_ERROR;
return false;
}
}
@@ -61,18 +53,18 @@ static bool _POSIX_RWLock_Check_id_and_auto_init(
}
POSIX_RWLock_Control *_POSIX_RWLock_Get(
pthread_rwlock_t *rwlock,
Objects_Locations *location
pthread_rwlock_t *rwlock,
ISR_lock_Context *lock_context
)
{
if ( !_POSIX_RWLock_Check_id_and_auto_init( rwlock, location ) ) {
if ( !_POSIX_RWLock_Check_id_and_auto_init( rwlock ) ) {
return NULL;
}
return (POSIX_RWLock_Control *) _Objects_Get(
&_POSIX_RWLock_Information,
return (POSIX_RWLock_Control *) _Objects_Get_local(
*rwlock,
location
&_POSIX_RWLock_Information,
lock_context
);
}
+17 -39
View File
@@ -18,53 +18,31 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/thread.h>
/**
* This directive attempts to obtain a read only lock on an rwlock instance.
*
* @param[in] rwlock is the pointer to rwlock id
*
* @retval 0 if successful
* @retval error_code if unsuccessful
*/
int pthread_rwlock_rdlock(
pthread_rwlock_t *rwlock
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
Thread_Control *executing;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
Thread_Control *executing;
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_reading(
&the_rwlock->RWLock,
executing,
true, /* we are willing to wait forever */
0
);
_Objects_Put( &the_rwlock->Object );
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_reading(
&the_rwlock->RWLock,
executing,
true, /* we are willing to wait forever */
0,
&lock_context
);
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
}
+37 -57
View File
@@ -18,37 +18,20 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/thread.h>
#include <rtems/score/todimpl.h>
/*
* pthread_rwlock_timedrdlock
*
* This directive attempts to obtain a read only lock on an rwlock instance.
*
* Input parameters:
* rwlock - pointer to rwlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
int pthread_rwlock_timedrdlock(
pthread_rwlock_t *rwlock,
const struct timespec *abstime
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
Watchdog_Interval ticks;
bool do_wait = true;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
Watchdog_Interval ticks;
bool do_wait;
TOD_Absolute_timeout_conversion_results status;
Thread_Control *executing;
Thread_Control *executing;
/*
* POSIX requires that blocking calls with timeouts that take
@@ -64,43 +47,40 @@ int pthread_rwlock_timedrdlock(
* then we should not wait.
*/
status = _TOD_Absolute_timeout_to_ticks( abstime, &ticks );
if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE )
do_wait = false;
do_wait = ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE );
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_reading(
&the_rwlock->RWLock,
executing,
do_wait,
ticks
);
_Objects_Put( &the_rwlock->Object );
if ( !do_wait ) {
if ( executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE ) {
if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
return EINVAL;
if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
status == TOD_ABSOLUTE_TIMEOUT_IS_NOW )
return ETIMEDOUT;
}
}
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_reading(
&the_rwlock->RWLock,
executing,
do_wait,
ticks,
&lock_context
);
if (
!do_wait
&& ( executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE )
) {
if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) {
return EINVAL;
}
if (
status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST
|| status == TOD_ABSOLUTE_TIMEOUT_IS_NOW
) {
return ETIMEDOUT;
}
}
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
}
+37 -56
View File
@@ -20,37 +20,20 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/thread.h>
#include <rtems/score/todimpl.h>
/*
* pthread_rwlock_timedwrlock
*
* This directive attempts to obtain a write only lock on an rwlock instance.
*
* Input parameters:
* rwlock - pointer to rwlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
int pthread_rwlock_timedwrlock(
pthread_rwlock_t *rwlock,
const struct timespec *abstime
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
Watchdog_Interval ticks;
bool do_wait = true;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
Watchdog_Interval ticks;
bool do_wait;
TOD_Absolute_timeout_conversion_results status;
Thread_Control *executing;
Thread_Control *executing;
/*
* POSIX requires that blocking calls with timeouts that take
@@ -66,42 +49,40 @@ int pthread_rwlock_timedwrlock(
* then we should not wait.
*/
status = _TOD_Absolute_timeout_to_ticks( abstime, &ticks );
if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE )
do_wait = false;
do_wait = ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE );
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_writing(
&the_rwlock->RWLock,
executing,
do_wait,
ticks
);
_Objects_Put( &the_rwlock->Object );
if ( !do_wait &&
(executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE) ) {
if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
return EINVAL;
if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
status == TOD_ABSOLUTE_TIMEOUT_IS_NOW )
return ETIMEDOUT;
}
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_writing(
&the_rwlock->RWLock,
executing,
do_wait,
ticks,
&lock_context
);
if (
!do_wait
&& ( executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE )
) {
if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) {
return EINVAL;
}
if (
status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST
|| status == TOD_ABSOLUTE_TIMEOUT_IS_NOW
) {
return ETIMEDOUT;
}
}
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
}
+17 -44
View File
@@ -18,58 +18,31 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/thread.h>
/*
* pthread_rwlock_tryrdlock
*
* This directive attempts to obtain a read only lock on an rwlock instance.
*
* Input parameters:
* rwlock - pointer to rwlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
int pthread_rwlock_tryrdlock(
pthread_rwlock_t *rwlock
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
Thread_Control *executing;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
Thread_Control *executing;
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_reading(
&the_rwlock->RWLock,
executing,
false, /* do not wait for the rwlock */
0
);
_Objects_Put( &the_rwlock->Object );
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_reading(
&the_rwlock->RWLock,
executing,
false, /* do not wait for the rwlock */
0,
&lock_context
);
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
}
+17 -43
View File
@@ -18,57 +18,31 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/posix/rwlockimpl.h>
#include <rtems/score/thread.h>
/*
* pthread_rwlock_trywrlock
*
* This directive attempts to obtain a Write only lock on an rwlock instance.
*
* Input parameters:
* rwlock - pointer to rwlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
int pthread_rwlock_trywrlock(
pthread_rwlock_t *rwlock
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
Thread_Control *executing;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
Thread_Control *executing;
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_writing(
&the_rwlock->RWLock,
executing,
false, /* we are not willing to wait */
0
);
_Objects_Put( &the_rwlock->Object );
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_writing(
&the_rwlock->RWLock,
executing,
false, /* we are not willing to wait */
0,
&lock_context
);
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
}
+8 -33
View File
@@ -20,47 +20,22 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/system.h>
#include <rtems/posix/rwlockimpl.h>
/*
* pthread_rwlock_unlock
*
* This directive attempts to release a lock on an RWLock.
*
* Input parameters:
* rwlock - pointer to rwlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
int pthread_rwlock_unlock(
pthread_rwlock_t *rwlock
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
CORE_RWLock_Status status;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
CORE_RWLock_Status status;
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
status = _CORE_RWLock_Surrender( &the_rwlock->RWLock, _Thread_Executing );
_Objects_Put( &the_rwlock->Object );
return _POSIX_RWLock_Translate_core_RWLock_return_code( status );
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
status = _CORE_RWLock_Surrender( &the_rwlock->RWLock, &lock_context );
return _POSIX_RWLock_Translate_core_RWLock_return_code( status );
}
+17 -39
View File
@@ -28,51 +28,29 @@
THREAD_WAIT_QUEUE_OBJECT_ASSERT( POSIX_RWLock_Control, RWLock.Wait_queue );
/*
* pthread_rwlock_wrlock
*
* This directive attempts to obtain a write only lock on an rwlock instance.
*
* Input parameters:
* rwlock - pointer to rwlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
int pthread_rwlock_wrlock(
pthread_rwlock_t *rwlock
)
{
POSIX_RWLock_Control *the_rwlock;
Objects_Locations location;
Thread_Control *executing;
POSIX_RWLock_Control *the_rwlock;
ISR_lock_Context lock_context;
Thread_Control *executing;
the_rwlock = _POSIX_RWLock_Get( rwlock, &location );
switch ( location ) {
the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );
case OBJECTS_LOCAL:
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_writing(
&the_rwlock->RWLock,
executing,
true, /* do not timeout -- wait forever */
0
);
_Objects_Put( &the_rwlock->Object );
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
if ( the_rwlock == NULL ) {
return EINVAL;
}
return EINVAL;
executing = _Thread_Executing;
_CORE_RWLock_Seize_for_writing(
&the_rwlock->RWLock,
executing,
true, /* do not timeout -- wait forever */
0,
&lock_context
);
return _POSIX_RWLock_Translate_core_RWLock_return_code(
(CORE_RWLock_Status) executing->Wait.return_code
);
}
@@ -86,6 +86,22 @@ RTEMS_INLINE_ROUTINE void _CORE_RWLock_Destroy(
_Thread_queue_Destroy( &the_rwlock->Wait_queue );
}
RTEMS_INLINE_ROUTINE void _CORE_RWLock_Acquire_critical(
CORE_RWLock_Control *the_rwlock,
ISR_lock_Context *lock_context
)
{
_Thread_queue_Acquire_critical( &the_rwlock->Wait_queue, lock_context );
}
RTEMS_INLINE_ROUTINE void _CORE_RWLock_Release(
CORE_RWLock_Control *the_rwlock,
ISR_lock_Context *lock_context
)
{
_Thread_queue_Release( &the_rwlock->Wait_queue, lock_context );
}
/**
* @brief Obtain RWLock for reading.
*
@@ -103,7 +119,8 @@ void _CORE_RWLock_Seize_for_reading(
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing,
bool wait,
Watchdog_Interval timeout
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
);
/**
@@ -122,7 +139,8 @@ void _CORE_RWLock_Seize_for_writing(
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing,
bool wait,
Watchdog_Interval timeout
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
);
/**
@@ -137,7 +155,7 @@ void _CORE_RWLock_Seize_for_writing(
*/
CORE_RWLock_Status _CORE_RWLock_Surrender(
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing
ISR_lock_Context *lock_context
);
/** @} */
+49 -51
View File
@@ -27,70 +27,68 @@ void _CORE_RWLock_Seize_for_reading(
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing,
bool wait,
Watchdog_Interval timeout
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
)
{
ISR_lock_Context lock_context;
/*
* If unlocked, then OK to read.
* If locked for reading and no waiters, then OK to read.
* If any thread is waiting, then we wait.
*/
_Thread_queue_Acquire( &the_rwlock->Wait_queue, &lock_context );
switch ( the_rwlock->current_state ) {
case CORE_RWLOCK_UNLOCKED:
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING;
the_rwlock->number_of_readers += 1;
_Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context );
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
return;
_CORE_RWLock_Acquire_critical( the_rwlock, lock_context );
case CORE_RWLOCK_LOCKED_FOR_READING: {
Thread_Control *waiter;
waiter = _Thread_queue_First_locked(
&the_rwlock->Wait_queue,
CORE_RWLOCK_TQ_OPERATIONS
);
if ( !waiter ) {
the_rwlock->number_of_readers += 1;
_Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context );
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
return;
}
break;
}
case CORE_RWLOCK_LOCKED_FOR_WRITING:
break;
}
/*
* If the thread is not willing to wait, then return immediately.
*/
if ( !wait ) {
_Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context );
executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
switch ( the_rwlock->current_state ) {
case CORE_RWLOCK_UNLOCKED:
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING;
the_rwlock->number_of_readers += 1;
_CORE_RWLock_Release( the_rwlock, lock_context );
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
return;
case CORE_RWLOCK_LOCKED_FOR_READING: {
Thread_Control *waiter;
waiter = _Thread_queue_First_locked(
&the_rwlock->Wait_queue,
CORE_RWLOCK_TQ_OPERATIONS
);
if ( !waiter ) {
the_rwlock->number_of_readers += 1;
_CORE_RWLock_Release( the_rwlock, lock_context );
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
return;
}
break;
}
case CORE_RWLOCK_LOCKED_FOR_WRITING:
break;
}
/*
* We need to wait to enter this critical section
*/
/*
* If the thread is not willing to wait, then return immediately.
*/
executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ;
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
if ( !wait ) {
_CORE_RWLock_Release( the_rwlock, lock_context );
executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
return;
}
_Thread_queue_Enqueue_critical(
&the_rwlock->Wait_queue.Queue,
CORE_RWLOCK_TQ_OPERATIONS,
executing,
STATES_WAITING_FOR_RWLOCK,
timeout,
CORE_RWLOCK_TIMEOUT,
&lock_context
);
/*
* We need to wait to enter this critical section
*/
/* return to API level so it can dispatch and we block */
executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ;
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
_Thread_queue_Enqueue_critical(
&the_rwlock->Wait_queue.Queue,
CORE_RWLOCK_TQ_OPERATIONS,
executing,
STATES_WAITING_FOR_RWLOCK,
timeout,
CORE_RWLOCK_TIMEOUT,
lock_context
);
}
+39 -41
View File
@@ -24,14 +24,13 @@
#include <rtems/score/watchdog.h>
void _CORE_RWLock_Seize_for_writing(
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing,
bool wait,
Watchdog_Interval timeout
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing,
bool wait,
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
)
{
ISR_lock_Context lock_context;
/*
* If unlocked, then OK to read.
* Otherwise, we have to block.
@@ -39,45 +38,44 @@ void _CORE_RWLock_Seize_for_writing(
* If any thread is waiting, then we wait.
*/
_Thread_queue_Acquire( &the_rwlock->Wait_queue, &lock_context );
switch ( the_rwlock->current_state ) {
case CORE_RWLOCK_UNLOCKED:
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING;
_Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context );
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
return;
_CORE_RWLock_Acquire_critical( the_rwlock, lock_context );
case CORE_RWLOCK_LOCKED_FOR_READING:
case CORE_RWLOCK_LOCKED_FOR_WRITING:
break;
}
/*
* If the thread is not willing to wait, then return immediately.
*/
if ( !wait ) {
_Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context );
executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
switch ( the_rwlock->current_state ) {
case CORE_RWLOCK_UNLOCKED:
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING;
_CORE_RWLock_Release( the_rwlock, lock_context );
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
return;
}
/*
* We need to wait to enter this critical section
*/
case CORE_RWLOCK_LOCKED_FOR_READING:
case CORE_RWLOCK_LOCKED_FOR_WRITING:
break;
}
executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE;
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
/*
* If the thread is not willing to wait, then return immediately.
*/
_Thread_queue_Enqueue_critical(
&the_rwlock->Wait_queue.Queue,
CORE_RWLOCK_TQ_OPERATIONS,
executing,
STATES_WAITING_FOR_RWLOCK,
timeout,
CORE_RWLOCK_TIMEOUT,
&lock_context
);
if ( !wait ) {
_CORE_RWLock_Release( the_rwlock, lock_context );
executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
return;
}
/* return to API level so it can dispatch and we block */
/*
* We need to wait to enter this critical section
*/
executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE;
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
_Thread_queue_Enqueue_critical(
&the_rwlock->Wait_queue.Queue,
CORE_RWLOCK_TQ_OPERATIONS,
executing,
STATES_WAITING_FOR_RWLOCK,
timeout,
CORE_RWLOCK_TIMEOUT,
lock_context
);
}
+86 -64
View File
@@ -19,19 +19,65 @@
#include "config.h"
#endif
#include <rtems/system.h>
#include <rtems/score/corerwlockimpl.h>
#include <rtems/score/threadqimpl.h>
#include <rtems/score/watchdog.h>
#include <rtems/score/assert.h>
static bool _CORE_RWLock_Is_waiting_for_reading(
const Thread_Control *the_thread
)
{
if ( the_thread->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_READ ) {
return true;
} else {
_Assert( the_thread->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE );
return false;
}
}
static Thread_Control *_CORE_RWLock_Flush_filter(
Thread_Control *the_thread,
Thread_queue_Queue *queue,
ISR_lock_Context *lock_context
)
{
CORE_RWLock_Control *the_rwlock;
the_rwlock = RTEMS_CONTAINER_OF(
queue,
CORE_RWLock_Control,
Wait_queue.Queue
);
switch ( the_rwlock->current_state ) {
case CORE_RWLOCK_LOCKED_FOR_READING:
if ( _CORE_RWLock_Is_waiting_for_reading( the_thread ) ) {
the_rwlock->number_of_readers += 1;
} else {
the_thread = NULL;
}
break;
case CORE_RWLOCK_LOCKED_FOR_WRITING:
the_thread = NULL;
break;
default:
_Assert( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED );
if ( _CORE_RWLock_Is_waiting_for_reading( the_thread ) ) {
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING;
the_rwlock->number_of_readers = 1;
} else {
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING;
}
break;
}
return the_thread;
}
CORE_RWLock_Status _CORE_RWLock_Surrender(
CORE_RWLock_Control *the_rwlock,
Thread_Control *executing
ISR_lock_Context *lock_context
)
{
ISR_Level level;
Thread_Control *next;
/*
* If unlocked, then OK to read.
* Otherwise, we have to block.
@@ -39,67 +85,43 @@ CORE_RWLock_Status _CORE_RWLock_Surrender(
* If any thread is waiting, then we wait.
*/
_ISR_Disable( level );
if ( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED){
_ISR_Enable( level );
executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
_CORE_RWLock_Acquire_critical( the_rwlock, lock_context );
if ( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED){
/* This is an error at the caller site */
_CORE_RWLock_Release( the_rwlock, lock_context );
return CORE_RWLOCK_SUCCESSFUL;
}
if ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING ) {
the_rwlock->number_of_readers -= 1;
if ( the_rwlock->number_of_readers != 0 ) {
/* must be unlocked again */
_CORE_RWLock_Release( the_rwlock, lock_context );
return CORE_RWLOCK_SUCCESSFUL;
}
if ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING ) {
the_rwlock->number_of_readers -= 1;
if ( the_rwlock->number_of_readers != 0 ) {
/* must be unlocked again */
_ISR_Enable( level );
return CORE_RWLOCK_SUCCESSFUL;
}
}
/* CORE_RWLOCK_LOCKED_FOR_WRITING or READING with readers */
executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
/*
* Implicitly transition to "unlocked" and find another thread interested
* in obtaining this rwlock.
*/
the_rwlock->current_state = CORE_RWLOCK_UNLOCKED;
_ISR_Enable( level );
next = _Thread_queue_Dequeue(
&the_rwlock->Wait_queue,
CORE_RWLOCK_TQ_OPERATIONS,
NULL,
0
);
if ( next ) {
if ( next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ) {
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING;
return CORE_RWLOCK_SUCCESSFUL;
}
/*
* Must be CORE_RWLOCK_THREAD_WAITING_FOR_READING
*/
the_rwlock->number_of_readers += 1;
the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING;
/*
* Now see if more readers can be let go.
*/
while ( 1 ) {
next = _Thread_queue_First(
&the_rwlock->Wait_queue,
CORE_RWLOCK_TQ_OPERATIONS
);
if ( !next ||
next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE )
return CORE_RWLOCK_SUCCESSFUL;
the_rwlock->number_of_readers += 1;
_Thread_queue_Extract( next );
}
}
/* indentation is to match _ISR_Disable at top */
_Assert(
the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_WRITING
|| ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING
&& the_rwlock->number_of_readers == 0 )
);
/*
* Implicitly transition to "unlocked" and find another thread interested
* in obtaining this rwlock.
*/
the_rwlock->current_state = CORE_RWLOCK_UNLOCKED;
_Thread_queue_Flush_critical(
&the_rwlock->Wait_queue.Queue,
CORE_RWLOCK_TQ_OPERATIONS,
_CORE_RWLock_Flush_filter,
NULL,
0,
lock_context
);
return CORE_RWLOCK_SUCCESSFUL;
}