2  * Copyright (c) 2000-2009 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  28 /* Copyright (c) 1995-2005 Apple Computer, Inc. All Rights Reserved */ 
  33 #define  _PTHREAD_CONDATTR_T 
  34 #define  _PTHREAD_COND_T 
  35 #define _PTHREAD_MUTEXATTR_T 
  36 #define _PTHREAD_MUTEX_T 
  37 #define _PTHREAD_RWLOCKATTR_T 
  38 #define _PTHREAD_RWLOCK_T 
  40 #undef pthread_mutexattr_t 
  41 #undef pthread_mutex_t 
  42 #undef pthread_condattr_t 
  44 #undef pthread_rwlockattr_t 
  45 #undef pthread_rwlock_t 
  47 #include <sys/param.h> 
  48 #include <sys/queue.h> 
  49 #include <sys/resourcevar.h> 
  50 #include <sys/proc_internal.h> 
  51 #include <sys/kauth.h> 
  52 #include <sys/systm.h> 
  53 #include <sys/timeb.h> 
  54 #include <sys/times.h> 
  56 #include <sys/kernel.h> 
  58 #include <sys/signalvar.h> 
  59 #include <sys/syslog.h> 
  62 #include <sys/kdebug.h> 
  63 #include <sys/sysproto.h> 
  64 #include <sys/pthread_internal.h> 
  66 #include <sys/user.h>           /* for coredump */ 
  67 #include <sys/proc_info.h>      /* for fill_procworkqueue */ 
  70 #include <mach/mach_types.h> 
  71 #include <mach/vm_prot.h> 
  72 #include <mach/semaphore.h> 
  73 #include <mach/sync_policy.h> 
  74 #include <mach/task.h> 
  75 #include <kern/kern_types.h> 
  76 #include <kern/task.h> 
  77 #include <kern/clock.h> 
  78 #include <mach/kern_return.h> 
  79 #include <kern/thread.h> 
  80 #include <kern/sched_prim.h> 
  81 #include <kern/kalloc.h> 
  82 #include <kern/sched_prim.h>    /* for thread_exception_return */ 
  83 #include <kern/processor.h> 
  84 #include <kern/affinity.h> 
  85 #include <kern/assert.h> 
  86 #include <mach/mach_vm.h> 
  87 #include <mach/mach_param.h> 
  88 #include <mach/thread_status.h> 
  89 #include <mach/thread_policy.h> 
  90 #include <mach/message.h> 
  91 #include <mach/port.h> 
  92 #include <vm/vm_protos.h> 
  93 #include <vm/vm_map.h>  /* for current_map() */ 
  94 #include <mach/thread_act.h> /* for thread_resume */ 
  95 #include <machine/machine_routines.h> 
  97 #include <i386/machine_routines.h> 
  98 #include <i386/eflags.h> 
 100 #include <i386/seg.h>    
 103 #include <libkern/OSAtomic.h> 
 107 #define KERNEL_DEBUG KERNEL_DEBUG_CONSTANT 
 109 #define KERNEL_DEBUG1 KERNEL_DEBUG_CONSTANT1 
 113 #if defined(__ppc__) || defined(__ppc64__) 
 114 #include <architecture/ppc/cframe.h> 
 118 lck_grp_attr_t   
*pthread_lck_grp_attr
; 
 119 lck_grp_t    
*pthread_lck_grp
; 
 120 lck_attr_t   
*pthread_lck_attr
; 
 122 extern kern_return_t 
thread_getstatus(register thread_t act
, int flavor
, 
 123                         thread_state_t tstate
, mach_msg_type_number_t 
*count
); 
 124 extern kern_return_t 
thread_setstatus(thread_t thread
, int flavor
, 
 125                         thread_state_t tstate
, mach_msg_type_number_t count
); 
 126 extern void thread_set_cthreadself(thread_t thread
, uint64_t pself
, int isLP64
); 
 127 extern kern_return_t 
mach_port_deallocate(ipc_space_t
, mach_port_name_t
); 
 128 extern kern_return_t 
semaphore_signal_internal_trap(mach_port_name_t
); 
 130 extern void workqueue_thread_yielded(void); 
 132 static int workqueue_additem(struct workqueue 
*wq
, int prio
, user_addr_t item
, int affinity
); 
 133 static int workqueue_removeitem(struct workqueue 
*wq
, int prio
, user_addr_t item
); 
 134 static boolean_t 
workqueue_run_nextitem(proc_t p
, struct workqueue 
*wq
, thread_t th
, 
 135                                         user_addr_t oc_item
, int oc_prio
, int oc_affinity
); 
 136 static void wq_runitem(proc_t p
, user_addr_t item
, thread_t th
, struct threadlist 
*tl
, 
 137                        int reuse_thread
, int wake_thread
, int return_directly
); 
 138 static void wq_unpark_continue(void); 
 139 static void wq_unsuspend_continue(void); 
 140 static int setup_wqthread(proc_t p
, thread_t th
, user_addr_t item
, int reuse_thread
, struct threadlist 
*tl
); 
 141 static boolean_t 
workqueue_addnewthread(struct workqueue 
*wq
); 
 142 static void workqueue_removethread(struct threadlist 
*tl
); 
 143 static void workqueue_lock_spin(proc_t
); 
 144 static void workqueue_unlock(proc_t
); 
 145 int proc_settargetconc(pid_t pid
, int queuenum
, int32_t targetconc
); 
 146 int proc_setalltargetconc(pid_t pid
, int32_t * targetconcp
); 
 148 #define WQ_MAXPRI_MIN   0       /* low prio queue num */ 
 149 #define WQ_MAXPRI_MAX   2       /* max  prio queuenum */ 
 150 #define WQ_PRI_NUM      3       /* number of prio work queues */ 
 152 #define C_32_STK_ALIGN          16 
 153 #define C_64_STK_ALIGN          16 
 154 #define C_64_REDZONE_LEN        128 
 155 #define TRUNC_DOWN32(a,c)       ((((uint32_t)a)-(c)) & ((uint32_t)(-(c)))) 
 156 #define TRUNC_DOWN64(a,c)       ((((uint64_t)a)-(c)) & ((uint64_t)(-(c)))) 
 160  * Flags filed passed to bsdthread_create and back in pthread_start  
 161 31  <---------------------------------> 0 
 162 _________________________________________ 
 163 | flags(8) | policy(8) | importance(16) | 
 164 ----------------------------------------- 
 166 void _pthread_start(pthread_t self
, mach_port_t kport
, void *(*fun
)(void *), void * funarg
, size_t stacksize
, unsigned int flags
); 
 168 #define PTHREAD_START_CUSTOM    0x01000000 
 169 #define PTHREAD_START_SETSCHED  0x02000000 
 170 #define PTHREAD_START_DETACHED  0x04000000 
 171 #define PTHREAD_START_POLICY_BITSHIFT 16 
 172 #define PTHREAD_START_POLICY_MASK 0xff 
 173 #define PTHREAD_START_IMPORTANCE_MASK 0xffff 
 175 #define SCHED_OTHER      POLICY_TIMESHARE 
 176 #define SCHED_FIFO       POLICY_FIFO 
 177 #define SCHED_RR         POLICY_RR 
 182 bsdthread_create(__unused 
struct proc 
*p
, struct bsdthread_create_args  
*uap
, user_addr_t 
*retval
) 
 188         mach_vm_offset_t stackaddr
; 
 189         mach_vm_size_t th_allocsize 
= 0; 
 190         mach_vm_size_t user_stacksize
; 
 191         mach_vm_size_t th_stacksize
; 
 192         mach_vm_offset_t th_stackaddr
; 
 193         mach_vm_offset_t th_stack
; 
 194         mach_vm_offset_t th_pthread
; 
 195         mach_port_name_t th_thport
; 
 197         user_addr_t user_func 
= uap
->func
; 
 198         user_addr_t user_funcarg 
= uap
->func_arg
; 
 199         user_addr_t user_stack 
= uap
->stack
; 
 200         user_addr_t user_pthread 
= uap
->pthread
; 
 201         unsigned int  flags 
= (unsigned int)uap
->flags
; 
 202         vm_map_t vmap 
= current_map(); 
 203         task_t ctask 
= current_task(); 
 204         unsigned int policy
, importance
; 
 209         if ((p
->p_lflag 
& P_LREGISTER
) == 0) 
 212         KERNEL_DEBUG_CONSTANT(0x9000080 | DBG_FUNC_START
, flags
, 0, 0, 0, 0); 
 215         isLP64 
= IS_64BIT_PROCESS(p
); 
 219         stackaddr 
= 0xF0000000; 
 220 #elif defined(__i386__) || defined(__x86_64__) 
 221         stackaddr 
= 0xB0000000; 
 223 #error Need to define a stack address hint for this architecture 
 225         kret 
= thread_create(ctask
, &th
); 
 226         if (kret 
!= KERN_SUCCESS
) 
 228         thread_reference(th
); 
 230         sright 
= (void *) convert_thread_to_port(th
); 
 231         th_thport 
= ipc_port_copyout_send(sright
, get_task_ipcspace(ctask
)); 
 233         if ((flags 
& PTHREAD_START_CUSTOM
) == 0) { 
 234                 th_stacksize 
= (mach_vm_size_t
)user_stack
;              /* if it is custom them it is stacksize */ 
 235                 th_allocsize 
= th_stacksize 
+ PTH_DEFAULT_GUARDSIZE 
+ p
->p_pthsize
; 
 237                 kret 
= mach_vm_map(vmap
, &stackaddr
, 
 240                                 VM_MAKE_TAG(VM_MEMORY_STACK
)| VM_FLAGS_ANYWHERE 
, NULL
, 
 241                                 0, FALSE
, VM_PROT_DEFAULT
, VM_PROT_ALL
, 
 243                 if (kret 
!= KERN_SUCCESS
) 
 244                         kret 
= mach_vm_allocate(vmap
, 
 245                                         &stackaddr
, th_allocsize
, 
 246                                         VM_MAKE_TAG(VM_MEMORY_STACK
)| VM_FLAGS_ANYWHERE
); 
 247                 if (kret 
!= KERN_SUCCESS
) { 
 252                 KERNEL_DEBUG_CONSTANT(0x9000080 |DBG_FUNC_NONE
, th_allocsize
, stackaddr
, 0, 2, 0); 
 254                 th_stackaddr 
= stackaddr
; 
 257                  * The guard page is at the lowest address 
 258                  * The stack base is the highest address 
 260                 kret 
= mach_vm_protect(vmap
,  stackaddr
, PTH_DEFAULT_GUARDSIZE
, FALSE
, VM_PROT_NONE
); 
 262                 if (kret 
!= KERN_SUCCESS
) {  
 266                 th_stack 
= (stackaddr 
+ th_stacksize 
+ PTH_DEFAULT_GUARDSIZE
); 
 267                 th_pthread 
= (stackaddr 
+ th_stacksize 
+ PTH_DEFAULT_GUARDSIZE
); 
 268                 user_stacksize 
= th_stacksize
; 
 270                 th_stack 
= user_stack
; 
 271                 user_stacksize 
= user_stack
; 
 272                 th_pthread 
= user_pthread
; 
 274                 KERNEL_DEBUG_CONSTANT(0x9000080 |DBG_FUNC_NONE
, 0, 0, 0, 3, 0); 
 280          * Set up PowerPC registers... 
 281          * internally they are always kept as 64 bit and 
 282          * since the register set is the same between 32 and 64bit modes 
 283          * we don't need 2 different methods for setting the state 
 286                 ppc_thread_state64_t state64
; 
 287                 ppc_thread_state64_t 
*ts64 
= &state64
; 
 289                 ts64
->srr0 
= (uint64_t)p
->p_threadstart
; 
 290                 ts64
->r1 
= (uint64_t)(th_stack 
- C_ARGSAVE_LEN 
- C_RED_ZONE
); 
 291                 ts64
->r3 
= (uint64_t)th_pthread
; 
 292                 ts64
->r4 
= (uint64_t)(th_thport
); 
 293                 ts64
->r5 
= (uint64_t)user_func
; 
 294                 ts64
->r6 
= (uint64_t)user_funcarg
; 
 295                 ts64
->r7 
= (uint64_t)user_stacksize
; 
 296                 ts64
->r8 
= (uint64_t)uap
->flags
; 
 298                 thread_set_wq_state64(th
, (thread_state_t
)ts64
); 
 300                 thread_set_cthreadself(th
, (uint64_t)th_pthread
, isLP64
); 
 302 #elif defined(__i386__) || defined(__x86_64__) 
 305          * Set up i386 registers & function call. 
 308                 x86_thread_state32_t state
; 
 309                 x86_thread_state32_t 
*ts 
= &state
; 
 311                 ts
->eip 
= (int)p
->p_threadstart
; 
 312                 ts
->eax 
= (unsigned int)th_pthread
; 
 313                 ts
->ebx 
= (unsigned int)th_thport
; 
 314                 ts
->ecx 
= (unsigned int)user_func
; 
 315                 ts
->edx 
= (unsigned int)user_funcarg
; 
 316                 ts
->edi 
= (unsigned int)user_stacksize
; 
 317                 ts
->esi 
= (unsigned int)uap
->flags
; 
 321                 ts
->esp 
= (int)((vm_offset_t
)(th_stack
-C_32_STK_ALIGN
)); 
 323                 thread_set_wq_state32(th
, (thread_state_t
)ts
); 
 326                 x86_thread_state64_t state64
; 
 327                 x86_thread_state64_t 
*ts64 
= &state64
; 
 329                 ts64
->rip 
= (uint64_t)p
->p_threadstart
; 
 330                 ts64
->rdi 
= (uint64_t)th_pthread
; 
 331                 ts64
->rsi 
= (uint64_t)(th_thport
); 
 332                 ts64
->rdx 
= (uint64_t)user_func
; 
 333                 ts64
->rcx 
= (uint64_t)user_funcarg
; 
 334                 ts64
->r8 
= (uint64_t)user_stacksize
; 
 335                 ts64
->r9 
= (uint64_t)uap
->flags
; 
 337                  * set stack pointer aligned to 16 byte boundary 
 339                 ts64
->rsp 
= (uint64_t)(th_stack 
- C_64_REDZONE_LEN
); 
 341                 thread_set_wq_state64(th
, (thread_state_t
)ts64
); 
 345 #error bsdthread_create  not defined for this architecture 
 347         /* Set scheduling parameters if needed */ 
 348         if ((flags 
& PTHREAD_START_SETSCHED
) != 0) { 
 349                 thread_extended_policy_data_t    extinfo
; 
 350                 thread_precedence_policy_data_t   precedinfo
; 
 352                 importance 
= (flags 
& PTHREAD_START_IMPORTANCE_MASK
); 
 353                 policy 
= (flags 
>> PTHREAD_START_POLICY_BITSHIFT
) & PTHREAD_START_POLICY_MASK
; 
 355                 if (policy 
== SCHED_OTHER
) 
 356                         extinfo
.timeshare 
= 1; 
 358                         extinfo
.timeshare 
= 0; 
 359                 thread_policy_set(th
, THREAD_EXTENDED_POLICY
, (thread_policy_t
)&extinfo
, THREAD_EXTENDED_POLICY_COUNT
); 
 361 #define BASEPRI_DEFAULT 31 
 362                 precedinfo
.importance 
= (importance 
- BASEPRI_DEFAULT
); 
 363                 thread_policy_set(th
, THREAD_PRECEDENCE_POLICY
, (thread_policy_t
)&precedinfo
, THREAD_PRECEDENCE_POLICY_COUNT
); 
 366         kret 
= thread_resume(th
); 
 367         if (kret 
!= KERN_SUCCESS
) { 
 371         thread_deallocate(th
);  /* drop the creator reference */ 
 373         KERNEL_DEBUG_CONSTANT(0x9000080 |DBG_FUNC_END
, error
, th_pthread
, 0, 0, 0); 
 375         *retval 
= th_pthread
; 
 381                 (void)mach_vm_deallocate(vmap
,  stackaddr
, th_allocsize
); 
 383         (void)mach_port_deallocate(get_task_ipcspace(ctask
), th_thport
); 
 384         (void)thread_terminate(th
); 
 385         (void)thread_deallocate(th
); 
 390 bsdthread_terminate(__unused 
struct proc 
*p
, struct bsdthread_terminate_args  
*uap
, __unused 
int32_t *retval
) 
 392         mach_vm_offset_t  freeaddr
; 
 393         mach_vm_size_t freesize
; 
 395         mach_port_name_t kthport 
= (mach_port_name_t
)uap
->port
; 
 396         mach_port_name_t sem 
= (mach_port_name_t
)uap
->sem
; 
 398         freeaddr 
= (mach_vm_offset_t
)uap
->stackaddr
; 
 399         freesize 
= uap
->freesize
; 
 402         KERNEL_DEBUG_CONSTANT(0x9000084 |DBG_FUNC_START
, freeaddr
, freesize
, kthport
, 0xff, 0); 
 404         if ((freesize 
!= (mach_vm_size_t
)0) && (freeaddr 
!= (mach_vm_offset_t
)0)) { 
 405                 kret 
= mach_vm_deallocate(current_map(), freeaddr
, freesize
); 
 406                 if (kret 
!= KERN_SUCCESS
) { 
 411         (void) thread_terminate(current_thread()); 
 412         if (sem 
!= MACH_PORT_NULL
) { 
 413                  kret 
= semaphore_signal_internal_trap(sem
); 
 414                 if (kret 
!= KERN_SUCCESS
) { 
 419         if (kthport 
!= MACH_PORT_NULL
) 
 420                         mach_port_deallocate(get_task_ipcspace(current_task()), kthport
); 
 421         thread_exception_return(); 
 422         panic("bsdthread_terminate: still running\n"); 
 424         KERNEL_DEBUG_CONSTANT(0x9000084 |DBG_FUNC_END
, 0, 0, 0, 0xff, 0); 
 431 bsdthread_register(struct proc 
*p
, struct bsdthread_register_args  
*uap
, __unused 
int32_t *retval
) 
 433         /* prevent multiple registrations */ 
 434         if ((p
->p_lflag 
& P_LREGISTER
) != 0) 
 436         /* syscall randomizer test can pass bogus values */ 
 437         if (uap
->pthsize 
> MAX_PTHREAD_SIZE
) { 
 440         p
->p_threadstart 
= uap
->threadstart
; 
 441         p
->p_wqthread 
= uap
->wqthread
; 
 442         p
->p_pthsize 
= uap
->pthsize
; 
 443         p
->p_targconc 
= uap
->targetconc_ptr
; 
 444         p
->p_dispatchqueue_offset 
= uap
->dispatchqueue_offset
; 
 450 uint32_t wq_yielded_threshold           
= WQ_YIELDED_THRESHOLD
; 
 451 uint32_t wq_yielded_window_usecs        
= WQ_YIELDED_WINDOW_USECS
; 
 452 uint32_t wq_stalled_window_usecs        
= WQ_STALLED_WINDOW_USECS
; 
 453 uint32_t wq_reduce_pool_window_usecs    
= WQ_REDUCE_POOL_WINDOW_USECS
; 
 454 uint32_t wq_max_timer_interval_usecs    
= WQ_MAX_TIMER_INTERVAL_USECS
; 
 455 uint32_t wq_max_threads                 
= WORKQUEUE_MAXTHREADS
; 
 458 SYSCTL_INT(_kern
, OID_AUTO
, wq_yielded_threshold
, CTLFLAG_RW
, 
 459            &wq_yielded_threshold
, 0, ""); 
 461 SYSCTL_INT(_kern
, OID_AUTO
, wq_yielded_window_usecs
, CTLFLAG_RW
, 
 462            &wq_yielded_window_usecs
, 0, ""); 
 464 SYSCTL_INT(_kern
, OID_AUTO
, wq_stalled_window_usecs
, CTLFLAG_RW
, 
 465            &wq_stalled_window_usecs
, 0, ""); 
 467 SYSCTL_INT(_kern
, OID_AUTO
, wq_reduce_pool_window_usecs
, CTLFLAG_RW
, 
 468            &wq_reduce_pool_window_usecs
, 0, ""); 
 470 SYSCTL_INT(_kern
, OID_AUTO
, wq_max_timer_interval_usecs
, CTLFLAG_RW
, 
 471            &wq_max_timer_interval_usecs
, 0, ""); 
 473 SYSCTL_INT(_kern
, OID_AUTO
, wq_max_threads
, CTLFLAG_RW
, 
 474            &wq_max_threads
, 0, ""); 
 478 workqueue_init_lock(proc_t p
) 
 480         lck_spin_init(&p
->p_wqlock
, pthread_lck_grp
, pthread_lck_attr
); 
 482         p
->p_wqiniting 
= FALSE
; 
 486 workqueue_destroy_lock(proc_t p
) 
 488         lck_spin_destroy(&p
->p_wqlock
, pthread_lck_grp
); 
 493 workqueue_lock_spin(proc_t p
) 
 495         lck_spin_lock(&p
->p_wqlock
); 
 499 workqueue_unlock(proc_t p
) 
 501         lck_spin_unlock(&p
->p_wqlock
); 
 506 workqueue_interval_timer_start(struct workqueue 
*wq
) 
 510         if (wq
->wq_timer_interval 
== 0) 
 511                 wq
->wq_timer_interval 
= wq_stalled_window_usecs
; 
 513                 wq
->wq_timer_interval 
= wq
->wq_timer_interval 
* 2; 
 515                 if (wq
->wq_timer_interval 
> wq_max_timer_interval_usecs
) 
 516                         wq
->wq_timer_interval 
= wq_max_timer_interval_usecs
; 
 518         clock_interval_to_deadline(wq
->wq_timer_interval
, 1000, &deadline
); 
 520         thread_call_enter_delayed(wq
->wq_atimer_call
, deadline
); 
 522         KERNEL_DEBUG(0xefffd110, wq
, wq
->wq_itemcount
, wq
->wq_flags
, wq
->wq_timer_interval
, 0); 
 527 wq_thread_is_busy(uint64_t cur_ts
, uint64_t *lastblocked_tsp
) 
 530         uint64_t lastblocked_ts
; 
 534          * the timestamp is updated atomically w/o holding the workqueue lock 
 535          * so we need to do an atomic read of the 64 bits so that we don't see 
 536          * a mismatched pair of 32 bit reads... we accomplish this in an architecturally 
 537          * independent fashion by using OSCompareAndSwap64 to write back the 
 538          * value we grabbed... if it succeeds, then we have a good timestamp to 
 539          * evaluate... if it fails, we straddled grabbing the timestamp while it 
 540          * was being updated... treat a failed update as a busy thread since 
 541          * it implies we are about to see a really fresh timestamp anyway 
 543         lastblocked_ts 
= *lastblocked_tsp
; 
 547         if ( !OSCompareAndSwap64((UInt64
)lastblocked_ts
, (UInt64
)lastblocked_ts
, lastblocked_tsp
)) 
 550         if (lastblocked_ts 
>= cur_ts
) { 
 552                  * because the update of the timestamp when a thread blocks isn't 
 553                  * serialized against us looking at it (i.e. we don't hold the workq lock) 
 554                  * it's possible to have a timestamp that matches the current time or 
 555                  * that even looks to be in the future relative to when we grabbed the current 
 556                  * time... just treat this as a busy thread since it must have just blocked. 
 560         elapsed 
= cur_ts 
- lastblocked_ts
; 
 562         absolutetime_to_microtime(elapsed
, &secs
, &usecs
); 
 564         if (secs 
== 0 && usecs 
< wq_stalled_window_usecs
) 
 570 #define WQ_TIMER_NEEDED(wq, start_timer) do {           \ 
 571         int oldflags = wq->wq_flags;                    \ 
 573         if ( !(oldflags & (WQ_EXITING | WQ_ATIMER_RUNNING))) {  \ 
 574                 if (OSCompareAndSwap(oldflags, oldflags | WQ_ATIMER_RUNNING, (UInt32 *)&wq->wq_flags)) \ 
 575                         start_timer = TRUE;                     \ 
 582 workqueue_add_timer(struct workqueue 
*wq
, __unused 
int param1
) 
 585         boolean_t       start_timer 
= FALSE
; 
 587         boolean_t       add_thread
; 
 590         KERNEL_DEBUG(0xefffd108 | DBG_FUNC_START
, wq
, wq
->wq_flags
, wq
->wq_nthreads
, wq
->wq_thidlecount
, 0); 
 594         workqueue_lock_spin(p
); 
 597          * because workqueue_callback now runs w/o taking the workqueue lock 
 598          * we are unsynchronized w/r to a change in state of the running threads... 
 599          * to make sure we always evaluate that change, we allow it to start up  
 600          * a new timer if the current one is actively evalutating the state 
 601          * however, we do not need more than 2 timers fired up (1 active and 1 pending) 
 602          * and we certainly do not want 2 active timers evaluating the state 
 603          * simultaneously... so use WQL_ATIMER_BUSY to serialize the timers... 
 604          * note that WQL_ATIMER_BUSY is in a different flag word from WQ_ATIMER_RUNNING since 
 605          * it is always protected by the workq lock... WQ_ATIMER_RUNNING is evaluated 
 606          * and set atomimcally since the callback function needs to manipulate it 
 607          * w/o holding the workq lock... 
 609          * !WQ_ATIMER_RUNNING && !WQL_ATIMER_BUSY   ==   no pending timer, no active timer 
 610          * !WQ_ATIMER_RUNNING && WQL_ATIMER_BUSY    ==   no pending timer, 1 active timer 
 611          * WQ_ATIMER_RUNNING && !WQL_ATIMER_BUSY    ==   1 pending timer, no active timer 
 612          * WQ_ATIMER_RUNNING && WQL_ATIMER_BUSY     ==   1 pending timer, 1 active timer 
 614         while (wq
->wq_lflags 
& WQL_ATIMER_BUSY
) { 
 615                 wq
->wq_lflags 
|= WQL_ATIMER_WAITING
; 
 617                 assert_wait((caddr_t
)wq
, (THREAD_UNINT
)); 
 620                 thread_block(THREAD_CONTINUE_NULL
); 
 622                 workqueue_lock_spin(p
); 
 624         wq
->wq_lflags 
|= WQL_ATIMER_BUSY
; 
 627          * the workq lock will protect us from seeing WQ_EXITING change state, but we 
 628          * still need to update this atomically in case someone else tries to start 
 629          * the timer just as we're releasing it 
 631         while ( !(OSCompareAndSwap(wq
->wq_flags
, (wq
->wq_flags 
& ~WQ_ATIMER_RUNNING
), (UInt32 
*)&wq
->wq_flags
))); 
 637         if ( !(wq
->wq_flags 
& WQ_EXITING
)) { 
 639                  * check to see if the stall frequency was beyond our tolerance 
 640                  * or we have work on the queue, but haven't scheduled any  
 641                  * new work within our acceptable time interval because 
 642                  * there were no idle threads left to schedule 
 644                 if (wq
->wq_itemcount
) { 
 646                         uint32_t        affinity_tag
; 
 650                         for (priority 
= 0; priority 
< WORKQUEUE_NUMPRIOS
; priority
++) { 
 651                                 if (wq
->wq_list_bitmap 
& (1 << priority
)) 
 654                         assert(priority 
< WORKQUEUE_NUMPRIOS
); 
 656                         curtime 
= mach_absolute_time(); 
 659                         for (affinity_tag 
= 0; affinity_tag 
< wq
->wq_reqconc
[priority
]; affinity_tag
++) { 
 661                                  * if we have no idle threads, we can try to add them if needed 
 663                                 if (wq
->wq_thidlecount 
== 0) 
 667                                  * look for first affinity group that is currently not active 
 668                                  * i.e. no active threads at this priority level or higher 
 669                                  * and has not been active recently at this priority level or higher 
 671                                 for (i 
= 0; i 
<= priority
; i
++) { 
 672                                         if (wq
->wq_thactive_count
[i
][affinity_tag
]) { 
 676                                         if (wq
->wq_thscheduled_count
[i
][affinity_tag
]) { 
 677                                                 if (wq_thread_is_busy(curtime
, &wq
->wq_lastblocked_ts
[i
][affinity_tag
])) { 
 684                                 if (add_thread 
== TRUE
) { 
 685                                         retval 
= workqueue_addnewthread(wq
); 
 689                         if (wq
->wq_itemcount
) { 
 691                                  * as long as we have threads to schedule, and we successfully 
 692                                  * scheduled new work, keep trying 
 694                                 while (wq
->wq_thidlecount 
&& !(wq
->wq_flags 
& WQ_EXITING
)) { 
 696                                          * workqueue_run_nextitem is responsible for 
 697                                          * dropping the workqueue lock in all cases 
 699                                         retval 
= workqueue_run_nextitem(p
, wq
, THREAD_NULL
, 0, 0, 0); 
 700                                         workqueue_lock_spin(p
); 
 705                                 if ( !(wq
->wq_flags 
& WQ_EXITING
) && wq
->wq_itemcount
) { 
 707                                         if (wq
->wq_thidlecount 
== 0 && retval 
== TRUE 
&& add_thread 
== TRUE
) 
 710                                         if (wq
->wq_thidlecount 
== 0 || busycount
) 
 711                                                 WQ_TIMER_NEEDED(wq
, start_timer
); 
 713                                         KERNEL_DEBUG(0xefffd108 | DBG_FUNC_NONE
, wq
, wq
->wq_itemcount
, wq
->wq_thidlecount
, busycount
, 0); 
 718         if ( !(wq
->wq_flags 
& WQ_ATIMER_RUNNING
)) 
 719                 wq
->wq_timer_interval 
= 0; 
 721         wq
->wq_lflags 
&= ~WQL_ATIMER_BUSY
; 
 723         if ((wq
->wq_flags 
& WQ_EXITING
) || (wq
->wq_lflags 
& WQL_ATIMER_WAITING
)) { 
 725                  * wakeup the thread hung up in workqueue_exit or workqueue_add_timer waiting for this timer 
 726                  * to finish getting out of the way 
 728                 wq
->wq_lflags 
&= ~WQL_ATIMER_WAITING
; 
 731         KERNEL_DEBUG(0xefffd108 | DBG_FUNC_END
, wq
, start_timer
, wq
->wq_nthreads
, wq
->wq_thidlecount
, 0); 
 735         if (start_timer 
== TRUE
) 
 736                 workqueue_interval_timer_start(wq
); 
 741 workqueue_thread_yielded(void) 
 743         struct workqueue 
*wq
; 
 748         if ((wq 
= p
->p_wqptr
) == NULL 
|| wq
->wq_itemcount 
== 0) 
 751         workqueue_lock_spin(p
); 
 753         if (wq
->wq_itemcount
) { 
 759                 if (wq
->wq_thread_yielded_count
++ == 0) 
 760                         wq
->wq_thread_yielded_timestamp 
= mach_absolute_time(); 
 762                 if (wq
->wq_thread_yielded_count 
< wq_yielded_threshold
) { 
 766                 KERNEL_DEBUG(0xefffd138 | DBG_FUNC_START
, wq
, wq
->wq_thread_yielded_count
, wq
->wq_itemcount
, 0, 0); 
 768                 wq
->wq_thread_yielded_count 
= 0; 
 770                 curtime 
= mach_absolute_time(); 
 771                 elapsed 
= curtime 
- wq
->wq_thread_yielded_timestamp
; 
 772                 absolutetime_to_microtime(elapsed
, &secs
, &usecs
); 
 774                 if (secs 
== 0 && usecs 
< wq_yielded_window_usecs
) { 
 776                         if (wq
->wq_thidlecount 
== 0) { 
 777                                 workqueue_addnewthread(wq
); 
 779                                  * 'workqueue_addnewthread' drops the workqueue lock 
 780                                  * when creating the new thread and then retakes it before 
 781                                  * returning... this window allows other threads to process 
 782                                  * work on the queue, so we need to recheck for available work 
 783                                  * if none found, we just return...  the newly created thread 
 784                                  * will eventually get used (if it hasn't already)... 
 786                                 if (wq
->wq_itemcount 
== 0) { 
 791                         if (wq
->wq_thidlecount
) { 
 793                                 uint32_t        affinity 
= -1; 
 795                                 struct workitem 
*witem 
= NULL
; 
 796                                 struct workitemlist 
*wl 
= NULL
; 
 798                                 struct threadlist 
*tl
; 
 800                                 uth 
= get_bsdthread_info(current_thread()); 
 801                                 if ((tl 
= uth
->uu_threadlist
)) 
 802                                         affinity 
= tl
->th_affinity_tag
; 
 804                                 for (priority 
= 0; priority 
< WORKQUEUE_NUMPRIOS
; priority
++) { 
 805                                         if (wq
->wq_list_bitmap 
& (1 << priority
)) { 
 806                                                 wl 
= (struct workitemlist 
*)&wq
->wq_list
[priority
]; 
 811                                 assert(!(TAILQ_EMPTY(&wl
->wl_itemlist
))); 
 813                                 witem 
= TAILQ_FIRST(&wl
->wl_itemlist
); 
 814                                 TAILQ_REMOVE(&wl
->wl_itemlist
, witem
, wi_entry
); 
 816                                 if (TAILQ_EMPTY(&wl
->wl_itemlist
)) 
 817                                         wq
->wq_list_bitmap 
&= ~(1 << priority
); 
 820                                 item 
= witem
->wi_item
; 
 821                                 witem
->wi_item 
= (user_addr_t
)0; 
 822                                 witem
->wi_affinity 
= 0; 
 824                                 TAILQ_INSERT_HEAD(&wl
->wl_freelist
, witem
, wi_entry
); 
 826                                 (void)workqueue_run_nextitem(p
, wq
, THREAD_NULL
, item
, priority
, affinity
); 
 828                                  * workqueue_run_nextitem is responsible for 
 829                                  * dropping the workqueue lock in all cases 
 831                                 KERNEL_DEBUG(0xefffd138 | DBG_FUNC_END
, wq
, wq
->wq_thread_yielded_count
, wq
->wq_itemcount
, 1, 0); 
 836                 KERNEL_DEBUG(0xefffd138 | DBG_FUNC_END
, wq
, wq
->wq_thread_yielded_count
, wq
->wq_itemcount
, 2, 0); 
 844 workqueue_callback(int type
, thread_t thread
) 
 847         struct threadlist 
*tl
; 
 848         struct workqueue  
*wq
; 
 850         uth 
= get_bsdthread_info(thread
); 
 851         tl 
= uth
->uu_threadlist
; 
 856               case SCHED_CALL_BLOCK
: 
 858                 uint32_t        old_activecount
; 
 860                 old_activecount 
= OSAddAtomic(-1, &wq
->wq_thactive_count
[tl
->th_priority
][tl
->th_affinity_tag
]); 
 862                 if (old_activecount 
== 1) { 
 863                         boolean_t       start_timer 
= FALSE
; 
 865                         UInt64          
*lastblocked_ptr
; 
 868                          * we were the last active thread on this affinity set 
 869                          * and we've got work to do 
 871                         lastblocked_ptr 
= (UInt64 
*)&wq
->wq_lastblocked_ts
[tl
->th_priority
][tl
->th_affinity_tag
]; 
 872                         curtime 
= mach_absolute_time(); 
 875                          * if we collide with another thread trying to update the last_blocked (really unlikely 
 876                          * since another thread would have to get scheduled and then block after we start down  
 877                          * this path), it's not a problem.  Either timestamp is adequate, so no need to retry 
 881                          * this doesn't have to actually work reliablly for PPC, it just has to compile/link 
 883                         *lastblocked_ptr 
= (UInt64
)curtime
; 
 885                         OSCompareAndSwap64(*lastblocked_ptr
, (UInt64
)curtime
, lastblocked_ptr
); 
 887                         if (wq
->wq_itemcount
) 
 888                                 WQ_TIMER_NEEDED(wq
, start_timer
); 
 890                         if (start_timer 
== TRUE
) 
 891                                 workqueue_interval_timer_start(wq
); 
 893                 KERNEL_DEBUG1(0xefffd020 | DBG_FUNC_START
, wq
, old_activecount
, tl
->th_priority
, tl
->th_affinity_tag
, thread_tid(thread
)); 
 897               case SCHED_CALL_UNBLOCK
: 
 899                  * we cannot take the workqueue_lock here... 
 900                  * an UNBLOCK can occur from a timer event which 
 901                  * is run from an interrupt context... if the workqueue_lock 
 902                  * is already held by this processor, we'll deadlock... 
 903                  * the thread lock for the thread being UNBLOCKED 
 906                  OSAddAtomic(1, &wq
->wq_thactive_count
[tl
->th_priority
][tl
->th_affinity_tag
]); 
 908                  KERNEL_DEBUG1(0xefffd020 | DBG_FUNC_END
, wq
, wq
->wq_threads_scheduled
, tl
->th_priority
, tl
->th_affinity_tag
, thread_tid(thread
)); 
 916 workqueue_removethread(struct threadlist 
*tl
) 
 918         struct workqueue 
*wq
; 
 919         struct uthread 
* uth
; 
 923         TAILQ_REMOVE(&wq
->wq_thidlelist
, tl
, th_entry
); 
 926         wq
->wq_thidlecount
--; 
 929          * Clear the threadlist pointer in uthread so  
 930          * blocked thread on wakeup for termination will 
 931          * not access the thread list as it is going to be 
 934         thread_sched_call(tl
->th_thread
, NULL
); 
 936         uth 
= get_bsdthread_info(tl
->th_thread
); 
 937         if (uth 
!= (struct uthread 
*)0) { 
 938                 uth
->uu_threadlist 
= NULL
; 
 940         workqueue_unlock(wq
->wq_proc
); 
 942         if ( (tl
->th_flags 
& TH_LIST_SUSPENDED
) ) { 
 944                  * thread was created, but never used...  
 945                  * need to clean up the stack and port ourselves 
 946                  * since we're not going to spin up through the 
 947                  * normal exit path triggered from Libc 
 949                 (void)mach_vm_deallocate(wq
->wq_map
, tl
->th_stackaddr
, tl
->th_allocsize
); 
 950                 (void)mach_port_deallocate(get_task_ipcspace(wq
->wq_task
), tl
->th_thport
); 
 952                 KERNEL_DEBUG1(0xefffd014 | DBG_FUNC_END
, wq
, (uintptr_t)thread_tid(current_thread()), wq
->wq_nthreads
, 0xdead, thread_tid(tl
->th_thread
)); 
 955                 KERNEL_DEBUG1(0xefffd018 | DBG_FUNC_END
, wq
, (uintptr_t)thread_tid(current_thread()), wq
->wq_nthreads
, 0xdead, thread_tid(tl
->th_thread
)); 
 958          * drop our ref on the thread 
 960         thread_deallocate(tl
->th_thread
); 
 962         kfree(tl
, sizeof(struct threadlist
)); 
 968 workqueue_addnewthread(struct workqueue 
*wq
) 
 970         struct threadlist 
*tl
; 
 976         mach_vm_offset_t stackaddr
; 
 978         if (wq
->wq_nthreads 
>= wq_max_threads 
|| wq
->wq_nthreads 
>= (CONFIG_THREAD_MAX 
- 20)) 
 985         kret 
= thread_create_workq(wq
->wq_task
, (thread_continue_t
)wq_unsuspend_continue
, &th
); 
 987         if (kret 
!= KERN_SUCCESS
) 
 990         tl 
= kalloc(sizeof(struct threadlist
)); 
 991         bzero(tl
, sizeof(struct threadlist
)); 
 994         stackaddr 
= 0xF0000000; 
 995 #elif defined(__i386__) || defined(__x86_64__) 
 996         stackaddr 
= 0xB0000000; 
 998 #error Need to define a stack address hint for this architecture 
1000         tl
->th_allocsize 
= PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE 
+ p
->p_pthsize
; 
1002         kret 
= mach_vm_map(wq
->wq_map
, &stackaddr
, 
1005                         VM_MAKE_TAG(VM_MEMORY_STACK
)| VM_FLAGS_ANYWHERE 
, NULL
, 
1006                         0, FALSE
, VM_PROT_DEFAULT
, VM_PROT_ALL
, 
1007                         VM_INHERIT_DEFAULT
); 
1009         if (kret 
!= KERN_SUCCESS
) { 
1010                 kret 
= mach_vm_allocate(wq
->wq_map
, 
1011                                         &stackaddr
, tl
->th_allocsize
, 
1012                                         VM_MAKE_TAG(VM_MEMORY_STACK
) | VM_FLAGS_ANYWHERE
); 
1014         if (kret 
== KERN_SUCCESS
) { 
1016                  * The guard page is at the lowest address 
1017                  * The stack base is the highest address 
1019                 kret 
= mach_vm_protect(wq
->wq_map
, stackaddr
, PTH_DEFAULT_GUARDSIZE
, FALSE
, VM_PROT_NONE
); 
1021                 if (kret 
!= KERN_SUCCESS
) 
1022                         (void) mach_vm_deallocate(wq
->wq_map
, stackaddr
, tl
->th_allocsize
); 
1024         if (kret 
!= KERN_SUCCESS
) { 
1025                 (void) thread_terminate(th
); 
1027                 kfree(tl
, sizeof(struct threadlist
)); 
1030         thread_reference(th
); 
1032         sright 
= (void *) convert_thread_to_port(th
); 
1033         tl
->th_thport 
= ipc_port_copyout_send(sright
, get_task_ipcspace(wq
->wq_task
)); 
1035         thread_static_param(th
, TRUE
); 
1037         tl
->th_flags 
= TH_LIST_INITED 
| TH_LIST_SUSPENDED
; 
1041         tl
->th_stackaddr 
= stackaddr
; 
1042         tl
->th_affinity_tag 
= -1; 
1043         tl
->th_priority 
= WORKQUEUE_NUMPRIOS
; 
1046 #if defined(__ppc__) 
1047         //ml_fp_setvalid(FALSE); 
1048         thread_set_cthreadself(th
, (uint64_t)(tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
), IS_64BIT_PROCESS(p
)); 
1049 #endif /* __ppc__ */ 
1051         uth 
= get_bsdthread_info(tl
->th_thread
); 
1052         uth
->uu_threadlist 
= (void *)tl
; 
1054         workqueue_lock_spin(p
); 
1056         TAILQ_INSERT_TAIL(&wq
->wq_thidlelist
, tl
, th_entry
); 
1058         wq
->wq_thidlecount
++; 
1060         KERNEL_DEBUG1(0xefffd014 | DBG_FUNC_START
, wq
, wq
->wq_nthreads
, 0, thread_tid(current_thread()), thread_tid(tl
->th_thread
)); 
1065         workqueue_lock_spin(p
); 
1073 workq_open(struct proc 
*p
, __unused 
struct workq_open_args  
*uap
, __unused 
int32_t *retval
) 
1075         struct workqueue 
* wq
; 
1083         boolean_t need_wakeup 
= FALSE
; 
1084         struct workitem 
* witem
; 
1085         struct workitemlist 
*wl
; 
1087         if ((p
->p_lflag 
& P_LREGISTER
) == 0) 
1090         workqueue_lock_spin(p
); 
1092         if (p
->p_wqptr 
== NULL
) { 
1094                 while (p
->p_wqiniting 
== TRUE
) { 
1096                         assert_wait((caddr_t
)&p
->p_wqiniting
, THREAD_UNINT
); 
1097                         workqueue_unlock(p
); 
1099                         thread_block(THREAD_CONTINUE_NULL
); 
1101                         workqueue_lock_spin(p
); 
1103                 if (p
->p_wqptr 
!= NULL
) 
1106                 p
->p_wqiniting 
= TRUE
; 
1108                 workqueue_unlock(p
); 
1110                 num_cpus 
= ml_get_max_cpus(); 
1112                 wq_size 
= sizeof(struct workqueue
) + 
1113                         (num_cpus 
* WORKQUEUE_NUMPRIOS 
* sizeof(uint32_t)) + 
1114                         (num_cpus 
* WORKQUEUE_NUMPRIOS 
* sizeof(uint32_t)) + 
1115                         (num_cpus 
* WORKQUEUE_NUMPRIOS 
* sizeof(uint64_t)) + 
1118                 ptr 
= (char *)kalloc(wq_size
); 
1119                 bzero(ptr
, wq_size
); 
1121                 wq 
= (struct workqueue 
*)ptr
; 
1122                 wq
->wq_flags 
= WQ_LIST_INITED
; 
1124                 wq
->wq_affinity_max 
= num_cpus
; 
1125                 wq
->wq_task 
= current_task(); 
1126                 wq
->wq_map  
= current_map(); 
1128                 for (i 
= 0; i 
< WORKQUEUE_NUMPRIOS
; i
++) { 
1129                         wl 
= (struct workitemlist 
*)&wq
->wq_list
[i
]; 
1130                         TAILQ_INIT(&wl
->wl_itemlist
); 
1131                         TAILQ_INIT(&wl
->wl_freelist
); 
1133                         for (j 
= 0; j 
< WORKITEM_SIZE
; j
++) { 
1134                                 witem 
= &wq
->wq_array
[(i
*WORKITEM_SIZE
) + j
]; 
1135                                 TAILQ_INSERT_TAIL(&wl
->wl_freelist
, witem
, wi_entry
); 
1137                         wq
->wq_reqconc
[i
] = wq
->wq_affinity_max
; 
1139                 nptr 
= ptr 
+ sizeof(struct workqueue
); 
1141                 for (i 
= 0; i 
< WORKQUEUE_NUMPRIOS
; i
++) { 
1142                         wq
->wq_thactive_count
[i
] = (uint32_t *)nptr
; 
1143                         nptr 
+= (num_cpus 
* sizeof(uint32_t)); 
1145                 for (i 
= 0; i 
< WORKQUEUE_NUMPRIOS
; i
++) { 
1146                         wq
->wq_thscheduled_count
[i
] = (uint32_t *)nptr
; 
1147                         nptr 
+= (num_cpus 
* sizeof(uint32_t)); 
1150                  * align nptr on a 64 bit boundary so that we can do nice 
1151                  * atomic64 operations on the timestamps... 
1152                  * note that we requested an extra uint64_t when calcuating 
1153                  * the size for the allocation of the workqueue struct 
1155                 nptr 
+= (sizeof(uint64_t) - 1); 
1156                 nptr 
= (char *)((long)nptr 
& ~(sizeof(uint64_t) - 1)); 
1158                 for (i 
= 0; i 
< WORKQUEUE_NUMPRIOS
; i
++) { 
1159                         wq
->wq_lastblocked_ts
[i
] = (uint64_t *)nptr
; 
1160                         nptr 
+= (num_cpus 
* sizeof(uint64_t)); 
1162                 TAILQ_INIT(&wq
->wq_thrunlist
); 
1163                 TAILQ_INIT(&wq
->wq_thidlelist
); 
1165                 wq
->wq_atimer_call 
= thread_call_allocate((thread_call_func_t
)workqueue_add_timer
, (thread_call_param_t
)wq
); 
1167                 workqueue_lock_spin(p
); 
1169                 p
->p_wqptr 
= (void *)wq
; 
1170                 p
->p_wqsize 
= wq_size
; 
1172                 p
->p_wqiniting 
= FALSE
; 
1176         workqueue_unlock(p
); 
1178         if (need_wakeup 
== TRUE
) 
1179                 wakeup(&p
->p_wqiniting
); 
1184 workq_kernreturn(struct proc 
*p
, struct workq_kernreturn_args  
*uap
, __unused 
int32_t *retval
) 
1186         user_addr_t item 
= uap
->item
; 
1187         int options     
= uap
->options
; 
1188         int prio        
= uap
->prio
;    /* should  be used to find the right workqueue */ 
1189         int affinity    
= uap
->affinity
; 
1191         thread_t th     
= THREAD_NULL
; 
1192         user_addr_t oc_item 
= 0; 
1193         struct workqueue 
*wq
; 
1195         if ((p
->p_lflag 
& P_LREGISTER
) == 0) 
1199          * affinity not yet hooked up on this path 
1205                 case WQOPS_QUEUE_ADD
: { 
1207                         if (prio 
& WORKQUEUE_OVERCOMMIT
) { 
1208                                 prio 
&= ~WORKQUEUE_OVERCOMMIT
; 
1211                         if ((prio 
< 0) || (prio 
>= WORKQUEUE_NUMPRIOS
)) 
1214                         workqueue_lock_spin(p
); 
1216                         if ((wq 
= (struct workqueue 
*)p
->p_wqptr
) == NULL
) { 
1217                                 workqueue_unlock(p
); 
1220                         if (wq
->wq_thidlecount 
== 0 && (oc_item 
|| (wq
->wq_nthreads 
< wq
->wq_affinity_max
))) { 
1222                                 workqueue_addnewthread(wq
); 
1224                                 if (wq
->wq_thidlecount 
== 0) 
1228                                 error 
= workqueue_additem(wq
, prio
, item
, affinity
); 
1230                         KERNEL_DEBUG(0xefffd008 | DBG_FUNC_NONE
, wq
, prio
, affinity
, oc_item
, 0); 
1233                 case WQOPS_QUEUE_REMOVE
: { 
1235                         if ((prio 
< 0) || (prio 
>= WORKQUEUE_NUMPRIOS
)) 
1238                         workqueue_lock_spin(p
); 
1240                         if ((wq 
= (struct workqueue 
*)p
->p_wqptr
) == NULL
) { 
1241                                 workqueue_unlock(p
); 
1244                         error 
= workqueue_removeitem(wq
, prio
, item
); 
1247                 case WQOPS_THREAD_RETURN
: { 
1249                         th 
= current_thread(); 
1250                         struct uthread 
*uth 
= get_bsdthread_info(th
); 
1252                         /* reset signal mask on the workqueue thread to default state */ 
1253                         if (uth
->uu_sigmask 
!= (sigset_t
)(~workq_threadmask
)) { 
1255                                 uth
->uu_sigmask 
= ~workq_threadmask
; 
1259                         workqueue_lock_spin(p
); 
1261                         if ((wq 
= (struct workqueue 
*)p
->p_wqptr
) == NULL 
|| (uth
->uu_threadlist 
== NULL
)) { 
1262                                 workqueue_unlock(p
); 
1265                         KERNEL_DEBUG(0xefffd004 | DBG_FUNC_END
, wq
, 0, 0, 0, 0); 
1268                 case WQOPS_THREAD_SETCONC
: { 
1270                         if ((prio 
< 0) || (prio 
> WORKQUEUE_NUMPRIOS
)) 
1273                         workqueue_lock_spin(p
); 
1275                         if ((wq 
= (struct workqueue 
*)p
->p_wqptr
) == NULL
) { 
1276                                 workqueue_unlock(p
); 
1280                          * for this operation, we re-purpose the affinity 
1281                          * argument as the concurrency target 
1283                         if (prio 
< WORKQUEUE_NUMPRIOS
) 
1284                                 wq
->wq_reqconc
[prio
] = affinity
; 
1286                                 for (prio 
= 0; prio 
< WORKQUEUE_NUMPRIOS
; prio
++) 
1287                                         wq
->wq_reqconc
[prio
] = affinity
; 
1295         (void)workqueue_run_nextitem(p
, wq
, th
, oc_item
, prio
, affinity
); 
1297          * workqueue_run_nextitem is responsible for 
1298          * dropping the workqueue lock in all cases 
1305 workqueue_exit(struct proc 
*p
) 
1307         struct workqueue  
* wq
; 
1308         struct threadlist  
* tl
, *tlist
; 
1309         struct uthread  
*uth
; 
1312         if (p
->p_wqptr 
!= NULL
) { 
1314                 KERNEL_DEBUG(0x900808c | DBG_FUNC_START
, p
->p_wqptr
, 0, 0, 0, 0); 
1316                 workqueue_lock_spin(p
); 
1318                 wq 
= (struct workqueue 
*)p
->p_wqptr
; 
1321                         workqueue_unlock(p
); 
1323                         KERNEL_DEBUG(0x900808c | DBG_FUNC_END
, 0, 0, 0, -1, 0); 
1326                 wq_size 
= p
->p_wqsize
; 
1331                  * we now arm the timer in the callback function w/o holding the workq lock... 
1332                  * we do this by setting  WQ_ATIMER_RUNNING via OSCompareAndSwap in order to  
1333                  * insure only a single timer if running and to notice that WQ_EXITING has 
1334                  * been set (we don't want to start a timer once WQ_EXITING is posted) 
1336                  * so once we have successfully set WQ_EXITING, we cannot fire up a new timer... 
1337                  * therefor no need to clear the timer state atomically from the flags 
1339                  * since we always hold the workq lock when dropping WQ_ATIMER_RUNNING 
1340                  * the check for and sleep until clear is protected 
1342                 while ( !(OSCompareAndSwap(wq
->wq_flags
, (wq
->wq_flags 
| WQ_EXITING
), (UInt32 
*)&wq
->wq_flags
))); 
1344                 if (wq
->wq_flags 
& WQ_ATIMER_RUNNING
) { 
1345                         if (thread_call_cancel(wq
->wq_atimer_call
) == TRUE
) 
1346                                 wq
->wq_flags 
&= ~WQ_ATIMER_RUNNING
; 
1348                 while ((wq
->wq_flags 
& WQ_ATIMER_RUNNING
) || (wq
->wq_lflags 
& WQL_ATIMER_BUSY
)) { 
1350                         assert_wait((caddr_t
)wq
, (THREAD_UNINT
)); 
1351                         workqueue_unlock(p
); 
1353                         thread_block(THREAD_CONTINUE_NULL
); 
1355                         workqueue_lock_spin(p
); 
1357                 workqueue_unlock(p
); 
1359                 TAILQ_FOREACH_SAFE(tl
, &wq
->wq_thrunlist
, th_entry
, tlist
) { 
1361                         thread_sched_call(tl
->th_thread
, NULL
); 
1363                         uth 
= get_bsdthread_info(tl
->th_thread
); 
1364                         if (uth 
!= (struct uthread 
*)0) { 
1365                                 uth
->uu_threadlist 
= NULL
; 
1367                         TAILQ_REMOVE(&wq
->wq_thrunlist
, tl
, th_entry
); 
1370                          * drop our last ref on the thread 
1372                         thread_deallocate(tl
->th_thread
); 
1374                         kfree(tl
, sizeof(struct threadlist
)); 
1376                 TAILQ_FOREACH_SAFE(tl
, &wq
->wq_thidlelist
, th_entry
, tlist
) { 
1378                         thread_sched_call(tl
->th_thread
, NULL
); 
1380                         uth 
= get_bsdthread_info(tl
->th_thread
); 
1381                         if (uth 
!= (struct uthread 
*)0) { 
1382                                 uth
->uu_threadlist 
= NULL
; 
1384                         TAILQ_REMOVE(&wq
->wq_thidlelist
, tl
, th_entry
); 
1387                          * drop our last ref on the thread 
1389                         thread_deallocate(tl
->th_thread
); 
1391                         kfree(tl
, sizeof(struct threadlist
)); 
1393                 thread_call_free(wq
->wq_atimer_call
); 
1397                 KERNEL_DEBUG(0x900808c | DBG_FUNC_END
, 0, 0, 0, 0, 0); 
1402 workqueue_additem(struct workqueue 
*wq
, int prio
, user_addr_t item
, int affinity
) 
1404         struct workitem 
*witem
; 
1405         struct workitemlist 
*wl
; 
1407         wl 
= (struct workitemlist 
*)&wq
->wq_list
[prio
]; 
1409         if (TAILQ_EMPTY(&wl
->wl_freelist
)) 
1412         witem 
= (struct workitem 
*)TAILQ_FIRST(&wl
->wl_freelist
); 
1413         TAILQ_REMOVE(&wl
->wl_freelist
, witem
, wi_entry
); 
1415         witem
->wi_item 
= item
; 
1416         witem
->wi_affinity 
= affinity
; 
1417         TAILQ_INSERT_TAIL(&wl
->wl_itemlist
, witem
, wi_entry
); 
1419         wq
->wq_list_bitmap 
|= (1 << prio
); 
1427 workqueue_removeitem(struct workqueue 
*wq
, int prio
, user_addr_t item
) 
1429         struct workitem 
*witem
; 
1430         struct workitemlist 
*wl
; 
1433         wl 
= (struct workitemlist 
*)&wq
->wq_list
[prio
]; 
1435         TAILQ_FOREACH(witem
, &wl
->wl_itemlist
, wi_entry
) { 
1436                 if (witem
->wi_item 
== item
) { 
1437                         TAILQ_REMOVE(&wl
->wl_itemlist
, witem
, wi_entry
); 
1439                         if (TAILQ_EMPTY(&wl
->wl_itemlist
)) 
1440                                 wq
->wq_list_bitmap 
&= ~(1 << prio
); 
1443                         witem
->wi_item 
= (user_addr_t
)0; 
1444                         witem
->wi_affinity 
= 0; 
1445                         TAILQ_INSERT_HEAD(&wl
->wl_freelist
, witem
, wi_entry
); 
1454 static int workqueue_importance
[WORKQUEUE_NUMPRIOS
] =  
1459 static int workqueue_policy
[WORKQUEUE_NUMPRIOS
] =  
1466  * workqueue_run_nextitem: 
1467  *   called with the workqueue lock held... 
1468  *   responsible for dropping it in all cases 
1471 workqueue_run_nextitem(proc_t p
, struct workqueue 
*wq
, thread_t thread
, user_addr_t oc_item
, int oc_prio
, int oc_affinity
) 
1473         struct workitem 
*witem 
= NULL
; 
1474         user_addr_t item 
= 0; 
1475         thread_t th_to_run 
= THREAD_NULL
; 
1476         thread_t th_to_park 
= THREAD_NULL
; 
1477         int wake_thread 
= 0; 
1478         int reuse_thread 
= 1; 
1479         uint32_t priority
, orig_priority
; 
1480         uint32_t affinity_tag
, orig_affinity_tag
; 
1482         uint32_t activecount
; 
1484         uint32_t us_to_wait
; 
1485         struct threadlist 
*tl 
= NULL
; 
1486         struct threadlist 
*ttl 
= NULL
; 
1487         struct uthread 
*uth 
= NULL
; 
1488         struct workitemlist 
*wl 
= NULL
; 
1489         boolean_t start_timer 
= FALSE
; 
1490         boolean_t adjust_counters 
= TRUE
; 
1494         KERNEL_DEBUG(0xefffd000 | DBG_FUNC_START
, wq
, thread
, wq
->wq_thidlecount
, wq
->wq_itemcount
, 0); 
1497          * from here until we drop the workq lock 
1498          * we can't be pre-empted since we hold  
1499          * the lock in spin mode... this is important 
1500          * since we have to independently update the priority 
1501          * and affinity that the thread is associated with 
1502          * and these values are used to index the multi-dimensional 
1503          * counter arrays in 'workqueue_callback' 
1506                 uint32_t min_scheduled 
= 0; 
1507                 uint32_t scheduled_count
; 
1508                 uint32_t active_count
; 
1509                 uint32_t t_affinity 
= 0; 
1514                 if ((affinity_tag 
= oc_affinity
) == (uint32_t)-1) { 
1515                         for (affinity_tag 
= 0; affinity_tag 
< wq
->wq_reqconc
[priority
]; affinity_tag
++) { 
1517                                  * look for the affinity group with the least number of threads 
1519                                 scheduled_count 
= 0; 
1522                                 for (i 
= 0; i 
<= priority
; i
++) { 
1523                                         scheduled_count 
+= wq
->wq_thscheduled_count
[i
][affinity_tag
]; 
1524                                         active_count 
+= wq
->wq_thactive_count
[i
][affinity_tag
]; 
1526                                 if (active_count 
== 0) { 
1527                                         t_affinity 
= affinity_tag
; 
1530                                 if (affinity_tag 
== 0 || scheduled_count 
< min_scheduled
) { 
1531                                         min_scheduled 
= scheduled_count
; 
1532                                         t_affinity 
= affinity_tag
; 
1535                         affinity_tag 
= t_affinity
; 
1537                 goto grab_idle_thread
; 
1539         if (wq
->wq_itemcount 
== 0) { 
1540                 if ((th_to_park 
= thread
) == THREAD_NULL
) 
1544         for (priority 
= 0; priority 
< WORKQUEUE_NUMPRIOS
; priority
++) { 
1545                 if (wq
->wq_list_bitmap 
& (1 << priority
)) { 
1546                         wl 
= (struct workitemlist 
*)&wq
->wq_list
[priority
]; 
1551         assert(!(TAILQ_EMPTY(&wl
->wl_itemlist
))); 
1553         curtime 
= mach_absolute_time(); 
1555         if (thread 
!= THREAD_NULL
) { 
1556                 uth 
= get_bsdthread_info(thread
); 
1557                 tl 
= uth
->uu_threadlist
; 
1558                 affinity_tag 
= tl
->th_affinity_tag
; 
1561                  * check to see if the affinity group this thread is 
1562                  * associated with is still within the bounds of the 
1563                  * specified concurrency for the priority level 
1564                  * we're considering running work for 
1566                 if (affinity_tag 
< wq
->wq_reqconc
[priority
]) { 
1568                          * we're a worker thread from the pool... currently we 
1569                          * are considered 'active' which means we're counted 
1570                          * in "wq_thactive_count" 
1571                          * add up the active counts of all the priority levels 
1572                          * up to and including the one we want to schedule 
1574                         for (activecount 
= 0, i 
= 0; i 
<= priority
; i
++) { 
1577                                 acount 
= wq
->wq_thactive_count
[i
][affinity_tag
]; 
1579                                 if (acount 
== 0 && wq
->wq_thscheduled_count
[i
][affinity_tag
]) { 
1580                                         if (wq_thread_is_busy(curtime
, &wq
->wq_lastblocked_ts
[i
][affinity_tag
])) 
1583                                 activecount 
+= acount
; 
1585                         if (activecount 
== 1) { 
1587                                  * we're the only active thread associated with our 
1588                                  * affinity group at this priority level and higher, 
1589                                  * so pick up some work and keep going 
1596                  * there's more than 1 thread running in this affinity group 
1597                  * or the concurrency level has been cut back for this priority... 
1598                  * lets continue on and look for an 'empty' group to run this 
1604         for (affinity_tag 
= 0; affinity_tag 
< wq
->wq_reqconc
[priority
]; affinity_tag
++) { 
1606                  * look for first affinity group that is currently not active 
1607                  * i.e. no active threads at this priority level or higher 
1608                  * and no threads that have run recently 
1610                 for (activecount 
= 0, i 
= 0; i 
<= priority
; i
++) { 
1611                         if ((activecount 
= wq
->wq_thactive_count
[i
][affinity_tag
])) 
1614                         if (wq
->wq_thscheduled_count
[i
][affinity_tag
]) { 
1615                                 if (wq_thread_is_busy(curtime
, &wq
->wq_lastblocked_ts
[i
][affinity_tag
])) { 
1621                 if (activecount 
== 0 && busycount 
== 0) 
1624         if (affinity_tag 
>= wq
->wq_reqconc
[priority
]) { 
1626                  * we've already got at least 1 thread per 
1627                  * affinity group in the active state... 
1631                          * we found at least 1 thread in the 
1632                          * 'busy' state... make sure we start 
1633                          * the timer because if they are the only 
1634                          * threads keeping us from scheduling 
1635                          * this workitem, we won't get a callback 
1636                          * to kick off the timer... we need to 
1639                         WQ_TIMER_NEEDED(wq
, start_timer
); 
1641                 KERNEL_DEBUG(0xefffd000 | DBG_FUNC_NONE
, wq
, busycount
, start_timer
, 0, 0); 
1643                 if (thread 
!= THREAD_NULL
) { 
1645                          * go park this one for later 
1647                         th_to_park 
= thread
; 
1652         if (thread 
!= THREAD_NULL
) { 
1654                  * we're overbooked on the affinity group this thread is 
1655                  * currently associated with, but we have work to do 
1656                  * and at least 1 idle processor, so we'll just retarget 
1657                  * this thread to a new affinity group 
1662         if (wq
->wq_thidlecount 
== 0) { 
1664                  * we don't have a thread to schedule, but we have 
1665                  * work to do and at least 1 affinity group that  
1666                  * doesn't currently have an active thread...  
1668                 WQ_TIMER_NEEDED(wq
, start_timer
); 
1670                 KERNEL_DEBUG(0xefffd118, wq
, wq
->wq_nthreads
, start_timer
, 0, 0); 
1672                 goto no_thread_to_run
; 
1677          * we've got a candidate (affinity group with no currently 
1678          * active threads) to start a new thread on... 
1679          * we already know there is both work available 
1680          * and an idle thread, so activate a thread and then 
1681          * fall into the code that pulls a new workitem... 
1683         TAILQ_FOREACH(ttl
, &wq
->wq_thidlelist
, th_entry
) { 
1684                 if (ttl
->th_affinity_tag 
== affinity_tag 
|| ttl
->th_affinity_tag 
== (uint16_t)-1) { 
1686                         TAILQ_REMOVE(&wq
->wq_thidlelist
, ttl
, th_entry
); 
1693                 tl 
= TAILQ_FIRST(&wq
->wq_thidlelist
); 
1694                 TAILQ_REMOVE(&wq
->wq_thidlelist
, tl
, th_entry
); 
1696         wq
->wq_thidlecount
--; 
1698         TAILQ_INSERT_TAIL(&wq
->wq_thrunlist
, tl
, th_entry
); 
1700         if ((tl
->th_flags 
& TH_LIST_SUSPENDED
) == TH_LIST_SUSPENDED
) { 
1701                 tl
->th_flags 
&= ~TH_LIST_SUSPENDED
; 
1704         } else if ((tl
->th_flags 
& TH_LIST_BLOCKED
) == TH_LIST_BLOCKED
) { 
1705                 tl
->th_flags 
&= ~TH_LIST_BLOCKED
; 
1708         tl
->th_flags 
|= TH_LIST_RUNNING 
| TH_LIST_BUSY
; 
1710         wq
->wq_threads_scheduled
++; 
1711         wq
->wq_thscheduled_count
[priority
][affinity_tag
]++; 
1712         OSAddAtomic(1, &wq
->wq_thactive_count
[priority
][affinity_tag
]); 
1714         adjust_counters 
= FALSE
; 
1715         th_to_run 
= tl
->th_thread
; 
1719                 witem 
= TAILQ_FIRST(&wl
->wl_itemlist
); 
1720                 TAILQ_REMOVE(&wl
->wl_itemlist
, witem
, wi_entry
); 
1722                 if (TAILQ_EMPTY(&wl
->wl_itemlist
)) 
1723                         wq
->wq_list_bitmap 
&= ~(1 << priority
); 
1726                 item 
= witem
->wi_item
; 
1727                 witem
->wi_item 
= (user_addr_t
)0; 
1728                 witem
->wi_affinity 
= 0; 
1729                 TAILQ_INSERT_HEAD(&wl
->wl_freelist
, witem
, wi_entry
); 
1731         orig_priority 
= tl
->th_priority
; 
1732         orig_affinity_tag 
= tl
->th_affinity_tag
; 
1734         tl
->th_priority 
= priority
; 
1735         tl
->th_affinity_tag 
= affinity_tag
; 
1737         if (adjust_counters 
== TRUE 
&& (orig_priority 
!= priority 
|| orig_affinity_tag 
!= affinity_tag
)) { 
1739                  * we need to adjust these counters based on this 
1740                  * thread's new disposition w/r to affinity and priority 
1742                 OSAddAtomic(-1, &wq
->wq_thactive_count
[orig_priority
][orig_affinity_tag
]); 
1743                 OSAddAtomic(1, &wq
->wq_thactive_count
[priority
][affinity_tag
]); 
1745                 wq
->wq_thscheduled_count
[orig_priority
][orig_affinity_tag
]--; 
1746                 wq
->wq_thscheduled_count
[priority
][affinity_tag
]++; 
1748         wq
->wq_thread_yielded_count 
= 0; 
1750         workqueue_unlock(p
); 
1752         if (orig_affinity_tag 
!= affinity_tag
) { 
1754                  * this thread's affinity does not match the affinity group 
1755                  * its being placed on (it's either a brand new thread or 
1756                  * we're retargeting an existing thread to a new group)... 
1757                  * affinity tag of 0 means no affinity... 
1758                  * but we want our tags to be 0 based because they 
1759                  * are used to index arrays, so... 
1760                  * keep it 0 based internally and bump by 1 when 
1761                  * calling out to set it 
1763                 KERNEL_DEBUG(0xefffd114 | DBG_FUNC_START
, wq
, orig_affinity_tag
, 0, 0, 0); 
1765                 (void)thread_affinity_set(th_to_run
, affinity_tag 
+ 1); 
1767                 KERNEL_DEBUG(0xefffd114 | DBG_FUNC_END
, wq
, affinity_tag
, 0, 0, 0); 
1769         if (orig_priority 
!= priority
) { 
1770                 thread_precedence_policy_data_t precedinfo
; 
1771                 thread_extended_policy_data_t   extinfo
; 
1774                 policy 
= workqueue_policy
[priority
]; 
1776                 KERNEL_DEBUG(0xefffd120 | DBG_FUNC_START
, wq
, orig_priority
, tl
->th_policy
, 0, 0); 
1778                 if (tl
->th_policy 
!= policy
) { 
1780                         extinfo
.timeshare 
= policy
; 
1781                         (void)thread_policy_set_internal(th_to_run
, THREAD_EXTENDED_POLICY
, (thread_policy_t
)&extinfo
, THREAD_EXTENDED_POLICY_COUNT
); 
1783                         tl
->th_policy 
= policy
; 
1785                 precedinfo
.importance 
= workqueue_importance
[priority
]; 
1786                 (void)thread_policy_set_internal(th_to_run
, THREAD_PRECEDENCE_POLICY
, (thread_policy_t
)&precedinfo
, THREAD_PRECEDENCE_POLICY_COUNT
); 
1788                 KERNEL_DEBUG(0xefffd120 | DBG_FUNC_END
, wq
,  priority
, policy
, 0, 0); 
1790         if (kdebug_enable
) { 
1794                 uint32_t  code 
= 0xefffd02c | DBG_FUNC_START
; 
1796                 for (n 
= 0; n 
< WORKQUEUE_NUMPRIOS
; n
++) { 
1797                         for (i 
= 0; i 
< wq
->wq_affinity_max
; i
++) { 
1798                                 if (wq
->wq_thactive_count
[n
][i
]) { 
1800                                                 KERNEL_DEBUG(code
, lpri
, laffinity
, wq
->wq_thactive_count
[lpri
][laffinity
], first
, 0); 
1812                         KERNEL_DEBUG(0xefffd02c | DBG_FUNC_END
, lpri
, laffinity
, wq
->wq_thactive_count
[lpri
][laffinity
], first
, 0); 
1816          * if current thread is reused for workitem, does not return via unix_syscall 
1818         wq_runitem(p
, item
, th_to_run
, tl
, reuse_thread
, wake_thread
, (thread 
== th_to_run
)); 
1820         KERNEL_DEBUG(0xefffd000 | DBG_FUNC_END
, wq
, thread_tid(th_to_run
), item
, 1, 0); 
1826          * we have no work to do or we are fully booked 
1827          * w/r to running threads... 
1830         workqueue_unlock(p
); 
1833                 workqueue_interval_timer_start(wq
); 
1835         KERNEL_DEBUG(0xefffd000 | DBG_FUNC_END
, wq
, thread_tid(thread
), 0, 2, 0); 
1841          * this is a workqueue thread with no more 
1842          * work to do... park it for now 
1844         uth 
= get_bsdthread_info(th_to_park
); 
1845         tl 
= uth
->uu_threadlist
; 
1847                 panic("wq thread with no threadlist "); 
1849         TAILQ_REMOVE(&wq
->wq_thrunlist
, tl
, th_entry
); 
1850         tl
->th_flags 
&= ~TH_LIST_RUNNING
; 
1852         tl
->th_flags 
|= TH_LIST_BLOCKED
; 
1853         TAILQ_INSERT_HEAD(&wq
->wq_thidlelist
, tl
, th_entry
); 
1855         thread_sched_call(th_to_park
, NULL
); 
1857         OSAddAtomic(-1, &wq
->wq_thactive_count
[tl
->th_priority
][tl
->th_affinity_tag
]); 
1858         wq
->wq_thscheduled_count
[tl
->th_priority
][tl
->th_affinity_tag
]--; 
1859         wq
->wq_threads_scheduled
--; 
1861         if (wq
->wq_thidlecount 
< 100) 
1862                 us_to_wait 
= wq_reduce_pool_window_usecs 
- (wq
->wq_thidlecount 
* (wq_reduce_pool_window_usecs 
/ 100)); 
1864                 us_to_wait 
= wq_reduce_pool_window_usecs 
/ 100; 
1866         wq
->wq_thidlecount
++; 
1868         assert_wait_timeout((caddr_t
)tl
, (THREAD_INTERRUPTIBLE
), us_to_wait
, NSEC_PER_USEC
); 
1870         workqueue_unlock(p
); 
1873                 workqueue_interval_timer_start(wq
); 
1875         KERNEL_DEBUG1(0xefffd018 | DBG_FUNC_START
, wq
, wq
->wq_threads_scheduled
, wq
->wq_thidlecount
, us_to_wait
, thread_tid(th_to_park
)); 
1876         KERNEL_DEBUG(0xefffd000 | DBG_FUNC_END
, wq
, thread_tid(thread
), 0, 3, 0); 
1878         thread_block((thread_continue_t
)wq_unpark_continue
); 
1886 wq_unsuspend_continue(void) 
1888         struct uthread 
*uth 
= NULL
; 
1889         thread_t th_to_unsuspend
; 
1890         struct threadlist 
*tl
; 
1893         th_to_unsuspend 
= current_thread(); 
1894         uth 
= get_bsdthread_info(th_to_unsuspend
); 
1896         if (uth 
!= NULL 
&& (tl 
= uth
->uu_threadlist
) != NULL
) { 
1898                 if ((tl
->th_flags 
& (TH_LIST_RUNNING 
| TH_LIST_BUSY
)) == TH_LIST_RUNNING
) { 
1900                          * most likely a normal resume of this thread occurred... 
1901                          * it's also possible that the thread was aborted after we 
1902                          * finished setting it up so that it could be dispatched... if 
1903                          * so, thread_bootstrap_return will notice the abort and put 
1904                          * the thread on the path to self-destruction 
1906 normal_resume_to_user
: 
1907                         thread_sched_call(th_to_unsuspend
, workqueue_callback
); 
1909                         thread_bootstrap_return(); 
1912                  * if we get here, it's because we've been resumed due to 
1913                  * an abort of this thread (process is crashing) 
1917                 workqueue_lock_spin(p
); 
1919                 if (tl
->th_flags 
& TH_LIST_SUSPENDED
) { 
1921                          * thread has been aborted while still on our idle 
1922                          * queue... remove it from our domain... 
1923                          * workqueue_removethread consumes the lock 
1925                         workqueue_removethread(tl
); 
1927                         thread_bootstrap_return(); 
1929                 while ((tl
->th_flags 
& TH_LIST_BUSY
)) { 
1931                          * this thread was aborted after we started making 
1932                          * it runnable, but before we finished dispatching it... 
1933                          * we need to wait for that process to finish, 
1934                          * and we need to ask for a wakeup instead of a 
1935                          * thread_resume since the abort has already resumed us 
1937                         tl
->th_flags 
|= TH_LIST_NEED_WAKEUP
; 
1939                         assert_wait((caddr_t
)tl
, (THREAD_UNINT
)); 
1941                         workqueue_unlock(p
); 
1943                         thread_block(THREAD_CONTINUE_NULL
); 
1945                         workqueue_lock_spin(p
); 
1947                 workqueue_unlock(p
); 
1949                  * we have finished setting up the thread's context... 
1950                  * thread_bootstrap_return will take us through the abort path 
1951                  * where the thread will self destruct 
1953                 goto normal_resume_to_user
; 
1955         thread_bootstrap_return(); 
1960 wq_unpark_continue(void) 
1962         struct uthread 
*uth 
= NULL
; 
1963         struct threadlist 
*tl
; 
1964         thread_t th_to_unpark
; 
1967         th_to_unpark 
= current_thread(); 
1968         uth 
= get_bsdthread_info(th_to_unpark
); 
1971                 if ((tl 
= uth
->uu_threadlist
) != NULL
) { 
1973                         if ((tl
->th_flags 
& (TH_LIST_RUNNING 
| TH_LIST_BUSY
)) == TH_LIST_RUNNING
) { 
1975                                  * a normal wakeup of this thread occurred... no need  
1976                                  * for any synchronization with the timer and wq_runitem 
1978 normal_return_to_user
:                   
1979                                 thread_sched_call(th_to_unpark
, workqueue_callback
); 
1981                                 KERNEL_DEBUG(0xefffd018 | DBG_FUNC_END
, tl
->th_workq
, 0, 0, 0, 0); 
1983                                 thread_exception_return(); 
1987                         workqueue_lock_spin(p
); 
1989                         if ( !(tl
->th_flags 
& TH_LIST_RUNNING
)) { 
1991                                  * the timer popped us out and we've not 
1992                                  * been moved off of the idle list 
1993                                  * so we should now self-destruct 
1995                                  * workqueue_removethread consumes the lock 
1997                                 workqueue_removethread(tl
); 
1999                                 thread_exception_return(); 
2002                          * the timer woke us up, but we have already 
2003                          * started to make this a runnable thread, 
2004                          * but have not yet finished that process... 
2005                          * so wait for the normal wakeup 
2007                         while ((tl
->th_flags 
& TH_LIST_BUSY
)) { 
2009                                 assert_wait((caddr_t
)tl
, (THREAD_UNINT
)); 
2011                                 workqueue_unlock(p
); 
2013                                 thread_block(THREAD_CONTINUE_NULL
); 
2015                                 workqueue_lock_spin(p
); 
2018                          * we have finished setting up the thread's context 
2019                          * now we can return as if we got a normal wakeup 
2021                         workqueue_unlock(p
); 
2023                         goto normal_return_to_user
; 
2026         thread_exception_return(); 
2032 wq_runitem(proc_t p
, user_addr_t item
, thread_t th
, struct threadlist 
*tl
, 
2033            int reuse_thread
, int wake_thread
, int return_directly
) 
2037         KERNEL_DEBUG1(0xefffd004 | DBG_FUNC_START
, tl
->th_workq
, tl
->th_priority
, tl
->th_affinity_tag
, thread_tid(current_thread()), thread_tid(th
)); 
2039         ret 
= setup_wqthread(p
, th
, item
, reuse_thread
, tl
); 
2042                 panic("setup_wqthread failed  %x\n", ret
); 
2044         if (return_directly
) { 
2045                 KERNEL_DEBUG(0xefffd000 | DBG_FUNC_END
, tl
->th_workq
, 0, 0, 4, 0); 
2047                 thread_exception_return(); 
2049                 panic("wq_runitem: thread_exception_return returned ...\n"); 
2052                 workqueue_lock_spin(p
); 
2054                 tl
->th_flags 
&= ~TH_LIST_BUSY
; 
2057                 workqueue_unlock(p
); 
2059                 KERNEL_DEBUG1(0xefffd014 | DBG_FUNC_END
, tl
->th_workq
, 0, 0, thread_tid(current_thread()), thread_tid(th
)); 
2061                 workqueue_lock_spin(p
); 
2063                 if (tl
->th_flags 
& TH_LIST_NEED_WAKEUP
) 
2068                 tl
->th_flags 
&= ~(TH_LIST_BUSY 
| TH_LIST_NEED_WAKEUP
); 
2070                 workqueue_unlock(p
); 
2075 setup_wqthread(proc_t p
, thread_t th
, user_addr_t item
, int reuse_thread
, struct threadlist 
*tl
) 
2077 #if defined(__ppc__) 
2079          * Set up PowerPC registers... 
2080          * internally they are always kept as 64 bit and 
2081          * since the register set is the same between 32 and 64bit modes 
2082          * we don't need 2 different methods for setting the state 
2085                 ppc_thread_state64_t state64
; 
2086                 ppc_thread_state64_t 
*ts64 
= &state64
; 
2088                 ts64
->srr0 
= (uint64_t)p
->p_wqthread
; 
2089                 ts64
->r1 
= (uint64_t)((tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
) - C_ARGSAVE_LEN 
- C_RED_ZONE
); 
2090                 ts64
->r3 
= (uint64_t)(tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
); 
2091                 ts64
->r4 
= (uint64_t)(tl
->th_thport
); 
2092                 ts64
->r5 
= (uint64_t)(tl
->th_stackaddr 
+ PTH_DEFAULT_GUARDSIZE
); 
2093                 ts64
->r6 
= (uint64_t)item
; 
2094                 ts64
->r7 
= (uint64_t)reuse_thread
; 
2095                 ts64
->r8 
= (uint64_t)0; 
2097                 if ((reuse_thread 
!= 0) && (ts64
->r3 
== (uint64_t)0)) 
2098                         panic("setup_wqthread: setting reuse thread with null pthread\n"); 
2099                 thread_set_wq_state64(th
, (thread_state_t
)ts64
); 
2101 #elif defined(__i386__) || defined(__x86_64__) 
2104         isLP64 
= IS_64BIT_PROCESS(p
); 
2106          * Set up i386 registers & function call. 
2109                 x86_thread_state32_t state
; 
2110                 x86_thread_state32_t 
*ts 
= &state
; 
2112                 ts
->eip 
= (int)p
->p_wqthread
; 
2113                 ts
->eax 
= (unsigned int)(tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
); 
2114                 ts
->ebx 
= (unsigned int)tl
->th_thport
; 
2115                 ts
->ecx 
= (unsigned int)(tl
->th_stackaddr 
+ PTH_DEFAULT_GUARDSIZE
); 
2116                 ts
->edx 
= (unsigned int)item
; 
2117                 ts
->edi 
= (unsigned int)reuse_thread
; 
2118                 ts
->esi 
= (unsigned int)0; 
2122                 ts
->esp 
= (int)((vm_offset_t
)((tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
) - C_32_STK_ALIGN
)); 
2124                 if ((reuse_thread 
!= 0) && (ts
->eax 
== (unsigned int)0)) 
2125                         panic("setup_wqthread: setting reuse thread with null pthread\n"); 
2126                 thread_set_wq_state32(th
, (thread_state_t
)ts
); 
2129                 x86_thread_state64_t state64
; 
2130                 x86_thread_state64_t 
*ts64 
= &state64
; 
2132                 ts64
->rip 
= (uint64_t)p
->p_wqthread
; 
2133                 ts64
->rdi 
= (uint64_t)(tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
); 
2134                 ts64
->rsi 
= (uint64_t)(tl
->th_thport
); 
2135                 ts64
->rdx 
= (uint64_t)(tl
->th_stackaddr 
+ PTH_DEFAULT_GUARDSIZE
); 
2136                 ts64
->rcx 
= (uint64_t)item
; 
2137                 ts64
->r8 
= (uint64_t)reuse_thread
; 
2138                 ts64
->r9 
= (uint64_t)0; 
2141                  * set stack pointer aligned to 16 byte boundary 
2143                 ts64
->rsp 
= (uint64_t)((tl
->th_stackaddr 
+ PTH_DEFAULT_STACKSIZE 
+ PTH_DEFAULT_GUARDSIZE
) - C_64_REDZONE_LEN
); 
2145                 if ((reuse_thread 
!= 0) && (ts64
->rdi 
== (uint64_t)0)) 
2146                         panic("setup_wqthread: setting reuse thread with null pthread\n"); 
2147                 thread_set_wq_state64(th
, (thread_state_t
)ts64
); 
2150 #error setup_wqthread  not defined for this architecture 
2156 fill_procworkqueue(proc_t p
, struct proc_workqueueinfo 
* pwqinfo
) 
2158         struct workqueue 
* wq
; 
2161         uint32_t pri
, affinity
; 
2163         workqueue_lock_spin(p
); 
2164         if ((wq 
= p
->p_wqptr
) == NULL
) { 
2170         for (pri 
= 0; pri 
< WORKQUEUE_NUMPRIOS
; pri
++) { 
2171                 for (affinity 
= 0; affinity 
< wq
->wq_affinity_max
; affinity
++) 
2172                         activecount 
+= wq
->wq_thactive_count
[pri
][affinity
]; 
2174         pwqinfo
->pwq_nthreads 
= wq
->wq_nthreads
; 
2175         pwqinfo
->pwq_runthreads 
= activecount
; 
2176         pwqinfo
->pwq_blockedthreads 
= wq
->wq_threads_scheduled 
- activecount
; 
2178         workqueue_unlock(p
); 
2182 /* Set target concurrency of one of the  queue(0,1,2) with specified value */ 
2184 proc_settargetconc(pid_t pid
, int queuenum
, int32_t targetconc
) 
2188         int32_t conc 
= targetconc
; 
2190         vm_map_t oldmap 
= VM_MAP_NULL
; 
2193         self 
= current_proc(); 
2194         if (self
->p_pid 
!= pid
) { 
2195                 /* if not on self, hold a refernce on the process */ 
2209         if ((addr 
= p
->p_targconc
) == (uint64_t)0) { 
2215         if ((queuenum 
>= WQ_MAXPRI_MIN
) && (queuenum 
<= WQ_MAXPRI_MAX
)) { 
2216                 addr 
+= (queuenum 
* sizeof(int32_t)); 
2218                         oldmap 
= vm_map_switch(get_task_map(p
->task
)); 
2219                 error 
= copyout(&conc
, addr
, sizeof(int32_t)); 
2221                         (void)vm_map_switch(oldmap
); 
2233 /* Set target concurrency on all the prio queues with specified value */ 
2235 proc_setalltargetconc(pid_t pid
, int32_t * targetconcp
) 
2240         vm_map_t oldmap 
= VM_MAP_NULL
; 
2243         self 
= current_proc(); 
2244         if (self
->p_pid 
!= pid
) { 
2245                 /* if not on self, hold a refernce on the process */ 
2259         if ((addr 
= (uint64_t)p
->p_targconc
) == (uint64_t)0) { 
2266                 oldmap 
= vm_map_switch(get_task_map(p
->task
)); 
2268         error 
= copyout(targetconcp
, addr
, WQ_PRI_NUM 
* sizeof(int32_t)); 
2270                 (void)vm_map_switch(oldmap
); 
2278 int thread_selfid(__unused 
struct proc 
*p
, __unused 
struct thread_selfid_args 
*uap
, user_addr_t 
*retval
) 
2280         thread_t                thread 
= current_thread(); 
2281         uint64_t                thread_id 
= thread_tid(thread
); 
2282         *retval 
= thread_id
; 
2283         return KERN_SUCCESS
; 
2289         pthread_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
2290         pthread_lck_grp 
= lck_grp_alloc_init("pthread", pthread_lck_grp_attr
); 
2293          * allocate the lock attribute for pthread synchronizers 
2295         pthread_lck_attr 
= lck_attr_alloc_init(); 
2297         workqueue_init_lock((proc_t
) get_bsdtask_info(kernel_task
)); 
2299         pthread_list_mlock 
= lck_mtx_alloc_init(pthread_lck_grp
, pthread_lck_attr
); 
2301         pth_global_hashinit(); 
2302         psynch_thcall 
= thread_call_allocate(psynch_wq_cleanup
, NULL
);