/* * Routine: convert_port_to_task_suspension_token * Purpose: * Convert from a port to a task suspension token. * Doesn't consume the port ref; produces a suspension token ref, * which may be null. * Conditions: * Nothing locked. */ task_suspension_token_t convert_port_to_task_suspension_token( ipc_port_t port) { task_suspension_token_t task = TASK_NULL; if (IP_VALID(port)) { ip_lock(port); if ( ip_active(port) && ip_kotype(port) == IKOT_TASK_RESUME) { task = (task_suspension_token_t)port->ip_kobject; assert(task != TASK_NULL); task_reference_internal(task); } ip_unlock(port); } return (task); }
/* * Routine: convert_port_to_task_name * Purpose: * Convert from a port to a task name. * Doesn't consume the port ref; produces a task name ref, * which may be null. * Conditions: * Nothing locked. */ task_name_t convert_port_to_task_name( ipc_port_t port) { task_name_t task = TASK_NULL; if (IP_VALID(port)) { ip_lock(port); if ( ip_active(port) && (ip_kotype(port) == IKOT_TASK || ip_kotype(port) == IKOT_TASK_NAME)) { task = (task_name_t)port->ip_kobject; assert(task != TASK_NAME_NULL); task_reference_internal(task); } ip_unlock(port); } return (task); }
/* * Create a new thread. * Doesn't start the thread running. */ static kern_return_t thread_create_internal( task_t parent_task, integer_t priority, thread_continue_t continuation, int options, #define TH_OPTION_NONE 0x00 #define TH_OPTION_NOCRED 0x01 #define TH_OPTION_NOSUSP 0x02 thread_t *out_thread) { thread_t new_thread; static thread_t first_thread = THREAD_NULL; /* * Allocate a thread and initialize static fields */ if (first_thread == THREAD_NULL) new_thread = first_thread = current_thread(); new_thread = (thread_t)zalloc(thread_zone); if (new_thread == THREAD_NULL) return (KERN_RESOURCE_SHORTAGE); if (new_thread != first_thread) *new_thread = thread_template; #ifdef MACH_BSD new_thread->uthread = uthread_alloc(parent_task, new_thread, (options & TH_OPTION_NOCRED) != 0); if (new_thread->uthread == NULL) { zfree(thread_zone, new_thread); return (KERN_RESOURCE_SHORTAGE); } #endif /* MACH_BSD */ if (machine_thread_create(new_thread, parent_task) != KERN_SUCCESS) { #ifdef MACH_BSD void *ut = new_thread->uthread; new_thread->uthread = NULL; /* cred free may not be necessary */ uthread_cleanup(parent_task, ut, parent_task->bsd_info); uthread_cred_free(ut); uthread_zone_free(ut); #endif /* MACH_BSD */ zfree(thread_zone, new_thread); return (KERN_FAILURE); } new_thread->task = parent_task; thread_lock_init(new_thread); wake_lock_init(new_thread); lck_mtx_init(&new_thread->mutex, &thread_lck_grp, &thread_lck_attr); ipc_thread_init(new_thread); queue_init(&new_thread->held_ulocks); new_thread->continuation = continuation; lck_mtx_lock(&tasks_threads_lock); task_lock(parent_task); if ( !parent_task->active || parent_task->halting || ((options & TH_OPTION_NOSUSP) != 0 && parent_task->suspend_count > 0) || (parent_task->thread_count >= task_threadmax && parent_task != kernel_task) ) { task_unlock(parent_task); lck_mtx_unlock(&tasks_threads_lock); #ifdef MACH_BSD { void *ut = new_thread->uthread; new_thread->uthread = NULL; uthread_cleanup(parent_task, ut, parent_task->bsd_info); /* cred free may not be necessary */ uthread_cred_free(ut); uthread_zone_free(ut); } #endif /* MACH_BSD */ ipc_thread_disable(new_thread); ipc_thread_terminate(new_thread); lck_mtx_destroy(&new_thread->mutex, &thread_lck_grp); machine_thread_destroy(new_thread); zfree(thread_zone, new_thread); return (KERN_FAILURE); } /* New threads inherit any default state on the task */ machine_thread_inherit_taskwide(new_thread, parent_task); task_reference_internal(parent_task); if (new_thread->task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) { /* * This task has a per-thread CPU limit; make sure this new thread * gets its limit set too, before it gets out of the kernel. */ set_astledger(new_thread); } new_thread->t_threadledger = LEDGER_NULL; /* per thread ledger is not inherited */ new_thread->t_ledger = new_thread->task->ledger; if (new_thread->t_ledger) ledger_reference(new_thread->t_ledger); /* Cache the task's map */ new_thread->map = parent_task->map; /* Chain the thread onto the task's list */ queue_enter(&parent_task->threads, new_thread, thread_t, task_threads); parent_task->thread_count++; /* So terminating threads don't need to take the task lock to decrement */ hw_atomic_add(&parent_task->active_thread_count, 1); /* Protected by the tasks_threads_lock */ new_thread->thread_id = ++thread_unique_id; queue_enter(&threads, new_thread, thread_t, threads); threads_count++; timer_call_setup(&new_thread->wait_timer, thread_timer_expire, new_thread); timer_call_setup(&new_thread->depress_timer, thread_depress_expire, new_thread); #if CONFIG_COUNTERS /* * If parent task has any reservations, they need to be propagated to this * thread. */ new_thread->t_chud = (TASK_PMC_FLAG == (parent_task->t_chud & TASK_PMC_FLAG)) ? THREAD_PMC_FLAG : 0U; #endif /* Set the thread's scheduling parameters */ new_thread->sched_mode = SCHED(initial_thread_sched_mode)(parent_task); new_thread->sched_flags = 0; new_thread->max_priority = parent_task->max_priority; new_thread->task_priority = parent_task->priority; new_thread->priority = (priority < 0)? parent_task->priority: priority; if (new_thread->priority > new_thread->max_priority) new_thread->priority = new_thread->max_priority; #if CONFIG_EMBEDDED if (new_thread->priority < MAXPRI_THROTTLE) { new_thread->priority = MAXPRI_THROTTLE; } #endif /* CONFIG_EMBEDDED */ new_thread->importance = new_thread->priority - new_thread->task_priority; #if CONFIG_EMBEDDED new_thread->saved_importance = new_thread->importance; /* apple ios daemon starts all threads in darwin background */ if (parent_task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) { /* Cannot use generic routines here so apply darwin bacground directly */ new_thread->policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL; /* set thread self backgrounding */ new_thread->appliedstate.hw_bg = new_thread->policystate.hw_bg; /* priority will get recomputed suitably bit later */ new_thread->importance = INT_MIN; /* to avoid changes to many pri compute routines, set the effect of those here */ new_thread->priority = MAXPRI_THROTTLE; } #endif /* CONFIG_EMBEDDED */ #if defined(CONFIG_SCHED_TRADITIONAL) new_thread->sched_stamp = sched_tick; new_thread->pri_shift = sched_pri_shift; #endif SCHED(compute_priority)(new_thread, FALSE); new_thread->active = TRUE; *out_thread = new_thread; { long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; kdbg_trace_data(parent_task->bsd_info, &dbg_arg2); KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, TRACEDBG_CODE(DBG_TRACE_DATA, 1) | DBG_FUNC_NONE, (vm_address_t)(uintptr_t)thread_tid(new_thread), dbg_arg2, 0, 0, 0); kdbg_trace_string(parent_task->bsd_info, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4); KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, TRACEDBG_CODE(DBG_TRACE_STRING, 1) | DBG_FUNC_NONE, dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); } DTRACE_PROC1(lwp__create, thread_t, *out_thread); return (KERN_SUCCESS); }
/* * Create a new thread. * Doesn't start the thread running. */ static kern_return_t thread_create_internal( task_t parent_task, integer_t priority, thread_continue_t continuation, thread_t *out_thread) { thread_t new_thread; static thread_t first_thread; /* * Allocate a thread and initialize static fields */ if (first_thread == NULL) new_thread = first_thread = current_thread(); else new_thread = (thread_t)zalloc(thread_zone); if (new_thread == NULL) return (KERN_RESOURCE_SHORTAGE); if (new_thread != first_thread) *new_thread = thread_template; #ifdef MACH_BSD { new_thread->uthread = uthread_alloc(parent_task, new_thread); if (new_thread->uthread == NULL) { zfree(thread_zone, new_thread); return (KERN_RESOURCE_SHORTAGE); } } #endif /* MACH_BSD */ if (machine_thread_create(new_thread, parent_task) != KERN_SUCCESS) { #ifdef MACH_BSD { void *ut = new_thread->uthread; new_thread->uthread = NULL; /* cred free may not be necessary */ uthread_cleanup(parent_task, ut, parent_task->bsd_info); uthread_cred_free(ut); uthread_zone_free(ut); } #endif /* MACH_BSD */ zfree(thread_zone, new_thread); return (KERN_FAILURE); } new_thread->task = parent_task; thread_lock_init(new_thread); wake_lock_init(new_thread); mutex_init(&new_thread->mutex, 0); ipc_thread_init(new_thread); queue_init(&new_thread->held_ulocks); new_thread->continuation = continuation; mutex_lock(&tasks_threads_lock); task_lock(parent_task); if ( !parent_task->active || (parent_task->thread_count >= THREAD_MAX && parent_task != kernel_task)) { task_unlock(parent_task); mutex_unlock(&tasks_threads_lock); #ifdef MACH_BSD { void *ut = new_thread->uthread; new_thread->uthread = NULL; uthread_cleanup(parent_task, ut, parent_task->bsd_info); /* cred free may not be necessary */ uthread_cred_free(ut); uthread_zone_free(ut); } #endif /* MACH_BSD */ ipc_thread_disable(new_thread); ipc_thread_terminate(new_thread); machine_thread_destroy(new_thread); zfree(thread_zone, new_thread); return (KERN_FAILURE); } task_reference_internal(parent_task); /* Cache the task's map */ new_thread->map = parent_task->map; /* Chain the thread onto the task's list */ queue_enter(&parent_task->threads, new_thread, thread_t, task_threads); parent_task->thread_count++; /* So terminating threads don't need to take the task lock to decrement */ hw_atomic_add(&parent_task->active_thread_count, 1); queue_enter(&threads, new_thread, thread_t, threads); threads_count++; timer_call_setup(&new_thread->wait_timer, thread_timer_expire, new_thread); timer_call_setup(&new_thread->depress_timer, thread_depress_expire, new_thread); /* Set the thread's scheduling parameters */ if (parent_task != kernel_task) new_thread->sched_mode |= TH_MODE_TIMESHARE; new_thread->max_priority = parent_task->max_priority; new_thread->task_priority = parent_task->priority; new_thread->priority = (priority < 0)? parent_task->priority: priority; if (new_thread->priority > new_thread->max_priority) new_thread->priority = new_thread->max_priority; new_thread->importance = new_thread->priority - new_thread->task_priority; new_thread->sched_stamp = sched_tick; new_thread->pri_shift = sched_pri_shift; compute_priority(new_thread, FALSE); new_thread->active = TRUE; *out_thread = new_thread; { long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; kdbg_trace_data(parent_task->bsd_info, &dbg_arg2); KERNEL_DEBUG_CONSTANT( TRACEDBG_CODE(DBG_TRACE_DATA, 1) | DBG_FUNC_NONE, (vm_address_t)new_thread, dbg_arg2, 0, 0, 0); kdbg_trace_string(parent_task->bsd_info, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4); KERNEL_DEBUG_CONSTANT( TRACEDBG_CODE(DBG_TRACE_STRING, 1) | DBG_FUNC_NONE, dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); } DTRACE_PROC1(lwp__create, thread_t, *out_thread); return (KERN_SUCCESS); }
/* * Create a new thread. * Doesn't start the thread running. */ static kern_return_t thread_create_internal( task_t parent_task, integer_t priority, thread_continue_t continuation, int options, #define TH_OPTION_NONE 0x00 #define TH_OPTION_NOCRED 0x01 #define TH_OPTION_NOSUSP 0x02 thread_t *out_thread) { thread_t new_thread; static thread_t first_thread; /* * Allocate a thread and initialize static fields */ if (first_thread == THREAD_NULL) new_thread = first_thread = current_thread(); else new_thread = (thread_t)zalloc(thread_zone); if (new_thread == THREAD_NULL) return (KERN_RESOURCE_SHORTAGE); if (new_thread != first_thread) *new_thread = thread_template; #ifdef MACH_BSD new_thread->uthread = uthread_alloc(parent_task, new_thread, (options & TH_OPTION_NOCRED) != 0); if (new_thread->uthread == NULL) { zfree(thread_zone, new_thread); return (KERN_RESOURCE_SHORTAGE); } #endif /* MACH_BSD */ if (machine_thread_create(new_thread, parent_task) != KERN_SUCCESS) { #ifdef MACH_BSD void *ut = new_thread->uthread; new_thread->uthread = NULL; /* cred free may not be necessary */ uthread_cleanup(parent_task, ut, parent_task->bsd_info); uthread_cred_free(ut); uthread_zone_free(ut); #endif /* MACH_BSD */ zfree(thread_zone, new_thread); return (KERN_FAILURE); } new_thread->task = parent_task; thread_lock_init(new_thread); wake_lock_init(new_thread); lck_mtx_init(&new_thread->mutex, &thread_lck_grp, &thread_lck_attr); ipc_thread_init(new_thread); queue_init(&new_thread->held_ulocks); new_thread->continuation = continuation; lck_mtx_lock(&tasks_threads_lock); task_lock(parent_task); if ( !parent_task->active || parent_task->halting || ((options & TH_OPTION_NOSUSP) != 0 && parent_task->suspend_count > 0) || (parent_task->thread_count >= task_threadmax && parent_task != kernel_task) ) { task_unlock(parent_task); lck_mtx_unlock(&tasks_threads_lock); #ifdef MACH_BSD { void *ut = new_thread->uthread; new_thread->uthread = NULL; uthread_cleanup(parent_task, ut, parent_task->bsd_info); /* cred free may not be necessary */ uthread_cred_free(ut); uthread_zone_free(ut); } #endif /* MACH_BSD */ ipc_thread_disable(new_thread); ipc_thread_terminate(new_thread); lck_mtx_destroy(&new_thread->mutex, &thread_lck_grp); machine_thread_destroy(new_thread); zfree(thread_zone, new_thread); return (KERN_FAILURE); } /* New threads inherit any default state on the task */ machine_thread_inherit_taskwide(new_thread, parent_task); task_reference_internal(parent_task); /* Cache the task's map */ new_thread->map = parent_task->map; /* Chain the thread onto the task's list */ queue_enter(&parent_task->threads, new_thread, thread_t, task_threads); parent_task->thread_count++; /* So terminating threads don't need to take the task lock to decrement */ hw_atomic_add(&parent_task->active_thread_count, 1); /* Protected by the tasks_threads_lock */ new_thread->thread_id = ++thread_unique_id; queue_enter(&threads, new_thread, thread_t, threads); threads_count++; timer_call_setup(&new_thread->wait_timer, thread_timer_expire, new_thread); timer_call_setup(&new_thread->depress_timer, thread_depress_expire, new_thread); #if CONFIG_COUNTERS /* * If parent task has any reservations, they need to be propagated to this * thread. */ new_thread->t_chud = (TASK_PMC_FLAG == (parent_task->t_chud & TASK_PMC_FLAG)) ? THREAD_PMC_FLAG : 0U; #endif /* Set the thread's scheduling parameters */ if (parent_task != kernel_task) new_thread->sched_mode |= TH_MODE_TIMESHARE; new_thread->max_priority = parent_task->max_priority; new_thread->task_priority = parent_task->priority; new_thread->priority = (priority < 0)? parent_task->priority: priority; if (new_thread->priority > new_thread->max_priority) new_thread->priority = new_thread->max_priority; new_thread->importance = new_thread->priority - new_thread->task_priority; new_thread->sched_stamp = sched_tick; new_thread->pri_shift = sched_pri_shift; compute_priority(new_thread, FALSE); new_thread->active = TRUE; *out_thread = new_thread; { long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; kdbg_trace_data(parent_task->bsd_info, &dbg_arg2); KERNEL_DEBUG_CONSTANT( TRACEDBG_CODE(DBG_TRACE_DATA, 1) | DBG_FUNC_NONE, (vm_address_t)(uintptr_t)thread_tid(new_thread), dbg_arg2, 0, 0, 0); kdbg_trace_string(parent_task->bsd_info, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4); KERNEL_DEBUG_CONSTANT( TRACEDBG_CODE(DBG_TRACE_STRING, 1) | DBG_FUNC_NONE, dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); } DTRACE_PROC1(lwp__create, thread_t, *out_thread); return (KERN_SUCCESS); }
/* * processor_set_things: * * Common internals for processor_set_{threads,tasks} */ kern_return_t processor_set_things( processor_set_t pset, mach_port_t **thing_list, mach_msg_type_number_t *count, int type) { unsigned int actual; /* this many things */ unsigned int maxthings; unsigned int i; vm_size_t size, size_needed; void *addr; if (pset == PROCESSOR_SET_NULL || pset != &pset0) return (KERN_INVALID_ARGUMENT); size = 0; addr = NULL; for (;;) { lck_mtx_lock(&tasks_threads_lock); if (type == THING_TASK) maxthings = tasks_count; else maxthings = threads_count; /* do we have the memory we need? */ size_needed = maxthings * sizeof (mach_port_t); if (size_needed <= size) break; /* unlock and allocate more memory */ lck_mtx_unlock(&tasks_threads_lock); if (size != 0) kfree(addr, size); assert(size_needed > 0); size = size_needed; addr = kalloc(size); if (addr == 0) return (KERN_RESOURCE_SHORTAGE); } /* OK, have memory and the list locked */ actual = 0; switch (type) { case THING_TASK: { task_t task, *task_list = (task_t *)addr; for (task = (task_t)queue_first(&tasks); !queue_end(&tasks, (queue_entry_t)task); task = (task_t)queue_next(&task->tasks)) { #if defined(SECURE_KERNEL) if (task != kernel_task) { #endif task_reference_internal(task); task_list[actual++] = task; #if defined(SECURE_KERNEL) } #endif } break; } case THING_THREAD: { thread_t thread, *thread_list = (thread_t *)addr; for (thread = (thread_t)queue_first(&threads); !queue_end(&threads, (queue_entry_t)thread); thread = (thread_t)queue_next(&thread->threads)) { thread_reference_internal(thread); thread_list[actual++] = thread; } break; } } lck_mtx_unlock(&tasks_threads_lock); if (actual < maxthings) size_needed = actual * sizeof (mach_port_t); if (actual == 0) { /* no things, so return null pointer and deallocate memory */ *thing_list = NULL; *count = 0; if (size != 0) kfree(addr, size); } else { /* if we allocated too much, must copy */ if (size_needed < size) { void *newaddr; newaddr = kalloc(size_needed); if (newaddr == 0) { switch (type) { case THING_TASK: { task_t *task_list = (task_t *)addr; for (i = 0; i < actual; i++) task_deallocate(task_list[i]); break; } case THING_THREAD: { thread_t *thread_list = (thread_t *)addr; for (i = 0; i < actual; i++) thread_deallocate(thread_list[i]); break; } } kfree(addr, size); return (KERN_RESOURCE_SHORTAGE); } bcopy((void *) addr, (void *) newaddr, size_needed); kfree(addr, size); addr = newaddr; } *thing_list = (mach_port_t *)addr; *count = actual; /* do the conversion that Mig should handle */ switch (type) { case THING_TASK: { task_t *task_list = (task_t *)addr; for (i = 0; i < actual; i++) (*thing_list)[i] = convert_task_to_port(task_list[i]); break; } case THING_THREAD: { thread_t *thread_list = (thread_t *)addr; for (i = 0; i < actual; i++) (*thing_list)[i] = convert_thread_to_port(thread_list[i]); break; } } } return (KERN_SUCCESS); }
/* * processor_set_things: * * Common internals for processor_set_{threads,tasks} */ kern_return_t processor_set_things( processor_set_t pset, void **thing_list, mach_msg_type_number_t *count, int type) { unsigned int i; task_t task; thread_t thread; task_t *task_list; unsigned int actual_tasks; vm_size_t task_size, task_size_needed; thread_t *thread_list; unsigned int actual_threads; vm_size_t thread_size, thread_size_needed; void *addr, *newaddr; vm_size_t size, size_needed; if (pset == PROCESSOR_SET_NULL || pset != &pset0) return (KERN_INVALID_ARGUMENT); task_size = 0; task_size_needed = 0; task_list = NULL; actual_tasks = 0; thread_size = 0; thread_size_needed = 0; thread_list = NULL; actual_threads = 0; for (;;) { lck_mtx_lock(&tasks_threads_lock); /* do we have the memory we need? */ if (type == PSET_THING_THREAD) thread_size_needed = threads_count * sizeof(void *); #if !CONFIG_MACF else #endif task_size_needed = tasks_count * sizeof(void *); if (task_size_needed <= task_size && thread_size_needed <= thread_size) break; /* unlock and allocate more memory */ lck_mtx_unlock(&tasks_threads_lock); /* grow task array */ if (task_size_needed > task_size) { if (task_size != 0) kfree(task_list, task_size); assert(task_size_needed > 0); task_size = task_size_needed; task_list = (task_t *)kalloc(task_size); if (task_list == NULL) { if (thread_size != 0) kfree(thread_list, thread_size); return (KERN_RESOURCE_SHORTAGE); } } /* grow thread array */ if (thread_size_needed > thread_size) { if (thread_size != 0) kfree(thread_list, thread_size); assert(thread_size_needed > 0); thread_size = thread_size_needed; thread_list = (thread_t *)kalloc(thread_size); if (thread_list == 0) { if (task_size != 0) kfree(task_list, task_size); return (KERN_RESOURCE_SHORTAGE); } } } /* OK, have memory and the list locked */ /* If we need it, get the thread list */ if (type == PSET_THING_THREAD) { for (thread = (thread_t)queue_first(&threads); !queue_end(&threads, (queue_entry_t)thread); thread = (thread_t)queue_next(&thread->threads)) { #if defined(SECURE_KERNEL) if (thread->task != kernel_task) { #endif thread_reference_internal(thread); thread_list[actual_threads++] = thread; #if defined(SECURE_KERNEL) } #endif } } #if !CONFIG_MACF else { #endif /* get a list of the tasks */ for (task = (task_t)queue_first(&tasks); !queue_end(&tasks, (queue_entry_t)task); task = (task_t)queue_next(&task->tasks)) { #if defined(SECURE_KERNEL) if (task != kernel_task) { #endif task_reference_internal(task); task_list[actual_tasks++] = task; #if defined(SECURE_KERNEL) } #endif } #if !CONFIG_MACF } #endif lck_mtx_unlock(&tasks_threads_lock); #if CONFIG_MACF unsigned int j, used; /* for each task, make sure we are allowed to examine it */ for (i = used = 0; i < actual_tasks; i++) { if (mac_task_check_expose_task(task_list[i])) { task_deallocate(task_list[i]); continue; } task_list[used++] = task_list[i]; } actual_tasks = used; task_size_needed = actual_tasks * sizeof(void *); if (type == PSET_THING_THREAD) { /* for each thread (if any), make sure it's task is in the allowed list */ for (i = used = 0; i < actual_threads; i++) { boolean_t found_task = FALSE; task = thread_list[i]->task; for (j = 0; j < actual_tasks; j++) { if (task_list[j] == task) { found_task = TRUE; break; } } if (found_task) thread_list[used++] = thread_list[i]; else thread_deallocate(thread_list[i]); } actual_threads = used; thread_size_needed = actual_threads * sizeof(void *); /* done with the task list */ for (i = 0; i < actual_tasks; i++) task_deallocate(task_list[i]); kfree(task_list, task_size); task_size = 0; actual_tasks = 0; task_list = NULL; } #endif if (type == PSET_THING_THREAD) { if (actual_threads == 0) { /* no threads available to return */ assert(task_size == 0); if (thread_size != 0) kfree(thread_list, thread_size); *thing_list = NULL; *count = 0; return KERN_SUCCESS; } size_needed = actual_threads * sizeof(void *); size = thread_size; addr = thread_list; } else { if (actual_tasks == 0) { /* no tasks available to return */ assert(thread_size == 0); if (task_size != 0) kfree(task_list, task_size); *thing_list = NULL; *count = 0; return KERN_SUCCESS; } size_needed = actual_tasks * sizeof(void *); size = task_size; addr = task_list; } /* if we allocated too much, must copy */ if (size_needed < size) { newaddr = kalloc(size_needed); if (newaddr == 0) { for (i = 0; i < actual_tasks; i++) { if (type == PSET_THING_THREAD) thread_deallocate(thread_list[i]); else task_deallocate(task_list[i]); } if (size) kfree(addr, size); return (KERN_RESOURCE_SHORTAGE); } bcopy((void *) addr, (void *) newaddr, size_needed); kfree(addr, size); addr = newaddr; size = size_needed; } *thing_list = (void **)addr; *count = (unsigned int)size / sizeof(void *); return (KERN_SUCCESS); }