* Rearranged pthread thread support a bit: there is now a pthread_thread
structure that is attached (via TLS) to each pthread.
* Implemented support for pthread_cleanup_{push|pop}().
* I haven't really been able to test these changes, yet, though.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24704 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+38
-11
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Distributed under the terms of the Haiku License.
|
* Copyright 2001-2008, Haiku Inc. All Rights Reserved.
|
||||||
*/
|
* Distributed under the terms of the Haiku License.
|
||||||
|
*/
|
||||||
#ifndef _PTHREAD_H_
|
#ifndef _PTHREAD_H_
|
||||||
#define _PTHREAD_H_
|
#define _PTHREAD_H_
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ 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;
|
||||||
typedef struct _pthread_rwlockattr *pthread_rwlockattr_t;
|
typedef struct _pthread_rwlockattr *pthread_rwlockattr_t;
|
||||||
typedef struct _pthread_barrier *pthread_barrier_t;
|
typedef struct _pthread_barrier *pthread_barrier_t;
|
||||||
typedef struct _pthread_barrierattr *pthread_barrierattr_t;
|
typedef struct _pthread_barrierattr *pthread_barrierattr_t;
|
||||||
typedef struct _pthread_spinlock *pthread_spinlock_t;
|
typedef struct _pthread_spinlock *pthread_spinlock_t;
|
||||||
|
|
||||||
struct _pthread_once {
|
struct _pthread_once {
|
||||||
@@ -58,19 +59,40 @@ enum pthread_process_shared {
|
|||||||
#define PTHREAD_CANCEL_DISABLE 1
|
#define PTHREAD_CANCEL_DISABLE 1
|
||||||
#define PTHREAD_CANCEL_DEFERRED 0
|
#define PTHREAD_CANCEL_DEFERRED 0
|
||||||
#define PTHREAD_CANCEL_ASYNCHRONOUS 2
|
#define PTHREAD_CANCEL_ASYNCHRONOUS 2
|
||||||
#define PTHREAD_CANCELED ((void *) 1)
|
#define PTHREAD_CANCELED ((void *) 1)
|
||||||
|
|
||||||
#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
|
||||||
|
|
||||||
//extern pthread_mutexattr_t pthread_mutexattr_default;
|
//extern pthread_mutexattr_t pthread_mutexattr_default;
|
||||||
|
|
||||||
|
/* private structure */
|
||||||
|
struct __pthread_cleanup_handler {
|
||||||
|
struct __pthread_cleanup_handler *previous;
|
||||||
|
void (*function)(void *argument);
|
||||||
|
void *argument;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define pthread_cleanup_push(func, arg) \
|
||||||
|
do { \
|
||||||
|
struct __pthread_cleanup_handler __handler; \
|
||||||
|
__handler.function = (func); \
|
||||||
|
__handler.argument = (arg); \
|
||||||
|
__pthread_cleanup_push_handler(&__handler);
|
||||||
|
|
||||||
|
#define pthread_cleanup_pop(execute) \
|
||||||
|
if (execute) \
|
||||||
|
__handler.function(__handler.argument); \
|
||||||
|
__pthread_cleanup_pop_handler(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -132,7 +154,7 @@ extern int pthread_attr_init(pthread_attr_t *attr);
|
|||||||
extern int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
|
extern int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
|
||||||
extern int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
|
extern int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
|
||||||
|
|
||||||
extern int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
extern int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
void *(*start_routine)(void*), void *arg);
|
void *(*start_routine)(void*), void *arg);
|
||||||
extern int pthread_detach(pthread_t thread);
|
extern int pthread_detach(pthread_t thread);
|
||||||
extern int pthread_equal(pthread_t t1, pthread_t t2);
|
extern int pthread_equal(pthread_t t1, pthread_t t2);
|
||||||
@@ -148,6 +170,11 @@ extern int pthread_key_delete(pthread_key_t key);
|
|||||||
extern void *pthread_getspecific(pthread_key_t key);
|
extern void *pthread_getspecific(pthread_key_t key);
|
||||||
extern int pthread_setspecific(pthread_key_t key, const void *value);
|
extern int pthread_setspecific(pthread_key_t key, const void *value);
|
||||||
|
|
||||||
|
/* private functions */
|
||||||
|
extern void __pthread_cleanup_push_handler(
|
||||||
|
struct __pthread_cleanup_handler *handler);
|
||||||
|
extern struct __pthread_cleanup_handler *__pthread_cleanup_pop_handler(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ MergeObject posix_pthread.o :
|
|||||||
pthread.c
|
pthread.c
|
||||||
pthread_atfork.c
|
pthread_atfork.c
|
||||||
pthread_attr.c
|
pthread_attr.c
|
||||||
|
pthread_cleanup.cpp
|
||||||
pthread_cond.c
|
pthread_cond.c
|
||||||
pthread_condattr.c
|
pthread_condattr.c
|
||||||
pthread_key.c
|
pthread_key.c
|
||||||
|
|||||||
@@ -1,45 +1,77 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2008, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Copyright 2006, Jérôme Duval. All rights reserved.
|
* Copyright 2006, Jérôme Duval. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pthread.h>
|
#include "pthread_private.h"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "pthread_private.h"
|
|
||||||
|
#include <TLS.h>
|
||||||
|
|
||||||
|
|
||||||
static const pthread_attr pthread_attr_default = {
|
static const pthread_attr pthread_attr_default = {
|
||||||
PTHREAD_CREATE_JOINABLE,
|
PTHREAD_CREATE_JOINABLE,
|
||||||
B_NORMAL_PRIORITY
|
B_NORMAL_PRIORITY
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pthread_data {
|
|
||||||
thread_entry entry;
|
static int32 sPthreadSlot = -1;
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
struct pthread_thread *
|
||||||
|
__get_pthread(void)
|
||||||
|
{
|
||||||
|
return (struct pthread_thread *)tls_get(sPthreadSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
pthread_destroy_thread(void *data)
|
||||||
|
{
|
||||||
|
struct pthread_thread *thread = __get_pthread();
|
||||||
|
|
||||||
|
// call cleanup handlers
|
||||||
|
while (true) {
|
||||||
|
struct __pthread_cleanup_handler *handler = __pthread_cleanup_pop_handler();
|
||||||
|
if (handler == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
handler->function(handler->argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
__pthread_key_call_destructors();
|
||||||
|
free(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int32
|
static int32
|
||||||
_pthread_thread_entry(void *entry_data)
|
pthread_thread_entry(void *_thread)
|
||||||
{
|
{
|
||||||
struct pthread_data *pdata = (struct pthread_data *)entry_data;
|
struct pthread_thread *thread = (struct pthread_thread *)_thread;
|
||||||
void *(*entry)(void*) = (void *(*)(void*))pdata->entry;
|
|
||||||
void *data = pdata->data;
|
|
||||||
|
|
||||||
free(pdata);
|
// store thread data in TLS
|
||||||
on_exit_thread(_pthread_key_call_destructors, NULL);
|
*tls_address(sPthreadSlot) = thread;
|
||||||
|
|
||||||
pthread_exit(entry(data));
|
on_exit_thread(pthread_destroy_thread, NULL);
|
||||||
|
|
||||||
|
pthread_exit(thread->entry(thread->entry_argument));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
// #pragma mark - public API
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
pthread_create(pthread_t *_thread, const pthread_attr_t *_attr,
|
pthread_create(pthread_t *_thread, const pthread_attr_t *_attr,
|
||||||
void *(*start_routine)(void*), void *arg)
|
void *(*startRoutine)(void*), void *arg)
|
||||||
{
|
{
|
||||||
thread_id thread;
|
|
||||||
const pthread_attr *attr = NULL;
|
const pthread_attr *attr = NULL;
|
||||||
struct pthread_data *pdata;
|
struct pthread_thread *thread;
|
||||||
|
thread_id threadID;
|
||||||
|
|
||||||
if (_thread == NULL)
|
if (_thread == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -48,39 +80,47 @@ pthread_create(pthread_t *_thread, const pthread_attr_t *_attr,
|
|||||||
attr = &pthread_attr_default;
|
attr = &pthread_attr_default;
|
||||||
else
|
else
|
||||||
attr = *_attr;
|
attr = *_attr;
|
||||||
|
|
||||||
pdata = malloc(sizeof(struct pthread_data));
|
|
||||||
if (!pdata)
|
|
||||||
return B_WOULD_BLOCK;
|
|
||||||
pdata->entry = (thread_entry)start_routine;
|
|
||||||
pdata->data = arg;
|
|
||||||
|
|
||||||
thread = spawn_thread(_pthread_thread_entry, "pthread func", attr->sched_priority, pdata);
|
thread = (struct pthread_thread *)malloc(sizeof(struct pthread_thread));
|
||||||
if (thread < B_OK)
|
if (thread == NULL)
|
||||||
|
return B_WOULD_BLOCK;
|
||||||
|
|
||||||
|
thread->entry = startRoutine;
|
||||||
|
thread->entry_argument = arg;
|
||||||
|
thread->cleanup_handlers = NULL;
|
||||||
|
|
||||||
|
if (sPthreadSlot == -1) {
|
||||||
|
// In a clean pthread environment, this is even thread-safe!
|
||||||
|
sPthreadSlot = tls_allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
threadID = spawn_thread(pthread_thread_entry, "pthread func",
|
||||||
|
attr->sched_priority, thread);
|
||||||
|
if (threadID < B_OK)
|
||||||
return B_WOULD_BLOCK;
|
return B_WOULD_BLOCK;
|
||||||
// stupid error code (EAGAIN) but demanded by POSIX
|
// stupid error code (EAGAIN) but demanded by POSIX
|
||||||
|
|
||||||
resume_thread(thread);
|
resume_thread(threadID);
|
||||||
*_thread = thread;
|
*_thread = threadID;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pthread_t
|
pthread_t
|
||||||
pthread_self()
|
pthread_self(void)
|
||||||
{
|
{
|
||||||
return find_thread(NULL);
|
return find_thread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_equal(pthread_t t1, pthread_t t2)
|
pthread_equal(pthread_t t1, pthread_t t2)
|
||||||
{
|
{
|
||||||
return (t1 > 0 && t2 > 0 && t1 == t2);
|
return t1 > 0 && t2 > 0 && t1 == t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_join(pthread_t thread, void **value_ptr)
|
pthread_join(pthread_t thread, void **value_ptr)
|
||||||
{
|
{
|
||||||
status_t error = wait_for_thread(thread, (status_t *)value_ptr);
|
status_t error = wait_for_thread(thread, (status_t *)value_ptr);
|
||||||
@@ -90,14 +130,14 @@ pthread_join(pthread_t thread, void **value_ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pthread_exit(void *value_ptr)
|
pthread_exit(void *value)
|
||||||
{
|
{
|
||||||
exit_thread((status_t)value_ptr);
|
exit_thread((status_t)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_kill(pthread_t thread, int sig)
|
pthread_kill(pthread_t thread, int sig)
|
||||||
{
|
{
|
||||||
status_t err = kill(thread, sig);
|
status_t err = kill(thread, sig);
|
||||||
@@ -107,7 +147,7 @@ pthread_kill(pthread_t thread, int sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_detach(pthread_t thread)
|
pthread_detach(pthread_t thread)
|
||||||
{
|
{
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "pthread_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
__pthread_cleanup_push_handler(__pthread_cleanup_handler* handler)
|
||||||
|
{
|
||||||
|
pthread_thread* thread = __get_pthread();
|
||||||
|
if (thread == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
handler->previous = thread->cleanup_handlers;
|
||||||
|
thread->cleanup_handlers = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__pthread_cleanup_handler*
|
||||||
|
__pthread_cleanup_pop_handler(void)
|
||||||
|
{
|
||||||
|
pthread_thread* thread = __get_pthread();
|
||||||
|
if (thread == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
__pthread_cleanup_handler* handler = thread->cleanup_handlers;
|
||||||
|
thread->cleanup_handlers = handler->previous;
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2006, Jérôme Duval. All rights reserved.
|
* Copyright 2006, Jérôme Duval. All rights reserved.
|
||||||
** Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <TLS.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "pthread_private.h"
|
#include "pthread_private.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <TLS.h>
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: use a better algorithm than a linked list!
|
||||||
struct key_link {
|
struct key_link {
|
||||||
struct key_link *next;
|
struct key_link *next;
|
||||||
pthread_key_t key;
|
pthread_key_t key;
|
||||||
@@ -20,7 +23,7 @@ static struct key_link *sKeyList = NULL;
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_pthread_key_call_destructors(void *param)
|
__pthread_key_call_destructors()
|
||||||
{
|
{
|
||||||
struct key_link *link = NULL;
|
struct key_link *link = NULL;
|
||||||
|
|
||||||
@@ -36,7 +39,7 @@ _pthread_key_call_destructors(void *param)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
|
pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
|
||||||
{
|
{
|
||||||
struct key_link *link;
|
struct key_link *link;
|
||||||
@@ -63,18 +66,18 @@ pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_key_delete(pthread_key_t key)
|
pthread_key_delete(pthread_key_t key)
|
||||||
{
|
{
|
||||||
struct key_link *link, *last = NULL;
|
struct key_link *link, *last = NULL;
|
||||||
pthread_mutex_lock(&sKeyLock);
|
pthread_mutex_lock(&sKeyLock);
|
||||||
|
|
||||||
//remove key/destructor from the list
|
// remove key/destructor from the list
|
||||||
for (link = sKeyList; link; link = link->next) {
|
for (link = sKeyList; link; link = link->next) {
|
||||||
if (link->key == key) {
|
if (link->key == key) {
|
||||||
if (last)
|
if (last)
|
||||||
last->next = link->next;
|
last->next = link->next;
|
||||||
else
|
else
|
||||||
sKeyList = link->next;
|
sKeyList = link->next;
|
||||||
free(link);
|
free(link);
|
||||||
pthread_mutex_unlock(&sKeyLock);
|
pthread_mutex_unlock(&sKeyLock);
|
||||||
@@ -95,7 +98,7 @@ pthread_getspecific(pthread_key_t key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pthread_setspecific(pthread_key_t key, const void *value)
|
pthread_setspecific(pthread_key_t key, const void *value)
|
||||||
{
|
{
|
||||||
// we don't check if the key is valid
|
// we don't check if the key is valid
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#ifndef _PTHREAD_PRIVATE_H_
|
/*
|
||||||
#define _PTHREAD_PRIVATE_H_
|
* Copyright 2003-2008, Axel Dörfler, [email protected].
|
||||||
/*
|
|
||||||
* Copyright 2003, Axel Dörfler, [email protected].
|
|
||||||
* Copyright 2007, Ryan Leavengood, [email protected].
|
* Copyright 2007, Ryan Leavengood, [email protected].
|
||||||
* All rights reserved. Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
#ifndef _PTHREAD_PRIVATE_H_
|
||||||
|
#define _PTHREAD_PRIVATE_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
@@ -44,6 +47,24 @@ typedef struct _pthread_attr {
|
|||||||
} pthread_attr;
|
} pthread_attr;
|
||||||
|
|
||||||
|
|
||||||
void _pthread_key_call_destructors(void *);
|
// This structure is used internally only, it has no public equivalent
|
||||||
|
struct pthread_thread {
|
||||||
|
void *(*entry)(void*);
|
||||||
|
void *entry_argument;
|
||||||
|
struct __pthread_cleanup_handler *cleanup_handlers;
|
||||||
|
// TODO: move pthread keys in here, too
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void __pthread_key_call_destructors(void);
|
||||||
|
struct pthread_thread *__get_pthread(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _PTHREAD_PRIVATE_H_ */
|
#endif /* _PTHREAD_PRIVATE_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user