adding rwlock and event support to mthread

This commit is contained in:
Raja Appuswamy 2011-11-29 14:03:49 +01:00 committed by Ben Gras
parent e2758c6759
commit 03a8d06668
5 changed files with 431 additions and 0 deletions

View file

@ -56,6 +56,18 @@ struct __mthread_attr {
};
typedef struct __mthread_attr *mthread_attr_t;
typedef struct {
mthread_mutex_t mutex;
mthread_cond_t cond;
} mthread_event_t;
typedef struct {
unsigned int readers;
mthread_thread_t writer;
mthread_mutex_t queue;
mthread_event_t drain;
} mthread_rwlock_t;
#define MTHREAD_CREATE_JOINABLE 001
#define MTHREAD_CREATE_DETACHED 002
#define MTHREAD_ONCE_INIT 0
@ -122,6 +134,19 @@ _PROTOTYPE( int mthread_mutex_lock, (mthread_mutex_t *mutex) );
_PROTOTYPE( int mthread_mutex_trylock, (mthread_mutex_t *mutex) );
_PROTOTYPE( int mthread_mutex_unlock, (mthread_mutex_t *mutex) );
/* event.c */
_PROTOTYPE( int mthread_event_destroy, (mthread_event_t *event) );
_PROTOTYPE( int mthread_event_init, (mthread_event_t *event) );
_PROTOTYPE( int mthread_event_wait, (mthread_event_t *event) );
_PROTOTYPE( int mthread_event_fire, (mthread_event_t *event) );
/* rwlock.c */
_PROTOTYPE( int mthread_rwlock_destroy, (mthread_rwlock_t *rwlock) );
_PROTOTYPE( int mthread_rwlock_init, (mthread_rwlock_t *rwlock) );
_PROTOTYPE( int mthread_rwlock_rdlock, (mthread_rwlock_t *rwlock) );
_PROTOTYPE( int mthread_rwlock_wrlock, (mthread_rwlock_t *rwlock) );
_PROTOTYPE( int mthread_rwlock_unlock, (mthread_rwlock_t *rwlock) );
/* schedule.c */
_PROTOTYPE( void mthread_init, (void) );
_PROTOTYPE( int mthread_yield, (void) );

View file

@ -8,6 +8,8 @@ SRCS= \
allocate.c \
attribute.c \
mutex.c \
event.c \
rwlock.c \
misc.c \
queue.c \
condition.c \

99
lib/libmthread/event.c Normal file
View file

@ -0,0 +1,99 @@
#include <minix/mthread.h>
#include "global.h"
/*===========================================================================*
* mthread_event_init *
*===========================================================================*/
PUBLIC int mthread_event_init(event)
mthread_event_t *event; /* The event to be initialized */
{
/* Initialize an event object.
*/
int r;
if (!event)
return EINVAL;
r = mthread_mutex_init(&event->mutex, NULL);
if (r != 0)
return r;
r = mthread_cond_init(&event->cond, NULL);
if (r != 0)
mthread_mutex_destroy(&event->mutex);
return r;
}
/*===========================================================================*
* mthread_event_destroy *
*===========================================================================*/
PUBLIC int mthread_event_destroy(event)
mthread_event_t *event; /* The event to be destroyed */
{
/* Destroy an event object.
*/
int r;
if (!event)
return EINVAL;
r = mthread_cond_destroy(&event->cond);
if (r != 0)
return r;
return mthread_mutex_destroy(&event->mutex);
}
/*===========================================================================*
* mthread_event_wait *
*===========================================================================*/
PUBLIC int mthread_event_wait(event)
mthread_event_t *event; /* The event to be waited on */
{
/* Wait for an event, blocking the current thread in the process.
*/
int r;
if (!event)
return EINVAL;
r = mthread_mutex_lock(&event->mutex);
if (r != 0)
return r;
r = mthread_cond_wait(&event->cond, &event->mutex);
if (r != 0) {
mthread_mutex_unlock(&event->mutex);
return r;
}
return mthread_mutex_unlock(&event->mutex);
}
/*===========================================================================*
* mthread_event_fire *
*===========================================================================*/
PUBLIC int mthread_event_fire(event)
mthread_event_t *event; /* The event to be fired */
{
/* Fire an event, waking up any thread blocked on it.
*/
int r;
if (!event)
return EINVAL;
r = mthread_mutex_lock(&event->mutex);
if (r != 0)
return r;
r = mthread_cond_signal(&event->cond);
if (r != 0) {
mthread_mutex_unlock(&event->mutex);
return r;
}
return mthread_mutex_unlock(&event->mutex);
}

130
lib/libmthread/rwlock.c Normal file
View file

@ -0,0 +1,130 @@
#include <minix/mthread.h>
#include "global.h"
/*===========================================================================*
* mthread_rwlock_init *
*===========================================================================*/
PUBLIC int mthread_rwlock_init(rwlock)
mthread_rwlock_t *rwlock; /* The rwlock to be initialized */
{
/* Initialize a readers/writer lock. */
int r;
if (!rwlock)
return EINVAL;
rwlock->writer = NO_THREAD;
rwlock->readers = 0;
r = mthread_mutex_init(&rwlock->queue, NULL);
if (r != 0)
return r;
r = mthread_event_init(&rwlock->drain);
if (r != 0)
mthread_mutex_destroy(&rwlock->queue);
return r;
}
/*===========================================================================*
* mthread_rwlock_destroy *
*===========================================================================*/
PUBLIC int mthread_rwlock_destroy(rwlock)
mthread_rwlock_t *rwlock; /* The rwlock to be destroyed */
{
/* Destroy a readers/writer lock. */
int r;
if (!rwlock)
return EINVAL;
assert(rwlock->writer == NO_THREAD);
assert(rwlock->readers == 0);
r = mthread_event_destroy(&rwlock->drain);
if (r != 0)
return r;
return mthread_mutex_destroy(&rwlock->queue);
}
/*===========================================================================*
* mthread_rwlock_rdlock *
*===========================================================================*/
PUBLIC int mthread_rwlock_rdlock(rwlock)
mthread_rwlock_t *rwlock; /* The rwlock to be read locked */
{
/* Acquire a reader lock. */
int r;
if (!rwlock)
return EINVAL;
r = mthread_mutex_lock(&rwlock->queue);
if (r != 0)
return r;
r = mthread_mutex_unlock(&rwlock->queue);
if (r != 0)
return r;
rwlock->readers++;
return 0;
}
/*===========================================================================*
* mthread_rwlock_wrlock *
*===========================================================================*/
PUBLIC int mthread_rwlock_wrlock(rwlock)
mthread_rwlock_t *rwlock; /* The rwlock to be write locked */
{
/* Acquire a writer lock. */
int r;
if (!rwlock)
return EINVAL;
r = mthread_mutex_lock(&rwlock->queue);
if (r != 0)
return r;
rwlock->writer = current_thread;
if (rwlock->readers > 0)
r = mthread_event_wait(&rwlock->drain);
if (r == 0)
assert(rwlock->readers == 0);
return r;
}
/*===========================================================================*
* mthread_rwlock_unlock *
*===========================================================================*/
PUBLIC int mthread_rwlock_unlock(rwlock)
mthread_rwlock_t *rwlock; /* The rwlock to be unlocked */
{
/* Release a lock. */
int r;
r = 0;
if (!rwlock)
return EINVAL;
if (rwlock->writer == current_thread) {
rwlock->writer = NO_THREAD;
r = mthread_mutex_unlock(&rwlock->queue);
} else {
assert(rwlock->readers > 0);
rwlock->readers--;
if (rwlock->readers == 0 && rwlock->writer != NO_THREAD)
r = mthread_event_fire(&rwlock->drain);
}
return r;
}

View file

@ -11,6 +11,8 @@
#define once_t mthread_once_t
#define attr_t mthread_attr_t
#define key_t mthread_key_t
#define event_t mthread_event_t
#define rwlock_t mthread_rwlock_t
#define MAX_ERROR 5
#include "common.c"
@ -26,6 +28,24 @@ PRIVATE once_t once;
PRIVATE key_t key[MTHREAD_KEYS_MAX+1];
PRIVATE int values[4];
PRIVATE int first;
PRIVATE event_t event;
PRIVATE int event_a_step, event_b_step;
PRIVATE rwlock_t rwlock;
PRIVATE int rwlock_a_step, rwlock_b_step;
#define VERIFY_RWLOCK(a, b, esub, eno) \
GEN_VERIFY(rwlock_a_step, a, rwlock_b_step, b, esub, eno)
#define VERIFY_EVENT(a, b, esub, eno) \
GEN_VERIFY(event_a_step, a, event_b_step, b, esub, eno)
#define GEN_VERIFY(acta, a, actb, b, esub, eno) do { \
if (acta != a) { \
printf("Expected %d %d, got: %d %d\n", \
a, b, acta, actb); \
err(esub, eno); \
} else if (actb != b) err(esub, eno); \
} while(0)
#define VERIFY_MUTEX(a,b,c,esub,eno) do { \
if (mutex_a_step != a) { \
@ -920,6 +940,157 @@ PRIVATE void test_keys(void)
if (mthread_join(t[i], NULL) != 0) err(20, 28);
}
/*===========================================================================*
* event_a *
*===========================================================================*/
PRIVATE void *event_a(void *arg)
{
VERIFY_EVENT(0, 0, 21, 1);
if (mthread_event_wait(&event) != 0) err(21, 2);
event_a_step = 1;
if (mthread_event_fire(&event) != 0) err(21, 3);
mthread_yield();
VERIFY_EVENT(1, 1, 21, 4);
return(NULL);
}
/*===========================================================================*
* event_b *
*===========================================================================*/
PRIVATE void *event_b(void *arg)
{
VERIFY_EVENT(0, 0, 22, 1);
if (mthread_event_wait(&event) != 0) err(22, 2);
VERIFY_EVENT(1, 0, 22, 3);
event_b_step = 1;
return(NULL);
}
/*===========================================================================*
* test_event *
*===========================================================================*/
PRIVATE void test_event(void)
{
thread_t t[2];
int i;
if (mthread_event_init(&event) != 0) err(23, 1);
/* Try with faulty memory locations */
if (mthread_event_wait(NULL) == 0) err(23, 2);
if (mthread_event_fire(NULL) == 0) err(23, 3);
if (mthread_create(&t[0], NULL, event_a, NULL) != 0) err(23, 4);
if (mthread_create(&t[1], NULL, event_b, NULL) != 0) err(23, 5);
mthread_yield_all();
VERIFY_EVENT(0, 0, 23, 6);
if (mthread_event_fire(&event) != 0) err(23, 7);
mthread_yield_all();
for (i = 0; i < 2; i++)
if (mthread_join(t[i], NULL) != 0) err(23, 8);
if (mthread_event_destroy(&event) != 0) err(23, 9);
}
/*===========================================================================*
* rwlock_a *
*===========================================================================*/
PRIVATE void *rwlock_a(void *arg)
{
/* acquire read lock */
VERIFY_RWLOCK(0, 0, 24, 1);
if (mthread_rwlock_rdlock(&rwlock) != 0) err(24, 2);
rwlock_a_step = 1;
mthread_yield();
/* release read lock */
VERIFY_RWLOCK(1, 1, 24, 3);
if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 4);
rwlock_a_step = 2;
/* get write lock */
if (mthread_rwlock_wrlock(&rwlock) != 0) err(24, 5);
rwlock_a_step = 3;
VERIFY_RWLOCK(3, 2, 24, 6);
/* release write lock */
if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 7);
mthread_yield();
VERIFY_RWLOCK(3, 3, 24, 8);
return(NULL);
}
/*===========================================================================*
* rwlock_b *
*===========================================================================*/
PRIVATE void *rwlock_b(void *arg)
{
/* Step 1: acquire the read lock */
VERIFY_RWLOCK(1, 0, 25, 1);
if (mthread_rwlock_rdlock(&rwlock) != 0) err(25, 2);
rwlock_b_step = 1;
mthread_yield();
/* We return back with first thread blocked on wrlock */
VERIFY_RWLOCK(2, 1, 25, 3);
rwlock_b_step = 2;
/* Release read lock and acquire write lock */
if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 4);
if (mthread_rwlock_wrlock(&rwlock) != 0) err(25, 5);
rwlock_b_step = 3;
VERIFY_RWLOCK(3, 3, 25, 6);
if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 6);
return(NULL);
}
/*===========================================================================*
* test_rwlock *
*===========================================================================*/
PRIVATE void test_rwlock(void)
{
thread_t t[2];
int i;
if (mthread_rwlock_init(&rwlock) != 0) err(26, 1);
/* Try with faulty memory locations */
if (mthread_rwlock_rdlock(NULL) == 0) err(26, 2);
if (mthread_rwlock_wrlock(NULL) == 0) err(26, 3);
if (mthread_rwlock_unlock(NULL) == 0) err(26, 4);
/* Create the threads and start testing */
if (mthread_create(&t[0], NULL, rwlock_a, NULL) != 0) err(26, 5);
if (mthread_create(&t[1], NULL, rwlock_b, NULL) != 0) err(26, 6);
mthread_yield_all();
for (i = 0; i < 2; i++)
if (mthread_join(t[i], NULL) != 0) err(26, 7);
if (mthread_rwlock_destroy(&rwlock) != 0) err(26, 8);
}
/*===========================================================================*
* main *
*===========================================================================*/
@ -928,12 +1099,16 @@ int main(void)
errct = 0;
th_a = th_b = th_c = th_d = th_e = th_f = th_g = th_h = 0;
mutex_a_step = mutex_b_step = mutex_c_step = 0;
event_a_step = event_b_step = 0;
rwlock_a_step = rwlock_b_step = 0;
once = MTHREAD_ONCE_INIT;
start(59);
mthread_init();
test_scheduling();
test_mutex();
test_event();
test_rwlock();
test_condition();
test_attributes();
test_keys();