void thread_reference( thread_t thread) { if (thread != THREAD_NULL) thread_reference_internal(thread); }
thread_t convert_port_to_thread( ipc_port_t port) { thread_t thread = THREAD_NULL; if (IP_VALID(port)) { ip_lock(port); if ( ip_active(port) && ip_kotype(port) == IKOT_THREAD ) { thread = (thread_t)port->ip_kobject; assert(thread != THREAD_NULL); thread_reference_internal(thread); } ip_unlock(port); } return (thread); }
/* * 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); }
/* * Return info on stack usage for threads in a specific processor set */ kern_return_t processor_set_stack_usage( processor_set_t pset, unsigned int *totalp, vm_size_t *spacep, vm_size_t *residentp, vm_size_t *maxusagep, vm_offset_t *maxstackp) { #if !MACH_DEBUG return KERN_NOT_SUPPORTED; #else unsigned int total; vm_size_t maxusage; vm_offset_t maxstack; register thread_t *thread_list; register thread_t thread; unsigned int actual; /* this many things */ 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 (;;) { mutex_lock(&tasks_threads_lock); actual = threads_count; /* do we have the memory we need? */ size_needed = actual * sizeof(thread_t); if (size_needed <= size) break; mutex_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 list is locked */ thread_list = (thread_t *) addr; for (i = 0, 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[i++] = thread; } assert(i <= actual); mutex_unlock(&tasks_threads_lock); /* calculate maxusage and free thread references */ total = 0; maxusage = 0; maxstack = 0; while (i > 0) { thread_t threadref = thread_list[--i]; if (threadref->kernel_stack != 0) total++; thread_deallocate(threadref); } if (size != 0) kfree(addr, size); *totalp = total; *residentp = *spacep = total * round_page(KERNEL_STACK_SIZE); *maxusagep = maxusage; *maxstackp = maxstack; return KERN_SUCCESS; #endif /* MACH_DEBUG */ }
// an exact copy of task_threads() except no mig conversion at the end! static kern_return_t chudxnu_private_task_threads( task_t task, thread_act_array_t *threads_out, mach_msg_type_number_t *count) { mach_msg_type_number_t actual; thread_t *thread_list; thread_t thread; vm_size_t size, size_needed; void *addr; unsigned int i, j; if (task == TASK_NULL) return (KERN_INVALID_ARGUMENT); size = 0; addr = NULL; for (;;) { task_lock(task); if (!task->active) { task_unlock(task); if (size != 0) kfree(addr, size); return (KERN_FAILURE); } actual = task->thread_count; /* do we have the memory we need? */ size_needed = actual * sizeof (mach_port_t); if (size_needed <= size) break; /* unlock the task and allocate more memory */ task_unlock(task); 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 task is locked & active */ thread_list = (thread_t *)addr; i = j = 0; for (thread = (thread_t)queue_first(&task->threads); i < actual; ++i, thread = (thread_t)queue_next(&thread->task_threads)) { thread_reference_internal(thread); thread_list[j++] = thread; } assert(queue_end(&task->threads, (queue_entry_t)thread)); actual = j; size_needed = actual * sizeof (mach_port_t); /* can unlock task now that we've got the thread refs */ task_unlock(task); if (actual == 0) { /* no threads, so return null pointer and deallocate memory */ *threads_out = 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) { for (i = 0; i < actual; ++i) thread_deallocate(thread_list[i]); kfree(addr, size); return (KERN_RESOURCE_SHORTAGE); } bcopy(addr, newaddr, size_needed); kfree(addr, size); thread_list = (thread_t *)newaddr; } *threads_out = thread_list; *count = actual; } return (KERN_SUCCESS); }