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:
@@ -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_ */
|
||||||
Reference in New Issue
Block a user