adding rwlock and event support to mthread
This commit is contained in:
parent
e2758c6759
commit
03a8d06668
5 changed files with 431 additions and 0 deletions
|
@ -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) );
|
||||
|
|
|
@ -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
99
lib/libmthread/event.c
Normal 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
130
lib/libmthread/rwlock.c
Normal 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;
|
||||
}
|
175
test/test59.c
175
test/test59.c
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue