Loading...
--- Libc/Libc-763.13/pthreads/pthread.c
+++ Libc/Libc-498/pthreads/pthread.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
@@ -61,10 +61,8 @@
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
-#include <sys/mman.h>
#include <machine/vmparam.h>
#include <mach/vm_statistics.h>
-#include <mach/mach_init.h>
#define __APPLE_API_PRIVATE
#include <machine/cpu_capabilities.h>
#include <libkern/OSAtomic.h>
@@ -73,23 +71,19 @@
#endif
-extern int _pthread_setcancelstate_internal(int state, int *oldstate, int conforming);
-extern int __pthread_sigmask(int, const sigset_t *, sigset_t *);
-
#ifndef BUILDING_VARIANT /* [ */
__private_extern__ struct __pthread_list __pthread_head = TAILQ_HEAD_INITIALIZER(__pthread_head);
-
-int32_t workq_targetconc[WORKQ_NUM_PRIOQUEUE];
/* Per-thread kernel support */
extern void _pthread_set_self(pthread_t);
extern void mig_init(int);
static int _pthread_create_pthread_onstack(pthread_attr_t *attrs, void **stack, pthread_t *thread);
static kern_return_t _pthread_free_pthread_onstack(pthread_t t, int freestruct, int termthread);
-static void _pthread_struct_init(pthread_t t, const pthread_attr_t *attrs, void * stack, size_t stacksize, int kernalloc, int nozero);
+void _pthread_struct_init(pthread_t t, const pthread_attr_t *attrs, void * stack, size_t stacksize, int kernalloc, int nozero);
+static void _pthread_tsd_reinit(pthread_t t);
static int _new_pthread_create_suspended(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
@@ -134,7 +128,6 @@
/* Same implementation as LOCK, but without the __is_threaded check */
int _spin_tries = 0;
-extern kern_return_t syscall_thread_switch(mach_port_name_t, int, mach_msg_timeout_t);
__private_extern__ void _spin_lock_retry(pthread_lock_t *lock)
{
int tries = _spin_tries;
@@ -146,7 +139,7 @@
} while(!_spin_lock_try(lock));
}
-static mach_port_t thread_recycle_port = MACH_PORT_NULL;
+extern mach_port_t thread_recycle_port;
/* These are used to keep track of a semaphore pool shared by mutexes and condition
** variables.
@@ -164,29 +157,27 @@
static OSSpinLock __workqueue_list_lock = OS_SPINLOCK_INIT;
-static void _pthread_exit(pthread_t self, void *value_ptr) __dead2;
+static void _pthread_exit(pthread_t self, void *value_ptr);
+int _pthread_setcancelstate_internal(int state, int *oldstate, int conforming);
static void _pthread_setcancelstate_exit(pthread_t self, void *value_ptr, int conforming);
static pthread_attr_t _pthread_attr_default = {0};
static void _pthread_workq_init(pthread_workqueue_t wq, const pthread_workqueue_attr_t * attr);
+static int handle_removeitem(pthread_workqueue_t workq, pthread_workitem_t item);
static int kernel_workq_setup = 0;
static volatile int32_t kernel_workq_count = 0;
-static volatile unsigned int user_workq_count = 0; /* number of outstanding workqueues */
-static volatile unsigned int user_workitem_count = 0; /* number of outstanding workitems */
+static volatile unsigned int user_workq_count = 0;
#define KERNEL_WORKQ_ELEM_MAX 64 /* Max number of elements in the kerrel */
static int wqreadyprio = 0; /* current highest prio queue ready with items */
__private_extern__ struct __pthread_workitem_pool __pthread_workitem_pool_head = TAILQ_HEAD_INITIALIZER(__pthread_workitem_pool_head);
__private_extern__ struct __pthread_workqueue_pool __pthread_workqueue_pool_head = TAILQ_HEAD_INITIALIZER(__pthread_workqueue_pool_head);
-
-static struct _pthread_workitem * __workqueue_pool_ptr;
-static size_t __workqueue_pool_size = 0;
-static int __workqueue_nitems = 0;
struct _pthread_workqueue_head __pthread_workq0_head;
struct _pthread_workqueue_head __pthread_workq1_head;
struct _pthread_workqueue_head __pthread_workq2_head;
struct _pthread_workqueue_head __pthread_workq3_head;
-pthread_workqueue_head_t __pthread_wq_head_tbl[WORKQ_NUM_PRIOQUEUE] = {&__pthread_workq0_head, &__pthread_workq1_head, &__pthread_workq2_head, &__pthread_workq3_head};
+struct _pthread_workqueue_head __pthread_workq4_head;
+pthread_workqueue_head_t __pthread_wq_head_tbl[WQ_NUM_PRIO_QS] = {&__pthread_workq0_head, &__pthread_workq1_head, &__pthread_workq2_head, &__pthread_workq3_head, &__pthread_workq4_head};
static void workqueue_list_lock(void);
static void workqueue_list_unlock(void);
@@ -195,30 +186,20 @@
static int post_nextworkitem(pthread_workqueue_t workq);
static void _pthread_workq_return(pthread_t self);
static pthread_workqueue_attr_t _pthread_wq_attr_default = {0};
+void _pthread_wqthread(pthread_t self, mach_port_t kport, void * stackaddr, pthread_workitem_t item, int reuse);
extern void start_wqthread(pthread_t self, mach_port_t kport, void * stackaddr, pthread_workitem_t item, int reuse);
-extern void thread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, unsigned int flags);
+extern void thread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, int flags);
static pthread_workitem_t alloc_workitem(void);
static void free_workitem(pthread_workitem_t);
-static void grow_workitem(void);
static pthread_workqueue_t alloc_workqueue(void);
static void free_workqueue(pthread_workqueue_t);
static int _pthread_work_internal_init(void);
static void workqueue_exit(pthread_t self, pthread_workqueue_t workq, pthread_workitem_t item);
-void _pthread_fork_child_postinit();
-
-void pthread_workqueue_atfork_prepare(void);
-void pthread_workqueue_atfork_parent(void);
-void pthread_workqueue_atfork_child(void);
-
-extern void dispatch_atfork_prepare(void);
-extern void dispatch_atfork_parent(void);
-extern void dispatch_atfork_child(void);
-
-/* workq_kernreturn commands */
+
+/* workq_ops commands */
#define WQOPS_QUEUE_ADD 1
#define WQOPS_QUEUE_REMOVE 2
#define WQOPS_THREAD_RETURN 4
-#define WQOPS_THREAD_SETCONC 8
/*
* Flags filed passed to bsdthread_create and back in pthread_start
@@ -227,11 +208,7 @@
| flags(8) | policy(8) | importance(16) |
-----------------------------------------
*/
-__private_extern__
void _pthread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, unsigned int flags);
-
-__private_extern__
-void _pthread_wqthread(pthread_t self, mach_port_t kport, void * stackaddr, pthread_workitem_t item, int reuse);
#define PTHREAD_START_CUSTOM 0x01000000
#define PTHREAD_START_SETSCHED 0x02000000
@@ -240,27 +217,13 @@
#define PTHREAD_START_POLICY_MASK 0xff
#define PTHREAD_START_IMPORTANCE_MASK 0xffff
-static int pthread_setschedparam_internal(pthread_t, mach_port_t, int, const struct sched_param *);
-extern pthread_t __bsdthread_create(void *(*func)(void *), void * func_arg, void * stack, pthread_t thread, unsigned int flags);
-extern int __bsdthread_register(void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), void (*)(pthread_t, mach_port_t, void *, pthread_workitem_t, int), int,void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), int32_t *,__uint64_t);
+extern pthread_t __bsdthread_create(void (*func)(void *), void * func_arg, void * stack, pthread_t thread, unsigned int flags);
extern int __bsdthread_terminate(void * freeaddr, size_t freesize, mach_port_t kport, mach_port_t joinsem);
-extern __uint64_t __thread_selfid( void );
-extern int __pthread_canceled(int);
-extern void _pthread_keys_init(void);
-extern int __pthread_kill(mach_port_t, int);
-extern int __pthread_markcancel(int);
-extern int __workq_open(void);
-
-#define WORKQUEUE_OVERCOMMIT 0x10000
-
-extern int __workq_kernreturn(int, pthread_workitem_t, int, int);
#if defined(__ppc__) || defined(__ppc64__)
static const vm_address_t PTHREAD_STACK_HINT = 0xF0000000;
#elif defined(__i386__) || defined(__x86_64__)
static const vm_address_t PTHREAD_STACK_HINT = 0xB0000000;
-#elif defined(__arm__)
-static const vm_address_t PTHREAD_STACK_HINT = 0x30000000;
#else
#error Need to define a stack address hint for this architecture
#endif
@@ -373,11 +336,12 @@
kern_return_t res = 0;
vm_address_t freeaddr;
size_t freesize;
+ task_t self = mach_task_self();
int thread_count;
mach_port_t kport;
semaphore_t joinsem = SEMAPHORE_NULL;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x900001c, freestruct, termthread, 0, 0, 0);
#endif
kport = t->kernel_thread;
@@ -395,7 +359,7 @@
if (freestruct != 0) {
TAILQ_REMOVE(&__pthread_head, t, plist);
/* if parent has not returned from create yet keep pthread_t */
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x9000010, t, 0, 0, 1, 0);
#endif
if (t->parentcheck == 0)
@@ -405,16 +369,16 @@
thread_count = --_pthread_count;
UNLOCK(_pthread_list_lock);
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000020, freeaddr, freesize, kport, 1, 0);
#endif
if (thread_count <=0)
exit(0);
else
- __bsdthread_terminate((void *)freeaddr, freesize, kport, joinsem);
- LIBC_ABORT("thread %p didn't terminate", t);
+ __bsdthread_terminate(freeaddr, freesize, kport, joinsem);
+ abort();
} else {
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000024, freeaddr, freesize, 0, 1, 0);
#endif
res = vm_deallocate(mach_task_self(), freeaddr, freesize);
@@ -425,7 +389,7 @@
LOCK(_pthread_list_lock);
if (freestruct != 0) {
TAILQ_REMOVE(&__pthread_head, t, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x9000010, t, 0, 0, 2, 0);
#endif
}
@@ -434,7 +398,7 @@
UNLOCK(_pthread_list_lock);
if (freestruct) {
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000008, t, 0, 0, 2, 0);
#endif
free(t);
@@ -442,7 +406,7 @@
freeaddr = 0;
freesize = 0;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000020, 0, 0, kport, 2, 0);
#endif
@@ -450,10 +414,10 @@
exit(0);
else
__bsdthread_terminate(NULL, 0, kport, joinsem);
- LIBC_ABORT("thread %p didn't terminate", t);
+ abort();
} else if (freestruct) {
t->sig = _PTHREAD_NO_SIG;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000024, t, 0, 0, 2, 0);
#endif
free(t);
@@ -827,16 +791,13 @@
_pthread_body(pthread_t self)
{
_pthread_set_self(self);
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- if( (self->thread_id = __thread_selfid()) == (__uint64_t)-1)
- printf("Failed to set thread_id in _pthread_body\n");
-#endif
_pthread_exit(self, (self->fun)(self->arg));
}
void
_pthread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, unsigned int pflags)
{
+ int ret;
#if WQ_DEBUG
pthread_t pself;
#endif
@@ -844,11 +805,8 @@
char * stackaddr;
if ((pflags & PTHREAD_START_CUSTOM) == 0) {
- stackaddr = (char *)self;
+ stackaddr = self;
_pthread_struct_init(self, attrs, stackaddr, stacksize, 1, 1);
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- _pthread_set_self(self);
-#endif
LOCK(_pthread_list_lock);
if (pflags & PTHREAD_START_SETSCHED) {
self->policy = ((pflags >> PTHREAD_START_POLICY_BITSHIFT) & PTHREAD_START_POLICY_MASK);
@@ -859,12 +817,8 @@
self->detached &= ~PTHREAD_CREATE_JOINABLE;
self->detached |= PTHREAD_CREATE_DETACHED;
}
- } else {
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- _pthread_set_self(self);
-#endif
+ } else
LOCK(_pthread_list_lock);
- }
self->kernel_thread = kport;
self->fun = fun;
self->arg = funarg;
@@ -872,25 +826,23 @@
/* Add to the pthread list */
if (self->parentcheck == 0) {
TAILQ_INSERT_TAIL(&__pthread_head, self, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x900000c, self, 0, 0, 3, 0);
#endif
_pthread_count++;
}
self->childrun = 1;
UNLOCK(_pthread_list_lock);
-
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- if( (self->thread_id = __thread_selfid()) == (__uint64_t)-1)
- printf("Failed to set thread_id in pthread_start\n");
+#if defined(__i386__) || defined(__x86_64__)
+ _pthread_set_self(self);
#endif
#if WQ_DEBUG
pself = pthread_self();
if (self != pself)
- LIBC_ABORT("self %p != pself %p", self, pself);
-#endif
-#if PTH_TRACE
+ abort();
+#endif
+#if WQ_TRACE
__kdebug_trace(0x9000030, self, pflags, 0, 0, 0);
#endif
@@ -926,7 +878,7 @@
t->policy = attrs->policy;
t->param = attrs->param;
t->freeStackOnExit = attrs->freeStackOnExit;
- t->cancel_error = 0;
+ t->mutexes = (struct _pthread_mutex *)NULL;
t->sig = _PTHREAD_SIG;
t->reply_port = MACH_PORT_NULL;
t->cthread_self = NULL;
@@ -938,7 +890,7 @@
t->death = SEMAPHORE_NULL;
if (kernel_thread != MACH_PORT_NULL)
- (void)pthread_setschedparam_internal(t, kernel_thread, t->policy, &t->param);
+ pthread_setschedparam(t, t->policy, &t->param);
} while (0);
return (res);
}
@@ -946,7 +898,7 @@
void
_pthread_struct_init(pthread_t t, const pthread_attr_t *attrs, void * stack, size_t stacksize, int kernalloc, int nozero)
{
- mach_vm_offset_t stackaddr = (mach_vm_offset_t)(uintptr_t)stack;
+ mach_vm_offset_t stackaddr = (mach_vm_offset_t)stack;
if (nozero == 0) {
memset(t, 0, sizeof(*t));
@@ -956,13 +908,13 @@
t->schedset = attrs->schedset;
t->tsd[0] = t;
if (kernalloc != 0) {
- stackaddr = (mach_vm_offset_t)(uintptr_t)t;
+ stackaddr = (mach_vm_offset_t)t;
/* if allocated from kernel set values appropriately */
t->stacksize = stacksize;
- t->stackaddr = (void *)(uintptr_t)stackaddr;
+ t->stackaddr = stackaddr;
t->freeStackOnExit = 1;
- t->freeaddr = (void *)(uintptr_t)(stackaddr - stacksize - vm_page_size);
+ t->freeaddr = stackaddr - stacksize - vm_page_size;
t->freesize = pthreadsize + stacksize + vm_page_size;
} else {
t->stacksize = attrs->stacksize;
@@ -973,7 +925,7 @@
t->inherit = attrs->inherit;
t->policy = attrs->policy;
t->param = attrs->param;
- t->cancel_error = 0;
+ t->mutexes = (struct _pthread_mutex *)NULL;
t->sig = _PTHREAD_SIG;
t->reply_port = MACH_PORT_NULL;
t->cthread_self = NULL;
@@ -989,6 +941,13 @@
t->max_tsd_key = 0;
}
+static void
+_pthread_tsd_reinit(pthread_t t)
+{
+ bzero(&t->tsd[1], (_INTERNAL_POSIX_THREAD_KEYS_END-1) * sizeof(void *));
+}
+
+
/* Need to deprecate this in future */
int
_pthread_is_threaded(void)
@@ -1012,24 +971,9 @@
{
mach_port_t kport = MACH_PORT_NULL;
- if (t == NULL)
- goto out;
-
- /*
- * If the call is on self, return the kernel port. We cannot
- * add this bypass for main thread as it might have exited,
- * and we should not return stale port info.
- */
- if (t == pthread_self())
- {
- kport = t->kernel_thread;
- goto out;
- }
-
if (_pthread_lookup_thread(t, &kport, 0) != 0)
- return((mach_port_t)0);
-
-out:
+ return(NULL);
+
return(kport);
}
@@ -1056,23 +1000,14 @@
if (t == NULL)
return(ESRCH);
- if ( t == pthread_self() || t == &_thread ) //since the main thread will not get de-allocated from underneath us
- {
- size=t->stacksize;
- return size;
- }
-
-
LOCK(_pthread_list_lock);
if ((ret = _pthread_find_thread(t)) != 0) {
UNLOCK(_pthread_list_lock);
return(ret);
}
-
- size=t->stacksize;
+ size = t->stacksize;
UNLOCK(_pthread_list_lock);
-
return(size);
}
@@ -1083,16 +1018,13 @@
void * addr = NULL;
if (t == NULL)
- return((void *)(uintptr_t)ESRCH);
+ return(ESRCH);
- if(t == pthread_self() || t == &_thread) //since the main thread will not get deallocated from underneath us
- return t->stackaddr;
-
LOCK(_pthread_list_lock);
if ((ret = _pthread_find_thread(t)) != 0) {
UNLOCK(_pthread_list_lock);
- return((void *)(uintptr_t)ret);
+ return(ret);
}
addr = t->stackaddr;
UNLOCK(_pthread_list_lock);
@@ -1114,75 +1046,6 @@
pthread_t self = pthread_self();
return ((self->detached & _PTHREAD_CREATE_PARENT) == _PTHREAD_CREATE_PARENT);
-}
-
-
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
-/* if we are passed in a pthread_t that is NULL, then we return
- the current thread's thread_id. So folks don't have to call
- pthread_self, in addition to us doing it, if they just want
- their thread_id.
-*/
-int
-pthread_threadid_np(pthread_t thread, __uint64_t *thread_id)
-{
- int rval=0;
- pthread_t self = pthread_self();
-
- if (thread_id == NULL) {
- return(EINVAL);
- } else if (thread == NULL || thread == self) {
- *thread_id = self->thread_id;
- return rval;
- }
-
- LOCK(_pthread_list_lock);
- if ((rval = _pthread_find_thread(thread)) != 0) {
- UNLOCK(_pthread_list_lock);
- return(rval);
- }
- *thread_id = thread->thread_id;
- UNLOCK(_pthread_list_lock);
- return rval;
-}
-#endif
-
-int
-pthread_getname_np(pthread_t thread, char *threadname, size_t len)
-{
- int rval;
- rval = 0;
-
- if (thread == NULL)
- return(ESRCH);
-
- LOCK(_pthread_list_lock);
- if ((rval = _pthread_find_thread(thread)) != 0) {
- UNLOCK(_pthread_list_lock);
- return(rval);
- }
- strlcpy(threadname, thread->pthread_name, len);
- UNLOCK(_pthread_list_lock);
- return rval;
-}
-
-int
-pthread_setname_np(const char *threadname)
-{
- int rval;
- int len;
-
- rval = 0;
- len = strlen(threadname);
-
- /* protytype is in pthread_internals.h */
- rval = proc_setthreadname((void *)threadname, len);
- if(rval == 0)
- {
- strlcpy((pthread_self())->pthread_name, threadname, MAXTHREADNAMESIZE);
- }
- return rval;
-
}
static int
@@ -1196,7 +1059,7 @@
void *stack;
int error;
unsigned int flags;
- pthread_t t,t2;
+ pthread_t t;
kern_return_t kern_res;
mach_port_t kernel_thread = MACH_PORT_NULL;
int needresume;
@@ -1226,7 +1089,7 @@
/* Rosetta or pthread_create_suspended() */
/* running under rosetta */
/* Allocate a stack for the thread */
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000000, create_susp, 0, 0, 0, 0);
#endif
if ((error = _pthread_allocate_stack(attrs, &stack)) != 0) {
@@ -1257,7 +1120,7 @@
/* Now set it up to execute */
LOCK(_pthread_list_lock);
TAILQ_INSERT_TAIL(&__pthread_head, t, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x900000c, t, 0, 0, 4, 0);
#endif
_pthread_count++;
@@ -1292,31 +1155,27 @@
t->fun = start_routine;
t->newstyle = 1;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000004, t, flags, 0, 0, 0);
#endif
- if ((t2 = __bsdthread_create(start_routine, arg, stack, t, flags)) == (pthread_t)-1) {
+ if ((t = __bsdthread_create(start_routine, arg, stack, t, flags)) == -1) {
_pthread_free_pthread_onstack(t, 1, 0);
return (EAGAIN);
}
- else t=t2;
LOCK(_pthread_list_lock);
t->parentcheck = 1;
if ((t->childexit != 0) && ((t->detached & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED)) {
/* detached child exited, mop up */
UNLOCK(_pthread_list_lock);
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000008, t, 0, 0, 1, 0);
#endif
- if(t->freeStackOnExit)
- vm_deallocate(self, (mach_vm_address_t)(uintptr_t)t, pthreadsize);
- else
free(t);
} else if (t->childrun == 0) {
TAILQ_INSERT_TAIL(&__pthread_head, t, plist);
_pthread_count++;
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x900000c, t, 0, 0, 1, 0);
#endif
UNLOCK(_pthread_list_lock);
@@ -1325,17 +1184,17 @@
*thread = t;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000014, t, 0, 0, 1, 0);
#endif
return (0);
} else {
/* kernel allocation */
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000018, flags, 0, 0, 0, 0);
#endif
- if ((t = __bsdthread_create(start_routine, arg, (void *)attrs->stacksize, NULL, flags)) == (pthread_t)-1)
+ if ((t = __bsdthread_create(start_routine, arg, attrs->stacksize, NULL, flags)) == -1)
return (EAGAIN);
/* Now set it up to execute */
LOCK(_pthread_list_lock);
@@ -1343,14 +1202,14 @@
if ((t->childexit != 0) && ((t->detached & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED)) {
/* detached child exited, mop up */
UNLOCK(_pthread_list_lock);
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000008, t, pthreadsize, 0, 2, 0);
#endif
- vm_deallocate(self, (mach_vm_address_t)(uintptr_t)t, pthreadsize);
+ vm_deallocate(self, t, pthreadsize);
} else if (t->childrun == 0) {
TAILQ_INSERT_TAIL(&__pthread_head, t, plist);
_pthread_count++;
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x900000c, t, 0, 0, 2, 0);
#endif
UNLOCK(_pthread_list_lock);
@@ -1359,7 +1218,7 @@
*thread = t;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000014, t, 0, 0, 2, 0);
#endif
return(0);
@@ -1431,7 +1290,7 @@
/* Now set it up to execute */
LOCK(_pthread_list_lock);
TAILQ_INSERT_TAIL(&__pthread_head, t, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x900000c, t, 0, 0, 5, 0);
#endif
_pthread_count++;
@@ -1511,6 +1370,9 @@
/*
* pthread_kill call to system call
*/
+
+extern int __pthread_kill(mach_port_t, int);
+
int
pthread_kill (
pthread_t th,
@@ -1525,32 +1387,11 @@
if (_pthread_lookup_thread(th, &kport, 0) != 0)
return (ESRCH); /* Not a valid thread */
- /* if the thread is a workqueue thread, just return error */
- if ((th->wqthread != 0) && (th->wqkillset ==0)) {
- return(ENOTSUP);
- }
-
error = __pthread_kill(kport, sig);
if (error == -1)
error = errno;
return(error);
-}
-
-int
-__pthread_workqueue_setkill(int enable)
-{
- pthread_t self = pthread_self();
-
- LOCK(self->lock);
- if (enable == 0)
- self->wqkillset = 0;
- else
- self->wqkillset = 1;
- UNLOCK(self->lock);
-
- return(0);
-
}
/* Announce that there are pthread resources ready to be reclaimed in a */
@@ -1624,7 +1465,7 @@
*value_ptr = th->exit_value;
if (conforming) {
if ((th->cancel_state & (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING)) ==
- (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING) && (value_ptr != NULL))
+ (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING))
*value_ptr = PTHREAD_CANCELED;
th->sig = _PTHREAD_NO_SIG;
}
@@ -1649,20 +1490,12 @@
mach_port_t kernel_thread = msg.header.msgh_remote_port;
pthread_t thread = msg.thread;
- /* deal with race with thread_create_running() */
- if (kernel_thread == MACH_PORT_NULL &&
- kernel_thread != thread->kernel_thread) {
- kernel_thread = thread->kernel_thread;
- }
-
- if ( kernel_thread == MACH_PORT_NULL ||
- _pthread_reap_thread(thread, kernel_thread, (void **)0, 0) == EAGAIN)
+ if (_pthread_reap_thread(thread, kernel_thread, (void **)0, 0) == EAGAIN)
{
/* not dead yet, put it back for someone else to reap, stop here */
_pthread_become_available(thread, kernel_thread);
return;
}
-
ret = mach_msg(&msg.header, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0,
sizeof msg, thread_recycle_port,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
@@ -1692,7 +1525,7 @@
/* Make this thread not to receive any signals */
__disable_threadsignal(1);
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x900001c, self, newstyle, 0, 0, 0);
#endif
@@ -1731,7 +1564,7 @@
UNLOCK(self->lock);
LOCK(_pthread_list_lock);
TAILQ_REMOVE(&__pthread_head, self, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x9000010, self, 0, 0, 5, 0);
#endif
thread_count = --_pthread_count;
@@ -1750,14 +1583,14 @@
} else {
semaphore_t joinsem = SEMAPHORE_NULL;
- if ((self->joiner_notify == (mach_port_t)0) && (self->detached & PTHREAD_CREATE_JOINABLE))
+ if ((self->joiner_notify == NULL) && (self->detached & PTHREAD_CREATE_JOINABLE))
joinsem = new_sem_from_pool();
LOCK(self->lock);
self->detached |= _PTHREAD_EXITED;
self->exit_value = value_ptr;
if (self->detached & PTHREAD_CREATE_JOINABLE) {
- if (self->joiner_notify == (mach_port_t)0) {
+ if (self->joiner_notify == NULL) {
self->joiner_notify = joinsem;
joinsem = SEMAPHORE_NULL;
}
@@ -1773,19 +1606,17 @@
_pthread_free_pthread_onstack(self, 1, 1);
}
}
- LIBC_ABORT("thread %p didn't exit", self);
+ abort();
}
void
pthread_exit(void *value_ptr)
{
pthread_t self = pthread_self();
- /* if the current thread is a workqueue thread, just crash the app, as per libdispatch folks */
- if (self->wqthread == 0) {
+ if (self->wqthread != 0)
+ workqueue_exit(self, self->cur_workq, self->cur_workitem);
+ else
_pthread_exit(self, value_ptr);
- } else {
- LIBC_ABORT("pthread_exit() may only be called against threads created via pthread_create()");
- }
}
/*
@@ -1819,9 +1650,8 @@
/*
* Set the scheduling policy and scheduling paramters for a thread.
*/
-static int
-pthread_setschedparam_internal(pthread_t thread,
- mach_port_t kport,
+int
+pthread_setschedparam(pthread_t thread,
int policy,
const struct sched_param *param)
{
@@ -1852,46 +1682,12 @@
default:
return (EINVAL);
}
- ret = thread_policy(kport, policy, base, count, TRUE);
+ ret = thread_policy(pthread_mach_thread_np(thread), policy, base, count, TRUE);
if (ret != KERN_SUCCESS)
return (EINVAL);
+ thread->policy = policy;
+ thread->param = *param;
return (0);
-}
-
-int
-pthread_setschedparam(pthread_t t,
- int policy,
- const struct sched_param *param)
-{
- mach_port_t kport = MACH_PORT_NULL;
- int error;
- int bypass = 1;
-
- if (t != pthread_self() && t != &_thread ) { //since the main thread will not get de-allocated from underneath us
- bypass = 0;
- if (_pthread_lookup_thread(t, &kport, 0) != 0)
- return(ESRCH);
- } else
- kport = t->kernel_thread;
-
- error = pthread_setschedparam_internal(t, kport, policy, param);
- if (error == 0) {
- if (bypass == 0) {
- /* ensure the thread is still valid */
- LOCK(_pthread_list_lock);
- if ((error = _pthread_find_thread(t)) != 0) {
- UNLOCK(_pthread_list_lock);
- return(error);
- }
- t->policy = policy;
- t->param = *param;
- UNLOCK(_pthread_list_lock);
- } else {
- t->policy = policy;
- t->param = *param;
- }
- }
- return(error);
}
/*
@@ -1922,21 +1718,16 @@
return (t1 == t2);
}
-// Force LLVM not to optimise this to a call to __pthread_set_self, if it does
-// then _pthread_set_self won't be bound when secondary threads try and start up.
-void __attribute__((noinline))
+__private_extern__ void
_pthread_set_self(pthread_t p)
{
- extern void __pthread_set_self(void *);
-
+ extern void __pthread_set_self(pthread_t);
if (p == 0) {
- if (_thread.tsd[0] != 0) {
- bzero(&_thread, sizeof(struct _pthread));
- }
+ bzero(&_thread, sizeof(struct _pthread));
p = &_thread;
}
p->tsd[0] = p;
- __pthread_set_self(&p->tsd[0]);
+ __pthread_set_self(p);
}
void
@@ -1980,7 +1771,7 @@
_spin_lock(&once_control->lock);
if (once_control->sig == _PTHREAD_ONCE_SIG_init)
{
- pthread_cleanup_push((void (*)(void *))__pthread_once_cancel_handler, once_control);
+ pthread_cleanup_push(__pthread_once_cancel_handler, once_control);
(*init_routine)();
pthread_cleanup_pop(0);
once_control->sig = _PTHREAD_ONCE_SIG;
@@ -2028,7 +1819,8 @@
/*
* Perform package initialization - called automatically when application starts
*/
-int
+
+__private_extern__ int
pthread_init(void)
{
pthread_attr_t *attrs;
@@ -2040,7 +1832,6 @@
host_t host;
mach_msg_type_number_t count;
int mib[2];
- int ncpus = 0;
size_t len;
void *stackaddr;
@@ -2065,10 +1856,7 @@
thread = &_thread;
TAILQ_INSERT_HEAD(&__pthread_head, thread, plist);
_pthread_set_self(thread);
-#if PTH_LISTTRACE
- __kdebug_trace(0x900000c, thread, 0, 0, 10, 0);
-#endif
-
+
/* In case of dyld reset the tsd keys from 1 - 10 */
_pthread_keys_init();
@@ -2078,17 +1866,11 @@
if (sysctl (mib, 2, &stackaddr, &len, NULL, 0) != 0)
stackaddr = (void *)USRSTACK;
_pthread_create(thread, attrs, stackaddr, mach_thread_self());
- thread->stacksize = DFLSSIZ; //initialize main thread's stacksize based on vmparam.h
thread->detached = PTHREAD_CREATE_JOINABLE|_PTHREAD_CREATE_PARENT;
_init_cpu_capabilities();
- if ((ncpus = _NumCPUs()) > 1)
+ if (_NumCPUs() > 1)
_spin_tries = MP_SPIN_TRIES;
-
- workq_targetconc[WORKQ_HIGH_PRIOQUEUE] = ncpus;
- workq_targetconc[WORKQ_DEFAULT_PRIOQUEUE] = ncpus;
- workq_targetconc[WORKQ_LOW_PRIOQUEUE] = ncpus;
- workq_targetconc[WORKQ_BG_PRIOQUEUE] = ncpus;
mach_port_deallocate(mach_task_self(), host);
@@ -2096,6 +1878,9 @@
IF_ROSETTA() {
__oldstyle = 1;
}
+#endif
+#if defined(__arm__)
+ __oldstyle = 1;
#endif
#if defined(_OBJC_PAGE_BASE_ADDRESS)
@@ -2111,21 +1896,15 @@
/* We ignore the return result here. The ObjC runtime will just have to deal. */
}
#endif
- //added so that thread_recycle_port is initialized on new launch.
- _pthread_fork_child_postinit();
+
mig_init(1); /* enable multi-threaded mig interfaces */
if (__oldstyle == 0) {
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- __bsdthread_register(thread_start, start_wqthread, round_page(sizeof(struct _pthread)), _pthread_start, &workq_targetconc[0], (uintptr_t)(&thread->tsd[__PTK_LIBDISPATCH_KEY0]) - (uintptr_t)(&thread->tsd[0]));
+#if defined(__i386__) || defined(__x86_64__)
+ __bsdthread_register(thread_start, start_wqthread, round_page(sizeof(struct _pthread)));
#else
- __bsdthread_register(_pthread_start, _pthread_wqthread, round_page(sizeof(struct _pthread)), NULL, &workq_targetconc[0], (uintptr_t)&thread->tsd[__PTK_LIBDISPATCH_KEY0] - (uintptr_t)thread);
-#endif
- }
-
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- if( (thread->thread_id = __thread_selfid()) == (__uint64_t)-1)
- printf("Failed to set thread_id in pthread_init\n");
-#endif
+ __bsdthread_register(_pthread_start, _pthread_wqthread, round_page(sizeof(struct _pthread)));
+#endif
+ }
return 0;
}
@@ -2136,12 +1915,8 @@
}
/* This used to be the "magic" that gets the initialization routine called when the application starts */
-/*
- * (These has been moved to setenv.c, so we can use it to fix a less than 10.5
- * crt1.o issue)
- * static int _do_nothing(void) { return 0; }
- * int (*_cthread_init_routine)(void) = _do_nothing;
- */
+static int _do_nothing(void) { return 0; }
+int (*_cthread_init_routine)(void) = _do_nothing;
/* Get a semaphore from the pool, growing it if necessary */
@@ -2188,23 +1963,7 @@
TAILQ_INIT(&__pthread_head);
LOCK_INIT(_pthread_list_lock);
TAILQ_INSERT_HEAD(&__pthread_head, p, plist);
-#if PTH_LISTTRACE
- __kdebug_trace(0x900000c, p, 0, 0, 10, 0);
-#endif
_pthread_count = 1;
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- if( (p->thread_id = __thread_selfid()) == (__uint64_t)-1)
- printf("Failed to set thread_id in pthread_fork_child\n");
-#endif
-}
-
-void _pthread_fork_child_postinit() {
- kern_return_t kr;
-
- kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &thread_recycle_port);
- if (kr != KERN_SUCCESS) {
- abort();
- }
}
/*
@@ -2260,9 +2019,9 @@
_pthread_join_cleanup(pthread_t thread, void ** value_ptr, int conforming)
{
kern_return_t res;
- int ret;
-
-#if PTH_TRACE
+ int detached = 0, ret;
+
+#if WQ_TRACE
__kdebug_trace(0x9000028, thread, 0, 0, 1, 0);
#endif
/* The scenario where the joiner was waiting for the thread and
@@ -2285,7 +2044,7 @@
}
/* It is still a joinable thread and needs to be reaped */
TAILQ_REMOVE(&__pthread_head, thread, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x9000010, thread, 0, 0, 3, 0);
#endif
UNLOCK(_pthread_list_lock);
@@ -2294,7 +2053,7 @@
*value_ptr = thread->exit_value;
if (conforming) {
if ((thread->cancel_state & (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING)) ==
- (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING) && (value_ptr != NULL)) {
+ (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING)) {
*value_ptr = PTHREAD_CANCELED;
}
}
@@ -2306,13 +2065,13 @@
}
if (thread->freeStackOnExit) {
thread->sig = _PTHREAD_NO_SIG;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000028, thread, 0, 0, 2, 0);
#endif
- vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)thread, pthreadsize);
+ vm_deallocate(mach_task_self(), thread, pthreadsize);
} else {
thread->sig = _PTHREAD_NO_SIG;
-#if PTH_TRACE
+#if WQ_TRACE
__kdebug_trace(0x9000028, thread, 0, 0, 3, 0);
#endif
free(thread);
@@ -2371,16 +2130,19 @@
int
pthread_workqueue_attr_init_np(pthread_workqueue_attr_t * attrp)
{
- attrp->queueprio = WORKQ_DEFAULT_PRIOQUEUE;
- attrp->sig = PTHREAD_WORKQUEUE_ATTR_SIG;
- attrp->overcommit = 0;
+ attrp->stacksize = DEFAULT_STACK_SIZE;
+ attrp->istimeshare = 1;
+ attrp->importance = 0;
+ attrp->affinity = 0;
+ attrp->queueprio = WORK_QUEUE_NORMALIZER;
+ attrp->sig = PTHEAD_WRKQUEUE_ATTR_SIG;
return(0);
}
int
pthread_workqueue_attr_destroy_np(pthread_workqueue_attr_t * attr)
{
- if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG)
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG)
{
return (0);
} else
@@ -2389,46 +2151,23 @@
}
}
+#ifdef NOTYET /* [ */
int
-pthread_workqueue_attr_getqueuepriority_np(const pthread_workqueue_attr_t * attr, int * qpriop)
-{
- if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
- *qpriop = attr->queueprio;
+pthread_workqueue_attr_getstacksize_np(const pthread_workqueue_attr_t * attr, size_t * stacksizep)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) {
+ *stacksizep = attr->stacksize;
return (0);
} else {
return (EINVAL); /* Not an attribute structure! */
}
}
-
int
-pthread_workqueue_attr_setqueuepriority_np(pthread_workqueue_attr_t * attr, int qprio)
-{
-int error = 0;
-
- if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
- switch(qprio) {
- case WORKQ_HIGH_PRIOQUEUE:
- case WORKQ_DEFAULT_PRIOQUEUE:
- case WORKQ_LOW_PRIOQUEUE:
- case WORKQ_BG_PRIOQUEUE:
- attr->queueprio = qprio;
- break;
- default:
- error = EINVAL;
- }
- } else {
- error = EINVAL;
- }
- return (error);
-}
-
-
-int
-pthread_workqueue_attr_getovercommit_np(const pthread_workqueue_attr_t * attr, int * ocommp)
-{
- if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
- *ocommp = attr->overcommit;
+pthread_workqueue_attr_setstacksize_np(pthread_workqueue_attr_t * attr, size_t stacksize)
+{
+ if ((attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) && ((stacksize % vm_page_size) == 0) && (stacksize >= PTHREAD_STACK_MIN)) {
+ attr->stacksize = stacksize;
return (0);
} else {
return (EINVAL); /* Not an attribute structure! */
@@ -2437,17 +2176,99 @@
int
-pthread_workqueue_attr_setovercommit_np(pthread_workqueue_attr_t * attr, int ocomm)
-{
-int error = 0;
-
- if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
- attr->overcommit = ocomm;
+pthread_workqueue_attr_getthreadtimeshare_np(const pthread_workqueue_attr_t * attr, int * istimesahrep)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) {
+ *istimesahrep = attr->istimeshare;
+ return (0);
} else {
- error = EINVAL;
+ return (EINVAL); /* Not an attribute structure! */
}
- return (error);
-}
+}
+
+int
+pthread_workqueue_attr_settthreadtimeshare_np(pthread_workqueue_attr_t * attr, int istimeshare)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) {
+ if (istimeshare != 0)
+ attr->istimeshare = istimeshare;
+ else
+ attr->istimeshare = 0;
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
+int
+pthread_workqueue_attr_getthreadimportance_np(const pthread_workqueue_attr_t * attr, int * importancep)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) {
+ *importancep = attr->importance;
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
+int
+pthread_workqueue_attr_settthreadimportance_np(pthread_workqueue_attr_t * attr, int importance)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG){
+ attr->importance = importance;
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
+int
+pthread_workqueue_attr_getthreadaffinity_np(const pthread_workqueue_attr_t * attr, int * affinityp)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) {
+ *affinityp = attr->affinity;
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
+int
+pthread_workqueue_attr_settthreadaffinity_np(pthread_workqueue_attr_t * attr, int affinity)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG){
+ attr->affinity = affinity;
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
+#endif /* NOTYET ] */
+
+int
+pthread_workqueue_attr_getqueuepriority_np(const pthread_workqueue_attr_t * attr, int * qpriop)
+{
+ if (attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) {
+ *qpriop = (attr->queueprio - WORK_QUEUE_NORMALIZER);
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
+int
+pthread_workqueue_attr_setqueuepriority_np(pthread_workqueue_attr_t * attr, int qprio)
+{
+ /* only -2 to +2 is valid */
+ if ((attr->sig == PTHEAD_WRKQUEUE_ATTR_SIG) && (qprio <= 2) && (qprio >= -2)) {
+ attr->queueprio = (qprio + WORK_QUEUE_NORMALIZER);
+ return (0);
+ } else {
+ return (EINVAL); /* Not an attribute structure! */
+ }
+}
+
/* XXXXXXXXXXXXX Pthread Workqueue support routines XXXXXXXXXXXXXXXXXX */
static void
@@ -2474,105 +2295,40 @@
return(ret);
}
-int
-pthread_workqueue_requestconcurrency_np(int queue, int request_concurrency)
-{
- int error = 0;
-
- if (queue < 0 || queue > WORKQ_NUM_PRIOQUEUE)
- return(EINVAL);
-
- error =__workq_kernreturn(WQOPS_THREAD_SETCONC, NULL, request_concurrency, queue);
-
- if (error == -1)
- return(errno);
- return(0);
-}
-
-void
-pthread_workqueue_atfork_prepare(void)
-{
- /*
- * NOTE: Any workq additions here
- * should be for i386,x86_64 only
- */
- dispatch_atfork_prepare();
-}
-
-void
-pthread_workqueue_atfork_parent(void)
-{
- /*
- * NOTE: Any workq additions here
- * should be for i386,x86_64 only
- */
- dispatch_atfork_parent();
-}
-
-void
-pthread_workqueue_atfork_child(void)
-{
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- /*
- * NOTE: workq additions here
- * are for i386,x86_64 only as
- * ppc and arm do not support it
- */
- __workqueue_list_lock = OS_SPINLOCK_INIT;
- if (kernel_workq_setup != 0){
- kernel_workq_setup = 0;
- _pthread_work_internal_init();
- }
-#endif
- dispatch_atfork_child();
-}
-
static int
_pthread_work_internal_init(void)
{
int i, error;
pthread_workqueue_head_t headp;
+ pthread_workitem_t witemp;
pthread_workqueue_t wq;
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- pthread_t self = pthread_self();
-#endif
if (kernel_workq_setup == 0) {
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- __bsdthread_register(thread_start, start_wqthread, round_page(sizeof(struct _pthread)), _pthread_start, &workq_targetconc[0], (uintptr_t)(&self->tsd[__PTK_LIBDISPATCH_KEY0]) - (uintptr_t)(&self->tsd[0]));
+#if defined(__i386__) || defined(__x86_64__)
+ __bsdthread_register(thread_start, start_wqthread, round_page(sizeof(struct _pthread)));
#else
- __bsdthread_register(_pthread_start, _pthread_wqthread, round_page(sizeof(struct _pthread)),NULL,NULL,0);
-#endif
-
- _pthread_wq_attr_default.queueprio = WORKQ_DEFAULT_PRIOQUEUE;
- _pthread_wq_attr_default.sig = PTHREAD_WORKQUEUE_ATTR_SIG;
-
- for( i = 0; i< WORKQ_NUM_PRIOQUEUE; i++) {
+ __bsdthread_register(_pthread_start, _pthread_wqthread, round_page(sizeof(struct _pthread)));
+#endif
+
+ _pthread_wq_attr_default.stacksize = DEFAULT_STACK_SIZE;
+ _pthread_wq_attr_default.istimeshare = 1;
+ _pthread_wq_attr_default.importance = 0;
+ _pthread_wq_attr_default.affinity = 0;
+ _pthread_wq_attr_default.queueprio = WORK_QUEUE_NORMALIZER;
+ _pthread_wq_attr_default.sig = PTHEAD_WRKQUEUE_ATTR_SIG;
+
+ for( i = 0; i< WQ_NUM_PRIO_QS; i++) {
headp = __pthread_wq_head_tbl[i];
TAILQ_INIT(&headp->wqhead);
headp->next_workq = 0;
}
- __workqueue_pool_ptr = NULL;
- __workqueue_pool_size = round_page(sizeof(struct _pthread_workitem) * WORKITEM_POOL_SIZE);
-
- __workqueue_pool_ptr = (struct _pthread_workitem *)mmap(NULL, __workqueue_pool_size,
- PROT_READ|PROT_WRITE,
- MAP_ANON | MAP_PRIVATE,
- 0,
- 0);
-
- if (__workqueue_pool_ptr == MAP_FAILED) {
- /* Not expected to fail, if it does, always malloc for work items */
- __workqueue_nitems = WORKITEM_POOL_SIZE;
- __workqueue_pool_ptr = NULL;
- } else
- __workqueue_nitems = 0;
-
- /* sets up the workitem pool */
- grow_workitem();
-
- /* since the size is less than a page, leaving this in malloc pool */
+ /* create work item and workqueue pools */
+ witemp = (struct _pthread_workitem *)malloc(sizeof(struct _pthread_workitem) * WORKITEM_POOL_SIZE);
+ bzero(witemp, (sizeof(struct _pthread_workitem) * WORKITEM_POOL_SIZE));
+ for (i = 0; i < WORKITEM_POOL_SIZE; i++) {
+ TAILQ_INSERT_TAIL(&__pthread_workitem_pool_head, &witemp[i], item_entry);
+ }
wq = (struct _pthread_workqueue *)malloc(sizeof(struct _pthread_workqueue) * WORKQUEUE_POOL_SIZE);
bzero(wq, (sizeof(struct _pthread_workqueue) * WORKQUEUE_POOL_SIZE));
for (i = 0; i < WORKQUEUE_POOL_SIZE; i++) {
@@ -2582,9 +2338,7 @@
if (error = __workq_open()) {
TAILQ_INIT(&__pthread_workitem_pool_head);
TAILQ_INIT(&__pthread_workqueue_pool_head);
- if (__workqueue_pool_ptr != NULL) {
- munmap((void *)__workqueue_pool_ptr, __workqueue_pool_size);
- }
+ free(witemp);
free(wq);
return(ENOMEM);
}
@@ -2601,25 +2355,13 @@
pthread_workitem_t witem;
if (TAILQ_EMPTY(&__pthread_workitem_pool_head)) {
- /* the chunk size is set so some multiple of it is pool size */
- if (__workqueue_nitems < WORKITEM_POOL_SIZE) {
- grow_workitem();
- } else {
- workqueue_list_unlock();
- witem = malloc(sizeof(struct _pthread_workitem));
- workqueue_list_lock();
- witem->fromcache = 0;
- goto out;
- }
- }
- witem = TAILQ_FIRST(&__pthread_workitem_pool_head);
- TAILQ_REMOVE(&__pthread_workitem_pool_head, witem, item_entry);
- witem->fromcache = 1;
-out:
- witem->flags = 0;
- witem->item_entry.tqe_next = 0;
- witem->item_entry.tqe_prev = 0;
- user_workitem_count++;
+ workqueue_list_unlock();
+ witem = malloc(sizeof(struct _pthread_workitem));
+ workqueue_list_lock();
+ } else {
+ witem = TAILQ_FIRST(&__pthread_workitem_pool_head);
+ TAILQ_REMOVE(&__pthread_workitem_pool_head, witem, item_entry);
+ }
return(witem);
}
@@ -2627,27 +2369,7 @@
static void
free_workitem(pthread_workitem_t witem)
{
- user_workitem_count--;
- witem->flags = 0;
- if (witem->fromcache != 0)
- TAILQ_INSERT_TAIL(&__pthread_workitem_pool_head, witem, item_entry);
- else
- free(witem);
-}
-
-static void
-grow_workitem(void)
-{
- pthread_workitem_t witemp;
- int i;
-
- witemp = &__workqueue_pool_ptr[__workqueue_nitems];
- bzero(witemp, (sizeof(struct _pthread_workitem) * WORKITEM_CHUNK_SIZE));
- for (i = 0; i < WORKITEM_CHUNK_SIZE; i++) {
- witemp[i].fromcache = 1;
- TAILQ_INSERT_TAIL(&__pthread_workitem_pool_head, &witemp[i], item_entry);
- }
- __workqueue_nitems += WORKITEM_CHUNK_SIZE;
+ TAILQ_INSERT_TAIL(&__pthread_workitem_pool_head, witem, item_entry);
}
/* This routine is called with list lock held */
@@ -2681,29 +2403,32 @@
{
bzero(wq, sizeof(struct _pthread_workqueue));
if (attr != NULL) {
+ wq->stacksize = attr->stacksize;
+ wq->istimeshare = attr->istimeshare;
+ wq->importance = attr->importance;
+ wq->affinity = attr->affinity;
wq->queueprio = attr->queueprio;
- wq->overcommit = attr->overcommit;
} else {
- wq->queueprio = WORKQ_DEFAULT_PRIOQUEUE;
- wq->overcommit = 0;
+ wq->stacksize = DEFAULT_STACK_SIZE;
+ wq->istimeshare = 1;
+ wq->importance = 0;
+ wq->affinity = 0;
+ wq->queueprio = WORK_QUEUE_NORMALIZER;
}
LOCK_INIT(wq->lock);
wq->flags = 0;
TAILQ_INIT(&wq->item_listhead);
TAILQ_INIT(&wq->item_kernhead);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080ac, wq, &wq->item_listhead, wq->item_listhead.tqh_first, wq->item_listhead.tqh_last, 0);
-#endif
wq->wq_list.tqe_next = 0;
wq->wq_list.tqe_prev = 0;
- wq->sig = PTHREAD_WORKQUEUE_SIG;
+ wq->sig = PTHEAD_WRKQUEUE_SIG;
wq->headp = __pthread_wq_head_tbl[wq->queueprio];
}
int
valid_workq(pthread_workqueue_t workq)
{
- if (workq->sig == PTHREAD_WORKQUEUE_SIG)
+ if (workq->sig == PTHEAD_WRKQUEUE_SIG)
return(1);
else
return(0);
@@ -2719,13 +2444,10 @@
pthread_workqueue_t workq;
pthread_workqueue_t nworkq = NULL;
-#if WQ_TRACE
- __kdebug_trace(0x9008098, kernel_workq_count, 0, 0, 0, 0);
-#endif
loop:
while (kernel_workq_count < KERNEL_WORKQ_ELEM_MAX) {
found = 0;
- for (i = 0; i < WORKQ_NUM_PRIOQUEUE; i++) {
+ for (i = 0; i < WQ_NUM_PRIO_QS; i++) {
wqreadyprio = i; /* because there is nothing else higher to run */
headp = __pthread_wq_head_tbl[i];
@@ -2740,9 +2462,6 @@
headp->next_workq = TAILQ_NEXT(workq, wq_list);
if (headp->next_workq == NULL)
headp->next_workq = TAILQ_FIRST(&headp->wqhead);
-#if WQ_TRACE
- __kdebug_trace(0x9008098, kernel_workq_count, workq, 0, 1, 0);
-#endif
val = post_nextworkitem(workq);
if (val != 0) {
@@ -2785,7 +2504,7 @@
static int
post_nextworkitem(pthread_workqueue_t workq)
{
- int error, prio;
+ int error;
pthread_workitem_t witem;
pthread_workqueue_head_t headp;
void (*func)(pthread_workqueue_t, void *);
@@ -2793,24 +2512,12 @@
if ((workq->flags & PTHREAD_WORKQ_SUSPEND) == PTHREAD_WORKQ_SUSPEND) {
return(0);
}
-#if WQ_TRACE
- __kdebug_trace(0x900809c, workq, workq->item_listhead.tqh_first, 0, 1, 0);
-#endif
if (TAILQ_EMPTY(&workq->item_listhead)) {
return(0);
}
- if ((workq->flags & PTHREAD_WORKQ_BARRIER_ON) == PTHREAD_WORKQ_BARRIER_ON)
- return(0);
-
witem = TAILQ_FIRST(&workq->item_listhead);
headp = workq->headp;
-#if WQ_TRACE
- __kdebug_trace(0x900809c, workq, witem, 0, 0xee, 0);
-#endif
if ((witem->flags & PTH_WQITEM_BARRIER) == PTH_WQITEM_BARRIER) {
-#if WQ_TRACE
- __kdebug_trace(0x9000064, workq, 0, 0, 2, 0);
-#endif
if ((witem->flags & PTH_WQITEM_APPLIED) != 0) {
return(0);
@@ -2830,26 +2537,14 @@
__kdebug_trace(0x9000064, 2, workq->barrier_count, 0, 0, 0);
#endif
if (witem->func != NULL) {
- /* since we are going to drop list lock */
- witem->flags |= PTH_WQITEM_APPLIED;
- workq->flags |= PTHREAD_WORKQ_BARRIER_ON;
workqueue_list_unlock();
- func = (void (*)(pthread_workqueue_t, void *))witem->func;
+ func = witem->func;
(*func)(workq, witem->func_arg);
-#if WQ_TRACE
- __kdebug_trace(0x9000064, 3, workq->barrier_count, 0, 0, 0);
-#endif
workqueue_list_lock();
- workq->flags &= ~PTHREAD_WORKQ_BARRIER_ON;
}
TAILQ_REMOVE(&workq->item_listhead, witem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080a8, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
+ witem->flags = 0;
free_workitem(witem);
-#if WQ_TRACE
- __kdebug_trace(0x9000064, 4, workq->barrier_count, 0, 0, 0);
-#endif
return(1);
}
} else if ((witem->flags & PTH_WQITEM_DESTROY) == PTH_WQITEM_DESTROY) {
@@ -2862,18 +2557,16 @@
witem->flags |= PTH_WQITEM_APPLIED;
workq->flags |= (PTHREAD_WORKQ_BARRIER_ON | PTHREAD_WORKQ_TERM_ON);
workq->barrier_count = workq->kq_count;
- workq->term_callback = (void (*)(struct _pthread_workqueue *,void *))witem->func;
+ workq->term_callback = witem->func;
workq->term_callarg = witem->func_arg;
TAILQ_REMOVE(&workq->item_listhead, witem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080a8, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
if ((TAILQ_EMPTY(&workq->item_listhead)) && (workq->kq_count == 0)) {
if (!(TAILQ_EMPTY(&workq->item_kernhead))) {
#if WQ_TRACE
__kdebug_trace(0x900006c, workq, workq->kq_count, 0, 0xff, 0);
#endif
}
+ witem->flags = 0;
free_workitem(witem);
workq->flags |= PTHREAD_WORKQ_DESTROYED;
#if WQ_TRACE
@@ -2897,12 +2590,8 @@
}
free_workqueue(workq);
return(1);
- } else {
+ } else
TAILQ_INSERT_HEAD(&workq->item_listhead, witem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080b0, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
- }
#if WQ_TRACE
__kdebug_trace(0x9000068, 2, workq->barrier_count, 0, 0, 0);
#endif
@@ -2912,9 +2601,6 @@
__kdebug_trace(0x9000060, witem, workq, witem->func_arg, 0xfff, 0);
#endif
TAILQ_REMOVE(&workq->item_listhead, witem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080a8, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
TAILQ_INSERT_TAIL(&workq->item_kernhead, witem, item_entry);
if ((witem->flags & PTH_WQITEM_KERN_COUNT) == 0) {
workq->kq_count++;
@@ -2922,13 +2608,7 @@
}
OSAtomicIncrement32(&kernel_workq_count);
workqueue_list_unlock();
-
- prio = workq->queueprio;
- if (workq->overcommit != 0) {
- prio |= WORKQUEUE_OVERCOMMIT;
- }
-
- if (( error =__workq_kernreturn(WQOPS_QUEUE_ADD, witem, workq->affinity, prio)) == -1) {
+ if (( error =__workq_ops(WQOPS_QUEUE_ADD, witem, 0)) == -1) {
OSAtomicDecrement32(&kernel_workq_count);
workqueue_list_lock();
#if WQ_TRACE
@@ -2936,9 +2616,6 @@
#endif
TAILQ_REMOVE(&workq->item_kernhead, witem, item_entry);
TAILQ_INSERT_HEAD(&workq->item_listhead, witem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080b0, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
if ((workq->flags & (PTHREAD_WORKQ_BARRIER_ON | PTHREAD_WORKQ_TERM_ON)) != 0)
workq->flags |= PTHREAD_WORKQ_REQUEUED;
} else
@@ -2951,7 +2628,7 @@
/* noone should come here */
#if 1
printf("error in logic for next workitem\n");
- LIBC_ABORT("error in logic for next workitem");
+ abort();
#endif
return(0);
}
@@ -2962,9 +2639,7 @@
int ret;
pthread_attr_t *attrs = &_pthread_attr_default;
pthread_workqueue_t workq;
-#if WQ_DEBUG
pthread_t pself;
-#endif
workq = item->workq;
@@ -2972,45 +2647,37 @@
/* reuse is set to 0, when a thread is newly created to run a workitem */
_pthread_struct_init(self, attrs, stackaddr, DEFAULT_STACK_SIZE, 1, 1);
self->wqthread = 1;
- self->wqkillset = 0;
self->parentcheck = 1;
/* These are not joinable threads */
self->detached &= ~PTHREAD_CREATE_JOINABLE;
self->detached |= PTHREAD_CREATE_DETACHED;
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#if defined(__i386__) || defined(__x86_64__)
_pthread_set_self(self);
#endif
#if WQ_TRACE
__kdebug_trace(0x9000050, self, item, item->func_arg, 0, 0);
#endif
self->kernel_thread = kport;
- self->fun = (void *(*)(void *))item->func;
+ self->fun = item->func;
self->arg = item->func_arg;
/* Add to the pthread list */
LOCK(_pthread_list_lock);
TAILQ_INSERT_TAIL(&__pthread_head, self, plist);
-#if PTH_LISTTRACE
+#if WQ_TRACE
__kdebug_trace(0x900000c, self, 0, 0, 10, 0);
#endif
_pthread_count++;
UNLOCK(_pthread_list_lock);
-
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
- if( (self->thread_id = __thread_selfid()) == (__uint64_t)-1)
- printf("Failed to set thread_id in pthread_wqthread\n");
-#endif
-
} else {
/* reuse is set to 1, when a thread is resued to run another work item */
#if WQ_TRACE
__kdebug_trace(0x9000054, self, item, item->func_arg, 0, 0);
#endif
/* reset all tsd from 1 to KEYS_MAX */
- if (self == NULL)
- LIBC_ABORT("_pthread_wqthread: pthread %p setup to be NULL", self);
-
- self->fun = (void *(*)(void *))item->func;
+ _pthread_tsd_reinit(self);
+
+ self->fun = item->func;
self->arg = item->func_arg;
}
@@ -3032,7 +2699,7 @@
pself = pthread_self();
if (self != pself) {
printf("(3)pthread_self not set in reuse: pself %p, passed in %p\n", pself, self);
- LIBC_ABORT("(3)pthread_self not set in reuse: pself %p, passed in %p", pself, self);
+ abort();
}
}
#endif /* WQ_DEBUG */
@@ -3041,15 +2708,8 @@
self->cur_workitem = item;
OSAtomicDecrement32(&kernel_workq_count);
- ret = (int)(intptr_t)(*self->fun)(self->arg);
-
- /* If we reach here without going through the above initialization path then don't go through
- * with the teardown code path ( e.g. setjmp/longjmp ). Instead just exit this thread.
- */
- if(self != pthread_self()) {
- pthread_exit(PTHREAD_CANCELED);
- }
-
+ ret = (*self->fun)(self->arg);
+
workqueue_exit(self, workq, item);
}
@@ -3057,6 +2717,7 @@
static void
workqueue_exit(pthread_t self, pthread_workqueue_t workq, pthread_workitem_t item)
{
+ pthread_attr_t *attrs = &_pthread_attr_default;
pthread_workitem_t baritem;
pthread_workqueue_head_t headp;
void (*func)(pthread_workqueue_t, void *);
@@ -3068,6 +2729,7 @@
#if WQ_TRACE
__kdebug_trace(0x9000070, self, 1, item->func_arg, workq->kq_count, 0);
#endif
+ item->flags = 0;
free_workitem(item);
if ((workq->flags & PTHREAD_WORKQ_BARRIER_ON) == PTHREAD_WORKQ_BARRIER_ON) {
@@ -3085,14 +2747,12 @@
/* if the front item is a barrier and call back is registered, run that */
if (((baritem->flags & PTH_WQITEM_BARRIER) == PTH_WQITEM_BARRIER) && (baritem->func != NULL)) {
workqueue_list_unlock();
- func = (void (*)(pthread_workqueue_t, void *))baritem->func;
+ func = baritem->func;
(*func)(workq, baritem->func_arg);
workqueue_list_lock();
}
TAILQ_REMOVE(&workq->item_listhead, baritem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080a8, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
+ baritem->flags = 0;
free_workitem(baritem);
workq->flags &= ~PTHREAD_WORKQ_BARRIER_ON;
#if WQ_TRACE
@@ -3141,13 +2801,100 @@
static void
_pthread_workq_return(pthread_t self)
{
- __workq_kernreturn(WQOPS_THREAD_RETURN, NULL, 0, 0);
+ struct __darwin_pthread_handler_rec *handler;
+ int value = 0;
+ int * value_ptr=&value;
+
+ /* set cancel state to disable and type to deferred */
+ _pthread_setcancelstate_exit(self, value_ptr, __unix_conforming);
+
+ /* Make this thread not to receive any signals */
+ __disable_threadsignal(1);
+
+ while ((handler = self->__cleanup_stack) != 0)
+ {
+ (handler->__routine)(handler->__arg);
+ self->__cleanup_stack = handler->__next;
+ }
+ _pthread_tsd_cleanup(self);
+
+ __workq_ops(WQOPS_THREAD_RETURN, NULL, 0);
/* This is the way to terminate the thread */
_pthread_exit(self, NULL);
}
+/* returns 0 if it handles it, otherwise 1 */
+static int
+handle_removeitem(pthread_workqueue_t workq, pthread_workitem_t item)
+{
+ pthread_workitem_t baritem;
+ pthread_workqueue_head_t headp;
+ void (*func)(pthread_workqueue_t, void *);
+
+ if ((workq->flags & PTHREAD_WORKQ_BARRIER_ON) == PTHREAD_WORKQ_BARRIER_ON) {
+ workq->barrier_count--;
+ if (workq->barrier_count <= 0 ) {
+ /* Need to remove barrier item from the list */
+ baritem = TAILQ_FIRST(&workq->item_listhead);
+#if WQ_DEBUG
+ if ((baritem->flags & (PTH_WQITEM_BARRIER | PTH_WQITEM_DESTROY| PTH_WQITEM_APPLIED)) == 0)
+ printf("Incorect bar item being removed in barrier processing\n");
+#endif /* WQ_DEBUG */
+ /* if the front item is a barrier and call back is registered, run that */
+ if (((baritem->flags & PTH_WQITEM_BARRIER) == PTH_WQITEM_BARRIER)
+ && (baritem->func != NULL)) {
+ workqueue_list_unlock();
+ func = baritem->func;
+ (*func)(workq, baritem->func_arg);
+ workqueue_list_lock();
+ }
+ TAILQ_REMOVE(&workq->item_listhead, baritem, item_entry);
+ baritem->flags = 0;
+ free_workitem(baritem);
+ item->flags = 0;
+ free_workitem(item);
+ workq->flags &= ~PTHREAD_WORKQ_BARRIER_ON;
+#if WQ_TRACE
+ __kdebug_trace(0x9000058, pthread_self(), item, item->func_arg, 0, 0);
+#endif
+ if ((workq->flags & PTHREAD_WORKQ_TERM_ON) != 0) {
+ headp = __pthread_wq_head_tbl[workq->queueprio];
+ workq->flags |= PTHREAD_WORKQ_DESTROYED;
+#if WQ_TRACE
+ __kdebug_trace(0x900006c, workq, workq->kq_count, 0, 2, 0);
+#endif
+ if (headp->next_workq == workq) {
+ headp->next_workq = TAILQ_NEXT(workq, wq_list);
+ if (headp->next_workq == NULL) {
+ headp->next_workq = TAILQ_FIRST(&headp->wqhead);
+ if (headp->next_workq == workq)
+ headp->next_workq = NULL;
+ }
+ }
+ TAILQ_REMOVE(&headp->wqhead, workq, wq_list);
+ workq->sig = 0;
+ if (workq->term_callback != NULL) {
+ workqueue_list_unlock();
+ (*workq->term_callback)(workq, workq->term_callarg);
+ workqueue_list_lock();
+ }
+ free_workqueue(workq);
+ pick_nextworkqueue_droplock();
+ return(0);
+ } else {
+ /* if there are higher prio schedulabel item reset to wqreadyprio */
+ if ((workq->queueprio < wqreadyprio) && (!(TAILQ_EMPTY(&workq->item_listhead))))
+ wqreadyprio = workq->queueprio;
+ free_workitem(item);
+ pick_nextworkqueue_droplock();
+ return(0);
+ }
+ }
+ }
+ return(1);
+}
/* XXXXXXXXXXXXX Pthread Workqueue functions XXXXXXXXXXXXXXXXXX */
int
@@ -3156,12 +2903,7 @@
pthread_workqueue_t wq;
pthread_workqueue_head_t headp;
-#if defined(__ppc__)
- IF_ROSETTA() {
- return(ENOTSUP);
- }
-#endif
- if ((attr != NULL) && (attr->sig != PTHREAD_WORKQUEUE_ATTR_SIG)) {
+ if ((attr != NULL) && (attr->sig != PTHEAD_WRKQUEUE_ATTR_SIG)) {
return(EINVAL);
}
@@ -3195,7 +2937,72 @@
}
int
-pthread_workqueue_additem_np(pthread_workqueue_t workq, void ( *workitem_func)(void *), void * workitem_arg, pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp)
+pthread_workqueue_destroy_np(pthread_workqueue_t workq, void (* callback_func)(pthread_workqueue_t, void *), void * callback_arg)
+{
+ pthread_workitem_t witem;
+ pthread_workqueue_head_t headp;
+
+ if (valid_workq(workq) == 0) {
+ return(EINVAL);
+ }
+
+ workqueue_list_lock();
+
+ /*
+ * Allocate the workitem here as it can drop the lock.
+ * Also we can evaluate the workqueue state only once.
+ */
+ witem = alloc_workitem();
+ witem->item_entry.tqe_next = 0;
+ witem->item_entry.tqe_prev = 0;
+ witem->func = callback_func;
+ witem->func_arg = callback_arg;
+ witem->flags = PTH_WQITEM_DESTROY;
+
+ if ((workq->flags & (PTHREAD_WORKQ_IN_TERMINATE | PTHREAD_WORKQ_TERM_ON | PTHREAD_WORKQ_DESTROYED)) == 0) {
+ workq->flags |= PTHREAD_WORKQ_IN_TERMINATE;
+ /* If nothing queued or running, destroy now */
+ if ((TAILQ_EMPTY(&workq->item_listhead)) && (TAILQ_EMPTY(&workq->item_kernhead))) {
+ workq->flags |= (PTHREAD_WORKQ_TERM_ON | PTHREAD_WORKQ_DESTROYED);
+ headp = __pthread_wq_head_tbl[workq->queueprio];
+ workq->term_callback = callback_func;
+ workq->term_callarg = callback_arg;
+ if (headp->next_workq == workq) {
+ headp->next_workq = TAILQ_NEXT(workq, wq_list);
+ if (headp->next_workq == NULL) {
+ headp->next_workq = TAILQ_FIRST(&headp->wqhead);
+ if (headp->next_workq == workq)
+ headp->next_workq = NULL;
+ }
+ }
+ TAILQ_REMOVE(&headp->wqhead, workq, wq_list);
+ workq->sig = 0;
+ free_workitem(witem);
+ if (workq->term_callback != NULL) {
+ workqueue_list_unlock();
+ (*workq->term_callback)(workq, workq->term_callarg);
+ workqueue_list_lock();
+ }
+#if WQ_TRACE
+ __kdebug_trace(0x900006c, workq, workq->kq_count, 0, 3, 0);
+#endif
+ free_workqueue(workq);
+ workqueue_list_unlock();
+ return(0);
+ }
+ TAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
+ } else {
+ free_workitem(witem);
+ workqueue_list_unlock();
+ return(EINPROGRESS);
+ }
+ workqueue_list_unlock();
+ return(0);
+}
+
+
+int
+pthread_workqueue_additem_np(pthread_workqueue_t workq, void ( *workitem_func)(void *), void * workitem_arg, pthread_workitem_handle_t * itemhandlep)
{
pthread_workitem_t witem;
@@ -3212,7 +3019,10 @@
witem = alloc_workitem();
witem->func = workitem_func;
witem->func_arg = workitem_arg;
+ witem->flags = 0;
witem->workq = workq;
+ witem->item_entry.tqe_next = 0;
+ witem->item_entry.tqe_prev = 0;
/* alloc workitem can drop the lock, check the state */
if ((workq->flags & (PTHREAD_WORKQ_IN_TERMINATE | PTHREAD_WORKQ_DESTROYED)) != 0) {
@@ -3224,16 +3034,7 @@
if (itemhandlep != NULL)
*itemhandlep = (pthread_workitem_handle_t *)witem;
- if (gencountp != NULL)
- *gencountp = 0;
-#if WQ_TRACE
- __kdebug_trace(0x9008090, witem, witem->func, witem->func_arg, workq, 0);
-#endif
TAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
-#if WQ_LISTTRACE
- __kdebug_trace(0x90080a4, workq, &workq->item_listhead, workq->item_listhead.tqh_first, workq->item_listhead.tqh_last, 0);
-#endif
-
if (((workq->flags & PTHREAD_WORKQ_BARRIER_ON) == 0) && (workq->queueprio < wqreadyprio))
wqreadyprio = workq->queueprio;
@@ -3242,18 +3043,154 @@
return(0);
}
-int
-pthread_workqueue_getovercommit_np(pthread_workqueue_t workq, unsigned int *ocommp)
-{
- if (valid_workq(workq) == 0) {
- return(EINVAL);
- }
-
- if (ocommp != NULL)
- *ocommp = workq->overcommit;
+int
+pthread_workqueue_removeitem_np(pthread_workqueue_t workq, pthread_workitem_handle_t itemhandle)
+{
+ pthread_workitem_t item, baritem;
+ pthread_workqueue_head_t headp;
+ int error;
+
+ if (valid_workq(workq) == 0) {
+ return(EINVAL);
+ }
+
+ workqueue_list_lock();
+ if ((workq->flags & (PTHREAD_WORKQ_IN_TERMINATE | PTHREAD_WORKQ_DESTROYED)) != 0) {
+ workqueue_list_unlock();
+ return(ESRCH);
+ }
+
+ TAILQ_FOREACH(item, &workq->item_listhead, item_entry) {
+ if (item == (pthread_workitem_t)itemhandle) {
+ TAILQ_REMOVE(&workq->item_listhead, item, item_entry);
+ if ((item->flags & (PTH_WQITEM_BARRIER | PTH_WQITEM_APPLIED)) == (PTH_WQITEM_BARRIER | PTH_WQITEM_APPLIED)) {
+ workq->flags &= ~PTHREAD_WORKQ_BARRIER_ON;
+ workq->barrier_count = 0;
+ if ((workq->queueprio < wqreadyprio) && (!(TAILQ_EMPTY(&workq->item_listhead)))) {
+ wqreadyprio = workq->queueprio;
+ }
+ } else if ((item->flags & PTH_WQITEM_KERN_COUNT) == PTH_WQITEM_KERN_COUNT) {
+ workq->kq_count--;
+ item->flags |= PTH_WQITEM_REMOVED;
+ if (handle_removeitem(workq, item) == 0)
+ return(0);
+ }
+ item->flags |= PTH_WQITEM_NOTINLIST;
+ free_workitem(item);
+ workqueue_list_unlock();
+ return(0);
+ }
+ }
+
+ TAILQ_FOREACH(item, &workq->item_kernhead, item_entry) {
+ if (item == (pthread_workitem_t)itemhandle) {
+ workqueue_list_unlock();
+ if ((error = __workq_ops(WQOPS_QUEUE_REMOVE, item, 0)) == 0) {
+ workqueue_list_lock();
+ TAILQ_REMOVE(&workq->item_kernhead, item, item_entry);
+ OSAtomicDecrement32(&kernel_workq_count);
+ workq->kq_count--;
+ item->flags |= PTH_WQITEM_REMOVED;
+ if (handle_removeitem(workq, item) != 0) {
+ free_workitem(item);
+ pick_nextworkqueue_droplock();
+ }
+ return(0);
+ } else {
+ workqueue_list_unlock();
+ return(EBUSY);
+ }
+ }
+ }
+ workqueue_list_unlock();
+ return(EINVAL);
+}
+
+
+int
+pthread_workqueue_addbarrier_np(pthread_workqueue_t workq, void (* callback_func)(pthread_workqueue_t, void *), void * callback_arg, __unused int waitforcallback, pthread_workitem_handle_t *itemhandlep)
+{
+ pthread_workitem_t witem;
+
+ if (valid_workq(workq) == 0) {
+ return(EINVAL);
+ }
+
+ workqueue_list_lock();
+
+ /*
+ * Allocate the workitem here as it can drop the lock.
+ * Also we can evaluate the workqueue state only once.
+ */
+ witem = alloc_workitem();
+ witem->item_entry.tqe_next = 0;
+ witem->item_entry.tqe_prev = 0;
+ witem->func = callback_func;
+ witem->func_arg = callback_arg;
+ witem->flags = PTH_WQITEM_BARRIER;
+
+ /* alloc workitem can drop the lock, check the state */
+ if ((workq->flags & (PTHREAD_WORKQ_IN_TERMINATE | PTHREAD_WORKQ_DESTROYED)) != 0) {
+ free_workitem(witem);
+ workqueue_list_unlock();
+ return(ESRCH);
+ }
+
+ if (itemhandlep != NULL)
+ *itemhandlep = (pthread_workitem_handle_t *)witem;
+
+ TAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
+ if (((workq->flags & PTHREAD_WORKQ_BARRIER_ON) == 0) && (workq->queueprio < wqreadyprio))
+ wqreadyprio = workq->queueprio;
+
+ pick_nextworkqueue_droplock();
+
return(0);
}
+int
+pthread_workqueue_suspend_np(pthread_workqueue_t workq)
+{
+ if (valid_workq(workq) == 0) {
+ return(EINVAL);
+ }
+ workqueue_list_lock();
+ if ((workq->flags & (PTHREAD_WORKQ_IN_TERMINATE | PTHREAD_WORKQ_DESTROYED)) != 0) {
+ workqueue_list_unlock();
+ return(ESRCH);
+ }
+
+ workq->flags |= PTHREAD_WORKQ_SUSPEND;
+ workq->suspend_count++;
+ workqueue_list_unlock();
+ return(0);
+}
+
+int
+pthread_workqueue_resume_np(pthread_workqueue_t workq)
+{
+ if (valid_workq(workq) == 0) {
+ return(EINVAL);
+ }
+ workqueue_list_lock();
+ if ((workq->flags & (PTHREAD_WORKQ_IN_TERMINATE | PTHREAD_WORKQ_DESTROYED)) != 0) {
+ workqueue_list_unlock();
+ return(ESRCH);
+ }
+
+ workq->suspend_count--;
+ if (workq->suspend_count <= 0) {
+ workq->flags &= ~PTHREAD_WORKQ_SUSPEND;
+ if (((workq->flags & PTHREAD_WORKQ_BARRIER_ON) == 0) && (workq->queueprio < wqreadyprio))
+ wqreadyprio = workq->queueprio;
+
+ pick_nextworkqueue_droplock();
+ } else
+ workqueue_list_unlock();
+
+
+ return(0);
+}
#else /* !BUILDING_VARIANT ] [ */
extern int __unix_conforming;
@@ -3273,7 +3210,8 @@
int already_exited, res;
void * dummy;
semaphore_t death;
- int newstyle;
+ mach_port_t joinport;
+ int newstyle = 0;
LOCK(thread->lock);
already_exited = (thread->detached & _PTHREAD_EXITED);
@@ -3283,7 +3221,7 @@
#if WQ_TRACE
__kdebug_trace(0x900002c, thread, newstyle, 0, 0, 0);
#endif
- if (newstyle == 0) {
+ if (newstyle = 0) {
death = thread->death;
if (!already_exited){
thread->joiner = (struct _pthread *)NULL;
@@ -3335,10 +3273,6 @@
if (_pthread_lookup_thread(thread, NULL, 0) != 0)
return(ESRCH);
- /* if the thread is a workqueue thread, then return error */
- if (thread->wqthread != 0) {
- return(ENOTSUP);
- }
#if __DARWIN_UNIX03
int state;