I needed Pthread condition variables for WebKit, so I implemented
them. I have tested this with a simple test program I downloaded from the internet. We get the same result as on Linux, so I think this is good. I will test it more with WebKit later. Our Pthreads implementation is still missing some stuff, but this adds a good chunk. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22274 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+22
-6
@@ -12,7 +12,7 @@ typedef struct _pthread_attr *pthread_attr_t;
|
|||||||
typedef struct _pthread_mutex *pthread_mutex_t;
|
typedef struct _pthread_mutex *pthread_mutex_t;
|
||||||
typedef struct _pthread_mutexattr *pthread_mutexattr_t;
|
typedef struct _pthread_mutexattr *pthread_mutexattr_t;
|
||||||
typedef struct _pthread_cond *pthread_cond_t;
|
typedef struct _pthread_cond *pthread_cond_t;
|
||||||
typedef struct _pthread_cond_attr *pthread_condattr_t;
|
typedef struct _pthread_condattr *pthread_condattr_t;
|
||||||
typedef int pthread_key_t;
|
typedef int pthread_key_t;
|
||||||
typedef struct _pthread_once pthread_once_t;
|
typedef struct _pthread_once pthread_once_t;
|
||||||
typedef struct _pthread_rwlock *pthread_rwlock_t;
|
typedef struct _pthread_rwlock *pthread_rwlock_t;
|
||||||
@@ -42,10 +42,10 @@ enum pthread_process_shared {
|
|||||||
/*
|
/*
|
||||||
* Flags for threads and thread attributes.
|
* Flags for threads and thread attributes.
|
||||||
*/
|
*/
|
||||||
#define PTHREAD_DETACHED 0x1
|
#define PTHREAD_DETACHED 0x1
|
||||||
#define PTHREAD_SCOPE_SYSTEM 0x2
|
#define PTHREAD_SCOPE_SYSTEM 0x2
|
||||||
#define PTHREAD_INHERIT_SCHED 0x4
|
#define PTHREAD_INHERIT_SCHED 0x4
|
||||||
#define PTHREAD_NOFLOAT 0x8
|
#define PTHREAD_NOFLOAT 0x8
|
||||||
|
|
||||||
#define PTHREAD_CREATE_DETACHED PTHREAD_DETACHED
|
#define PTHREAD_CREATE_DETACHED PTHREAD_DETACHED
|
||||||
#define PTHREAD_CREATE_JOINABLE 0
|
#define PTHREAD_CREATE_JOINABLE 0
|
||||||
@@ -61,14 +61,12 @@ enum pthread_process_shared {
|
|||||||
#define PTHREAD_CANCEL_ASYNCHRONOUS 2
|
#define PTHREAD_CANCEL_ASYNCHRONOUS 2
|
||||||
#define PTHREAD_CANCELED ((void *) 1)
|
#define PTHREAD_CANCELED ((void *) 1)
|
||||||
|
|
||||||
#define PTHREAD_COND_INITIALIZER NULL
|
|
||||||
|
|
||||||
#define PTHREAD_NEEDS_INIT 0
|
#define PTHREAD_NEEDS_INIT 0
|
||||||
#define PTHREAD_DONE_INIT 1
|
#define PTHREAD_DONE_INIT 1
|
||||||
#define PTHREAD_ONCE_INIT { PTHREAD_NEEDS_INIT, NULL }
|
#define PTHREAD_ONCE_INIT { PTHREAD_NEEDS_INIT, NULL }
|
||||||
|
|
||||||
#define PTHREAD_BARRIER_SERIAL_THREAD -1
|
#define PTHREAD_BARRIER_SERIAL_THREAD -1
|
||||||
#define PTHREAD_PRIO_NONE 0
|
#define PTHREAD_PRIO_NONE 0
|
||||||
#define PTHREAD_PRIO_INHERIT 1
|
#define PTHREAD_PRIO_INHERIT 1
|
||||||
#define PTHREAD_PRIO_PROTECT 2
|
#define PTHREAD_PRIO_PROTECT 2
|
||||||
|
|
||||||
@@ -84,6 +82,9 @@ extern pthread_mutex_t _pthread_recursive_mutex_static_initializer(void);
|
|||||||
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER \
|
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER \
|
||||||
pthread_recursive_mutex_static_initializer();
|
pthread_recursive_mutex_static_initializer();
|
||||||
|
|
||||||
|
extern pthread_cond_t _pthread_cond_static_initializer(void);
|
||||||
|
#define PTHREAD_COND_INITIALIZER _pthread_cond_static_initializer();
|
||||||
|
|
||||||
/* mutex functions */
|
/* mutex functions */
|
||||||
extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||||
extern int pthread_mutex_getprioceiling(pthread_mutex_t *mutex, int *_priorityCeiling);
|
extern int pthread_mutex_getprioceiling(pthread_mutex_t *mutex, int *_priorityCeiling);
|
||||||
@@ -107,6 +108,21 @@ extern int pthread_mutexattr_setprotocol(pthread_mutexattr_t *mutexAttr, int pro
|
|||||||
extern int pthread_mutexattr_setpshared(pthread_mutexattr_t *mutexAttr, int processShared);
|
extern int pthread_mutexattr_setpshared(pthread_mutexattr_t *mutexAttr, int processShared);
|
||||||
extern int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type);
|
extern int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type);
|
||||||
|
|
||||||
|
/* condition variable functions */
|
||||||
|
extern int pthread_cond_destroy(pthread_cond_t *cond);
|
||||||
|
extern int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
|
||||||
|
extern int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||||
|
extern int pthread_cond_signal(pthread_cond_t *cond);
|
||||||
|
extern int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||||
|
const struct timespec *abstime);
|
||||||
|
extern int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
||||||
|
|
||||||
|
/* condition variable attribute functions */
|
||||||
|
extern int pthread_condattr_destroy(pthread_condattr_t *condAttr);
|
||||||
|
extern int pthread_condattr_init(pthread_condattr_t *condAttr);
|
||||||
|
extern int pthread_condattr_getpshared(const pthread_condattr_t *condAttr, int *processShared);
|
||||||
|
extern int pthread_condattr_setpshared(pthread_condattr_t *condAttr, int processShared);
|
||||||
|
|
||||||
/* misc. functions */
|
/* misc. functions */
|
||||||
extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
|
extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ MergeObject posix_pthread.o :
|
|||||||
pthread.c
|
pthread.c
|
||||||
pthread_atfork.c
|
pthread_atfork.c
|
||||||
pthread_attr.c
|
pthread_attr.c
|
||||||
|
pthread_cond.c
|
||||||
|
pthread_condattr.c
|
||||||
pthread_key.c
|
pthread_key.c
|
||||||
pthread_mutex.c
|
pthread_mutex.c
|
||||||
pthread_mutexattr.c
|
pthread_mutexattr.c
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Ryan Leavengood, [email protected].
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "pthread_private.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const pthread_condattr pthread_condattr_default = {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
pthread_cond_t
|
||||||
|
_pthread_cond_static_initializer(void)
|
||||||
|
{
|
||||||
|
pthread_cond_t cond;
|
||||||
|
if (pthread_cond_init(&cond, NULL) == B_OK)
|
||||||
|
return cond;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_cond_init(pthread_cond_t *_cond, const pthread_condattr_t *_attr)
|
||||||
|
{
|
||||||
|
pthread_cond *cond;
|
||||||
|
const pthread_condattr *attr = NULL;
|
||||||
|
|
||||||
|
if (_cond == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
cond = (pthread_cond *)malloc(sizeof(pthread_cond));
|
||||||
|
if (cond == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (_attr != NULL)
|
||||||
|
attr = *_attr;
|
||||||
|
else
|
||||||
|
attr = &pthread_condattr_default;
|
||||||
|
|
||||||
|
// TODO: What about the process_shared attribute?
|
||||||
|
cond->sem = create_sem(0, "pthread_cond");
|
||||||
|
if (cond->sem < B_OK) {
|
||||||
|
free(cond);
|
||||||
|
return B_WOULD_BLOCK;
|
||||||
|
// stupid error code (EAGAIN) but demanded by POSIX
|
||||||
|
}
|
||||||
|
|
||||||
|
cond->mutex = NULL;
|
||||||
|
cond->waiter_count = 0;
|
||||||
|
memcpy(&cond->attr, attr, sizeof(pthread_condattr));
|
||||||
|
|
||||||
|
*_cond = cond;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_cond_destroy(pthread_cond_t *_cond)
|
||||||
|
{
|
||||||
|
pthread_cond *cond;
|
||||||
|
|
||||||
|
if (_cond == NULL || (cond = *_cond) == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
delete_sem(cond->sem);
|
||||||
|
*_cond = NULL;
|
||||||
|
free(cond);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cond_wait(pthread_cond *cond, pthread_mutex_t *_mutex, bigtime_t timeout)
|
||||||
|
{
|
||||||
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
if (cond == NULL || *_mutex == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if ((*_mutex)->owner != find_thread(NULL))
|
||||||
|
// POSIX suggests EPERM (= B_NOT_ALLOWED) to be returned
|
||||||
|
// if this thread does not own the mutex
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
if (cond->mutex && cond->mutex != _mutex)
|
||||||
|
// POSIX suggests EINVAL (= B_BAD_VALUE) to be returned if
|
||||||
|
// the same condition variable is used with multiple mutexes
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
cond->mutex = _mutex;
|
||||||
|
cond->waiter_count++;
|
||||||
|
pthread_mutex_unlock(_mutex);
|
||||||
|
status = acquire_sem_etc(cond->sem, 1, timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_TIMEOUT, timeout);
|
||||||
|
pthread_mutex_lock(_mutex);
|
||||||
|
cond->waiter_count--;
|
||||||
|
// If there are no more waiters, we can change mutexes
|
||||||
|
if (cond->waiter_count == 0)
|
||||||
|
cond->mutex = NULL;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cond_signal(pthread_cond *cond, bool broadcast)
|
||||||
|
{
|
||||||
|
if (cond == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
return release_sem_etc(cond->sem, broadcast ? cond->waiter_count : 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_cond_wait(pthread_cond_t *_cond, pthread_mutex_t *_mutex)
|
||||||
|
{
|
||||||
|
if (_cond == NULL || _mutex == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (*_cond == NULL)
|
||||||
|
pthread_cond_init(_cond, NULL);
|
||||||
|
|
||||||
|
return cond_wait(*_cond, _mutex, B_INFINITE_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_cond_timedwait(pthread_cond_t *_cond, 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 (_cond == NULL || _mutex == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (*_cond == NULL)
|
||||||
|
pthread_cond_init(_cond, NULL);
|
||||||
|
|
||||||
|
status = cond_wait(*_cond, _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_cond_broadcast(pthread_cond_t *_cond)
|
||||||
|
{
|
||||||
|
if (_cond == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
return cond_signal(*_cond, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_cond_signal(pthread_cond_t *_cond)
|
||||||
|
{
|
||||||
|
if (_cond == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
return cond_signal(*_cond, false);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Ryan Leavengood, [email protected].
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "pthread_private.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_condattr_init(pthread_condattr_t *_condAttr)
|
||||||
|
{
|
||||||
|
pthread_condattr *attr;
|
||||||
|
|
||||||
|
if (_condAttr == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
attr = (pthread_condattr *)malloc(sizeof(pthread_condattr));
|
||||||
|
if (attr == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
attr->process_shared = false;
|
||||||
|
|
||||||
|
*_condAttr = attr;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_condattr_destroy(pthread_condattr_t *_condAttr)
|
||||||
|
{
|
||||||
|
pthread_condattr *attr;
|
||||||
|
|
||||||
|
if (_condAttr == NULL || (attr = *_condAttr) == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
*_condAttr = NULL;
|
||||||
|
free(attr);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_condattr_getpshared(const pthread_condattr_t *_condAttr, int *_processShared)
|
||||||
|
{
|
||||||
|
pthread_condattr *attr;
|
||||||
|
|
||||||
|
if (_condAttr == NULL || (attr = *_condAttr) == NULL || _processShared == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
*_processShared = attr->process_shared ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pthread_condattr_setpshared(pthread_condattr_t *_condAttr, int processShared)
|
||||||
|
{
|
||||||
|
pthread_condattr *attr;
|
||||||
|
|
||||||
|
if (_condAttr == NULL || (attr = *_condAttr) == 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#ifndef _PTHREAD_PRIVATE_H_
|
#ifndef _PTHREAD_PRIVATE_H_
|
||||||
#define _PTHREAD_PRIVATE_H_
|
#define _PTHREAD_PRIVATE_H_
|
||||||
/*
|
/*
|
||||||
** Copyright 2003, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2003, Axel Dörfler, [email protected].
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Copyright 2007, Ryan Leavengood, [email protected].
|
||||||
*/
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
@@ -12,6 +13,17 @@
|
|||||||
// necessary in the future (not only due to the incomplete implementation
|
// necessary in the future (not only due to the incomplete implementation
|
||||||
// at this point).
|
// at this point).
|
||||||
|
|
||||||
|
typedef struct _pthread_condattr {
|
||||||
|
bool process_shared;
|
||||||
|
} pthread_condattr;
|
||||||
|
|
||||||
|
typedef struct _pthread_cond {
|
||||||
|
sem_id sem;
|
||||||
|
pthread_mutex_t *mutex;
|
||||||
|
int32 waiter_count;
|
||||||
|
pthread_condattr attr;
|
||||||
|
} pthread_cond;
|
||||||
|
|
||||||
typedef struct _pthread_mutexattr {
|
typedef struct _pthread_mutexattr {
|
||||||
int32 type;
|
int32 type;
|
||||||
bool process_shared;
|
bool process_shared;
|
||||||
|
|||||||
Reference in New Issue
Block a user