* 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:
Axel Dörfler 2008-03-31 15:10:00 +00:00
parent f946336faa
commit a635399b07
6 changed files with 193 additions and 67 deletions

View File

@ -1,5 +1,6 @@
/* /*
** 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_
@ -71,6 +72,27 @@ enum pthread_process_shared {
//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
@ -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

View File

@ -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

View File

@ -1,45 +1,77 @@
/* /*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. 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;
} }
// #pragma mark - public API
int 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;
@ -49,26 +81,34 @@ pthread_create(pthread_t *_thread, const pthread_attr_t *_attr,
else else
attr = *_attr; attr = *_attr;
pdata = malloc(sizeof(struct pthread_data)); thread = (struct pthread_thread *)malloc(sizeof(struct pthread_thread));
if (!pdata) if (thread == NULL)
return B_WOULD_BLOCK; 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->entry = startRoutine;
if (thread < B_OK) 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);
} }
@ -77,7 +117,7 @@ pthread_self()
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
@ -91,9 +131,9 @@ 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);
} }

View File

@ -0,0 +1,34 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. 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;
}

View File

@ -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;

View File

@ -1,10 +1,13 @@
#ifndef _PTHREAD_PRIVATE_H_
#define _PTHREAD_PRIVATE_H_
/* /*
* Copyright 2003, Axel Dörfler, axeld@pinc-software.de. * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2007, Ryan Leavengood, leavengood@gmail.com. * Copyright 2007, Ryan Leavengood, leavengood@gmail.com.
* 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_ */