Added a basic pthread_mutex and pthread_mutexattr implementation which

will come in handy for the glibc stuff - and is great for our libroot.so,
too.
Everything should work except for: pthread_mutexattr_(set|get)prioceiling/
protocol(). That might be added at a later time, though, I don't consider
it a high priority.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3082 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2003-04-20 18:48:54 +00:00
parent 0008ea004e
commit 74b016ecad
4 changed files with 423 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
SubDir OBOS_TOP src kernel libroot posix pthread ;
KernelMergeObject posix_pthread.o :
<$(SOURCE_GRIST)>pthread_mutex.c
<$(SOURCE_GRIST)>pthread_mutexattr.c
:
-fPIC -DPIC
;
@@ -0,0 +1,238 @@
#include <pthread.h>
#include "pthread_private.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static const pthread_mutexattr pthread_mutexattr_default = {
PTHREAD_MUTEX_DEFAULT,
false
};
pthread_mutex_t
_pthread_recursive_mutex_static_initializer(void)
{
pthread_mutex_t mutex;
pthread_mutexattr attr;
pthread_mutexattr_t attrPointer = &attr;
attr.type = PTHREAD_MUTEX_RECURSIVE;
attr.process_shared = false;
if (pthread_mutex_init(&mutex, &attrPointer) == B_OK)
return mutex;
return NULL;
}
pthread_mutex_t
_pthread_mutex_static_initializer(void)
{
pthread_mutex_t mutex;
if (pthread_mutex_init(&mutex, NULL) == B_OK)
return mutex;
return NULL;
}
int
pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t *_attr)
{
pthread_mutex *mutex;
const pthread_mutexattr *attr = NULL;
if (_mutex == NULL)
return B_BAD_VALUE;
mutex = (pthread_mutex *)malloc(sizeof(pthread_mutex));
if (mutex == NULL)
return B_NO_MEMORY;
if (_attr != NULL)
attr = *_attr;
else
attr = &pthread_mutexattr_default;
mutex->sem = create_sem(attr && attr->process_shared ? 0 : 1, "pthread_mutex");
if (mutex->sem < B_OK) {
free(mutex);
return B_WOULD_BLOCK;
// stupid error code (EAGAIN) but demanded by POSIX
}
mutex->count = 0;
mutex->owner = -1;
mutex->owner_count = 0;
memcpy(&mutex->attr, attr, sizeof(pthread_mutexattr));
*_mutex = mutex;
return B_OK;
}
int
pthread_mutex_destroy(pthread_mutex_t *_mutex)
{
pthread_mutex *mutex;
if (_mutex == NULL || (mutex = *_mutex) == NULL)
return B_BAD_VALUE;
delete_sem(mutex->sem);
*_mutex = NULL;
free(mutex);
return B_OK;
}
static status_t
mutex_unlock(pthread_mutex *mutex)
{
if (mutex == NULL)
return B_BAD_VALUE;
if (mutex->owner != find_thread(NULL)) {
// this is a bug in the calling application!
// ToDo: should we handle it in another way?
fprintf(stderr, "mutex unlocked from foreign thread!\n");
}
if (mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) {
if (mutex->owner_count-- > 1)
return B_OK;
mutex->owner = -1;
}
if (!mutex->attr.process_shared || atomic_add(&mutex->count, -1) > 1)
release_sem(mutex->sem);
}
static status_t
mutex_lock(pthread_mutex *mutex, bigtime_t timeout)
{
thread_id thisThread = find_thread(NULL);
status_t status = B_OK;
if (mutex == NULL)
return B_BAD_VALUE;
if (mutex->attr.type == PTHREAD_MUTEX_ERRORCHECK && mutex->owner == thisThread) {
// we detect this kind of deadlock and return an error
return B_BUSY;
}
if (mutex->attr.type == PTHREAD_MUTEX_RECURSIVE && mutex->owner == thisThread) {
// if we already hold the mutex, we don't need to grab it again
mutex->owner_count++;
return B_OK;
}
if (!mutex->attr.process_shared || atomic_add(&mutex->count, 1) > 0) {
// this mutex is already locked by someone else, so we need
// to wait
status = acquire_sem_etc(mutex->sem, 1, timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_TIMEOUT, timeout);
}
if (status == B_OK) {
// we have locked the mutex for the first time
mutex->owner = thisThread;
mutex->owner_count = 1;
}
return status;
}
int
pthread_mutex_lock(pthread_mutex_t *_mutex)
{
if (_mutex == NULL)
return B_BAD_VALUE;
return mutex_lock(*_mutex, B_INFINITE_TIMEOUT);
}
int
pthread_mutex_trylock(pthread_mutex_t *_mutex)
{
if (_mutex == NULL)
return B_BAD_VALUE;
return mutex_lock(*_mutex, 0);
}
int
pthread_mutex_timedlock(pthread_mutex_t *_mutex, const struct timespec *tv)
{
bool invalidTime = false;
status_t status;
bigtime_t timeout = 0;
if (tv && tv->tv_nsec < 1000*1000*1000 && tv->tv_nsec >= 0)
timeout = tv->tv_sec * 1000000LL + tv->tv_nsec / 1000LL;
else
invalidTime = true;
if (_mutex == NULL)
return B_BAD_VALUE;
status = mutex_lock(*_mutex, timeout);
if (status != B_OK && invalidTime) {
// POSIX requires EINVAL (= B_BAD_VALUE) to be returned
// if the timespec structure was invalid
return B_BAD_VALUE;
}
return status;
}
int
pthread_mutex_unlock(pthread_mutex_t *_mutex)
{
if (_mutex == NULL)
return B_BAD_VALUE;
return mutex_unlock(*_mutex);
}
int
pthread_mutex_getprioceiling(pthread_mutex_t *_mutex, int *_prioCeiling)
{
pthread_mutex *mutex;
if (_mutex == NULL || (mutex = *_mutex) == NULL || _prioCeiling == NULL)
return B_BAD_VALUE;
*_prioCeiling = 0;
// not implemented
return B_OK;
}
int
pthread_mutex_setprioceiling(pthread_mutex_t *_mutex, int prioCeiling, int *_oldCeiling)
{
pthread_mutex *mutex;
if (_mutex == NULL || (mutex = *_mutex) == NULL)
return B_BAD_VALUE;
// not implemented
return B_NOT_ALLOWED;
}
@@ -0,0 +1,152 @@
#include <pthread.h>
#include "pthread_private.h"
#include <stdlib.h>
int
pthread_mutexattr_init(pthread_mutexattr_t *_mutexAttr)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL)
return B_BAD_VALUE;
attr = (pthread_mutexattr *)malloc(sizeof(pthread_mutexattr));
if (attr == NULL)
return B_NO_MEMORY;
attr->type = PTHREAD_MUTEX_DEFAULT;
attr->process_shared = false;
*_mutexAttr = attr;
return B_OK;
}
int
pthread_mutexattr_destroy(pthread_mutexattr_t *_mutexAttr)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL)
return B_BAD_VALUE;
*_mutexAttr = NULL;
free(attr);
return B_OK;
}
int
pthread_mutexattr_gettype(pthread_mutexattr_t *_mutexAttr, int *_type)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL || _type == NULL)
return B_BAD_VALUE;
*_type = attr->type;
return B_OK;
}
int
pthread_mutexattr_settype(pthread_mutexattr_t *_mutexAttr, int type)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL
|| type < PTHREAD_MUTEX_DEFAULT
|| type > PTHREAD_MUTEX_RECURSIVE)
return B_BAD_VALUE;
attr->type = type;
return B_OK;
}
int
pthread_mutexattr_getpshared(pthread_mutexattr_t *_mutexAttr, int *_processShared)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL || _processShared == NULL)
return B_BAD_VALUE;
*_processShared = attr->process_shared ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
return B_OK;
}
int
pthread_mutexattr_setpshared(pthread_mutexattr_t *_mutexAttr, int processShared)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL
|| processShared < PTHREAD_PROCESS_PRIVATE
|| processShared > PTHREAD_PROCESS_SHARED)
return B_BAD_VALUE;
attr->process_shared = processShared == PTHREAD_PROCESS_SHARED ? true : false;
return B_OK;
}
int
pthread_mutexattr_getprioceiling(pthread_mutexattr_t *_mutexAttr, int *_priorityCeiling)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL || _priorityCeiling == NULL)
return B_BAD_VALUE;
*_priorityCeiling = 0;
// not implemented
return B_OK;
}
int
pthread_mutexattr_setprioceiling(pthread_mutexattr_t *_mutexAttr, int priorityCeiling)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL)
return B_BAD_VALUE;
// not implemented
return B_NOT_ALLOWED;
}
int
pthread_mutexattr_getprotocol(pthread_mutexattr_t *_mutexAttr, int *_protocol)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL || _protocol == NULL)
return B_BAD_VALUE;
*_protocol = 0;
// not implemented
return B_OK;
}
int
pthread_mutexattr_setprotocol(pthread_mutexattr_t *_mutexAttr, int protocol)
{
pthread_mutexattr *attr;
if (_mutexAttr == NULL || (attr = *_mutexAttr) == NULL)
return B_BAD_VALUE;
// not implemented
return B_NOT_ALLOWED;
}
@@ -0,0 +1,24 @@
#ifndef _PTHREAD_PRIVATE_H_
#define _PTHREAD_PRIVATE_H_
#include <OS.h>
// The public *_t types are only pointers to these structures
// This way, we are completely free to change them, which might be
// necessary in the future (not only due to the incomplete implementation
// at this point).
typedef struct _pthread_mutexattr {
int32 type;
bool process_shared;
} pthread_mutexattr;
typedef struct _pthread_mutex {
vint32 count;
sem_id sem;
thread_id owner;
int32 owner_count;
pthread_mutexattr attr;
} pthread_mutex;
#endif /* _PTHREAD_PRIVATE_H_ */