1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030 |
- /*
- * Mach Operating System
- * Copyright (c) 1993-1988 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- * processor.c: processor and processor_set manipulation routines.
- */
- #include <string.h>
- #include <mach/boolean.h>
- #include <mach/policy.h>
- #include <mach/processor_info.h>
- #include <mach/vm_param.h>
- #include <kern/cpu_number.h>
- #include <kern/debug.h>
- #include <kern/kalloc.h>
- #include <kern/lock.h>
- #include <kern/host.h>
- #include <kern/ipc_tt.h>
- #include <kern/processor.h>
- #include <kern/sched.h>
- #include <kern/task.h>
- #include <kern/thread.h>
- #include <kern/ipc_host.h>
- #include <ipc/ipc_port.h>
- #if MACH_HOST
- #include <kern/slab.h>
- struct kmem_cache pset_cache;
- #endif /* MACH_HOST */
- /*
- * Exported variables.
- */
- struct processor_set default_pset;
- struct processor processor_array[NCPUS];
- queue_head_t all_psets;
- int all_psets_count;
- decl_simple_lock_data(, all_psets_lock);
- processor_t master_processor;
- processor_t processor_ptr[NCPUS];
- /*
- * Bootstrap the processor/pset system so the scheduler can run.
- */
- void pset_sys_bootstrap(void)
- {
- int i;
- pset_init(&default_pset);
- default_pset.empty = FALSE;
- for (i = 0; i < NCPUS; i++) {
- /*
- * Initialize processor data structures.
- * Note that cpu_to_processor(i) is processor_ptr[i].
- */
- processor_ptr[i] = &processor_array[i];
- processor_init(processor_ptr[i], i);
- }
- master_processor = cpu_to_processor(master_cpu);
- queue_init(&all_psets);
- simple_lock_init(&all_psets_lock);
- queue_enter(&all_psets, &default_pset, processor_set_t, all_psets);
- all_psets_count = 1;
- default_pset.active = TRUE;
- default_pset.empty = FALSE;
- /*
- * Note: the default_pset has a max_priority of BASEPRI_USER.
- * Internal kernel threads override this in kernel_thread.
- */
- }
- #if MACH_HOST
- /*
- * Rest of pset system initializations.
- */
- void pset_sys_init(void)
- {
- int i;
- processor_t processor;
- /*
- * Allocate the cache for processor sets.
- */
- kmem_cache_init(&pset_cache, "processor_set",
- sizeof(struct processor_set), 0, NULL, 0);
- /*
- * Give each processor a control port.
- * The master processor already has one.
- */
- for (i = 0; i < NCPUS; i++) {
- processor = cpu_to_processor(i);
- if (processor != master_processor &&
- machine_slot[i].is_cpu)
- {
- ipc_processor_init(processor);
- }
- }
- }
- #endif /* MACH_HOST */
- /*
- * Initialize the given processor_set structure.
- */
- void pset_init(
- processor_set_t pset)
- {
- int i;
- simple_lock_init(&pset->runq.lock);
- pset->runq.low = 0;
- pset->runq.count = 0;
- for (i = 0; i < NRQS; i++) {
- queue_init(&(pset->runq.runq[i]));
- }
- queue_init(&pset->idle_queue);
- pset->idle_count = 0;
- simple_lock_init(&pset->idle_lock);
- queue_init(&pset->processors);
- pset->processor_count = 0;
- pset->empty = TRUE;
- queue_init(&pset->tasks);
- pset->task_count = 0;
- queue_init(&pset->threads);
- pset->thread_count = 0;
- pset->ref_count = 1;
- simple_lock_init(&pset->ref_lock);
- queue_init(&pset->all_psets);
- pset->active = FALSE;
- simple_lock_init(&pset->lock);
- pset->pset_self = IP_NULL;
- pset->pset_name_self = IP_NULL;
- pset->max_priority = BASEPRI_USER;
- #if MACH_FIXPRI
- pset->policies = POLICY_TIMESHARE;
- #endif /* MACH_FIXPRI */
- pset->set_quantum = min_quantum;
- #if NCPUS > 1
- pset->quantum_adj_index = 0;
- simple_lock_init(&pset->quantum_adj_lock);
- for (i = 0; i <= NCPUS; i++) {
- pset->machine_quantum[i] = min_quantum;
- }
- #endif /* NCPUS > 1 */
- pset->mach_factor = 0;
- pset->load_average = 0;
- pset->sched_load = SCHED_SCALE; /* i.e. 1 */
- }
- /*
- * Initialize the given processor structure for the processor in
- * the slot specified by slot_num.
- */
- void processor_init(
- processor_t pr,
- int slot_num)
- {
- int i;
- simple_lock_init(&pr->runq.lock);
- pr->runq.low = 0;
- pr->runq.count = 0;
- for (i = 0; i < NRQS; i++) {
- queue_init(&(pr->runq.runq[i]));
- }
- queue_init(&pr->processor_queue);
- pr->state = PROCESSOR_OFF_LINE;
- pr->next_thread = THREAD_NULL;
- pr->idle_thread = THREAD_NULL;
- pr->quantum = 0;
- pr->first_quantum = FALSE;
- pr->last_quantum = 0;
- pr->processor_set = PROCESSOR_SET_NULL;
- pr->processor_set_next = PROCESSOR_SET_NULL;
- queue_init(&pr->processors);
- simple_lock_init(&pr->lock);
- pr->processor_self = IP_NULL;
- pr->slot_num = slot_num;
- }
- /*
- * pset_remove_processor() removes a processor from a processor_set.
- * It can only be called on the current processor. Caller must
- * hold lock on current processor and processor set.
- */
- void pset_remove_processor(
- processor_set_t pset,
- processor_t processor)
- {
- if (pset != processor->processor_set)
- panic("pset_remove_processor: wrong pset");
- queue_remove(&pset->processors, processor, processor_t, processors);
- processor->processor_set = PROCESSOR_SET_NULL;
- pset->processor_count--;
- quantum_set(pset);
- }
- /*
- * pset_add_processor() adds a processor to a processor_set.
- * It can only be called on the current processor. Caller must
- * hold lock on curent processor and on pset. No reference counting on
- * processors. Processor reference to pset is implicit.
- */
- void pset_add_processor(
- processor_set_t pset,
- processor_t processor)
- {
- queue_enter(&pset->processors, processor, processor_t, processors);
- processor->processor_set = pset;
- pset->processor_count++;
- quantum_set(pset);
- }
- /*
- * pset_remove_task() removes a task from a processor_set.
- * Caller must hold locks on pset and task. Pset reference count
- * is not decremented; caller must explicitly pset_deallocate.
- */
- void pset_remove_task(
- processor_set_t pset,
- task_t task)
- {
- if (pset != task->processor_set)
- return;
- queue_remove(&pset->tasks, task, task_t, pset_tasks);
- task->processor_set = PROCESSOR_SET_NULL;
- pset->task_count--;
- }
- /*
- * pset_add_task() adds a task to a processor_set.
- * Caller must hold locks on pset and task. Pset references to
- * tasks are implicit.
- */
- void pset_add_task(
- processor_set_t pset,
- task_t task)
- {
- queue_enter(&pset->tasks, task, task_t, pset_tasks);
- task->processor_set = pset;
- pset->task_count++;
- }
- /*
- * pset_remove_thread() removes a thread from a processor_set.
- * Caller must hold locks on pset and thread. Pset reference count
- * is not decremented; caller must explicitly pset_deallocate.
- */
- void pset_remove_thread(
- processor_set_t pset,
- thread_t thread)
- {
- queue_remove(&pset->threads, thread, thread_t, pset_threads);
- thread->processor_set = PROCESSOR_SET_NULL;
- pset->thread_count--;
- }
- /*
- * pset_add_thread() adds a thread to a processor_set.
- * Caller must hold locks on pset and thread. Pset references to
- * threads are implicit.
- */
- void pset_add_thread(
- processor_set_t pset,
- thread_t thread)
- {
- queue_enter(&pset->threads, thread, thread_t, pset_threads);
- thread->processor_set = pset;
- pset->thread_count++;
- }
- /*
- * thread_change_psets() changes the pset of a thread. Caller must
- * hold locks on both psets and thread. The old pset must be
- * explicitly pset_deallocat()'ed by caller.
- */
- void thread_change_psets(
- thread_t thread,
- processor_set_t old_pset,
- processor_set_t new_pset)
- {
- queue_remove(&old_pset->threads, thread, thread_t, pset_threads);
- old_pset->thread_count--;
- queue_enter(&new_pset->threads, thread, thread_t, pset_threads);
- thread->processor_set = new_pset;
- new_pset->thread_count++;
- }
- /*
- * pset_deallocate:
- *
- * Remove one reference to the processor set. Destroy processor_set
- * if this was the last reference.
- */
- void pset_deallocate(
- processor_set_t pset)
- {
- if (pset == PROCESSOR_SET_NULL)
- return;
- pset_ref_lock(pset);
- if (--pset->ref_count > 0) {
- pset_ref_unlock(pset);
- return;
- }
- #if !MACH_HOST
- panic("pset_deallocate: default_pset destroyed");
- #endif /* !MACH_HOST */
- #if MACH_HOST
- /*
- * Reference count is zero, however the all_psets list
- * holds an implicit reference and may make new ones.
- * Its lock also dominates the pset lock. To check for this,
- * temporarily restore one reference, and then lock the
- * other structures in the right order.
- */
- pset->ref_count = 1;
- pset_ref_unlock(pset);
- simple_lock(&all_psets_lock);
- pset_ref_lock(pset);
- if (--pset->ref_count > 0) {
- /*
- * Made an extra reference.
- */
- pset_ref_unlock(pset);
- simple_unlock(&all_psets_lock);
- return;
- }
- /*
- * Ok to destroy pset. Make a few paranoia checks.
- */
- if ((pset == &default_pset) || (pset->thread_count > 0) ||
- (pset->task_count > 0) || pset->processor_count > 0) {
- panic("pset_deallocate: destroy default or active pset");
- }
- /*
- * Remove from all_psets queue.
- */
- queue_remove(&all_psets, pset, processor_set_t, all_psets);
- all_psets_count--;
- pset_ref_unlock(pset);
- simple_unlock(&all_psets_lock);
- /*
- * That's it, free data structure.
- */
- kmem_cache_free(&pset_cache, (vm_offset_t)pset);
- #endif /* MACH_HOST */
- }
- /*
- * pset_reference:
- *
- * Add one reference to the processor set.
- */
- void pset_reference(
- processor_set_t pset)
- {
- pset_ref_lock(pset);
- pset->ref_count++;
- pset_ref_unlock(pset);
- }
- kern_return_t
- processor_info(
- processor_t processor,
- int flavor,
- host_t *host,
- processor_info_t info,
- natural_t *count)
- {
- int slot_num, state;
- processor_basic_info_t basic_info;
- if (processor == PROCESSOR_NULL)
- return KERN_INVALID_ARGUMENT;
- if (flavor != PROCESSOR_BASIC_INFO ||
- *count < PROCESSOR_BASIC_INFO_COUNT)
- return KERN_FAILURE;
- basic_info = (processor_basic_info_t) info;
- slot_num = processor->slot_num;
- basic_info->cpu_type = machine_slot[slot_num].cpu_type;
- basic_info->cpu_subtype = machine_slot[slot_num].cpu_subtype;
- state = processor->state;
- if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE)
- basic_info->running = FALSE;
- else
- basic_info->running = TRUE;
- basic_info->slot_num = slot_num;
- if (processor == master_processor)
- basic_info->is_master = TRUE;
- else
- basic_info->is_master = FALSE;
- *count = PROCESSOR_BASIC_INFO_COUNT;
- *host = &realhost;
- return KERN_SUCCESS;
- }
- kern_return_t processor_start(
- processor_t processor)
- {
- if (processor == PROCESSOR_NULL)
- return KERN_INVALID_ARGUMENT;
- #if NCPUS > 1
- return cpu_start(processor->slot_num);
- #else /* NCPUS > 1 */
- return KERN_FAILURE;
- #endif /* NCPUS > 1 */
- }
- kern_return_t processor_exit(
- processor_t processor)
- {
- if (processor == PROCESSOR_NULL)
- return KERN_INVALID_ARGUMENT;
- #if NCPUS > 1
- return processor_shutdown(processor);
- #else /* NCPUS > 1 */
- return KERN_FAILURE;
- #endif /* NCPUS > 1 */
- }
- kern_return_t
- processor_control(
- processor_t processor,
- processor_info_t info,
- natural_t count)
- {
- if (processor == PROCESSOR_NULL)
- return KERN_INVALID_ARGUMENT;
- #if NCPUS > 1
- return cpu_control(processor->slot_num, (int *)info, count);
- #else /* NCPUS > 1 */
- return KERN_FAILURE;
- #endif /* NCPUS > 1 */
- }
- /*
- * Precalculate the appropriate system quanta based on load. The
- * index into machine_quantum is the number of threads on the
- * processor set queue. It is limited to the number of processors in
- * the set.
- */
- void quantum_set(
- processor_set_t pset)
- {
- #if NCPUS > 1
- int i, ncpus;
- ncpus = pset->processor_count;
- for ( i=1 ; i <= ncpus ; i++) {
- pset->machine_quantum[i] =
- ((min_quantum * ncpus) + (i/2)) / i ;
- }
- pset->machine_quantum[0] = 2 * pset->machine_quantum[1];
- i = ((pset->runq.count > pset->processor_count) ?
- pset->processor_count : pset->runq.count);
- pset->set_quantum = pset->machine_quantum[i];
- #else /* NCPUS > 1 */
- default_pset.set_quantum = min_quantum;
- #endif /* NCPUS > 1 */
- }
- #if MACH_HOST
- /*
- * processor_set_create:
- *
- * Create and return a new processor set.
- */
- kern_return_t
- processor_set_create(
- host_t host,
- processor_set_t *new_set,
- processor_set_t *new_name)
- {
- processor_set_t pset;
- if (host == HOST_NULL)
- return KERN_INVALID_ARGUMENT;
- pset = (processor_set_t) kmem_cache_alloc(&pset_cache);
- pset_init(pset);
- pset_reference(pset); /* for new_set out argument */
- pset_reference(pset); /* for new_name out argument */
- ipc_pset_init(pset);
- pset->active = TRUE;
- simple_lock(&all_psets_lock);
- queue_enter(&all_psets, pset, processor_set_t, all_psets);
- all_psets_count++;
- simple_unlock(&all_psets_lock);
- ipc_pset_enable(pset);
- *new_set = pset;
- *new_name = pset;
- return KERN_SUCCESS;
- }
- /*
- * processor_set_destroy:
- *
- * destroy a processor set. Any tasks, threads or processors
- * currently assigned to it are reassigned to the default pset.
- */
- kern_return_t processor_set_destroy(
- processor_set_t pset)
- {
- queue_entry_t elem;
- queue_head_t *list;
- if (pset == PROCESSOR_SET_NULL || pset == &default_pset)
- return KERN_INVALID_ARGUMENT;
- /*
- * Handle multiple termination race. First one through sets
- * active to FALSE and disables ipc access.
- */
- pset_lock(pset);
- if (!(pset->active)) {
- pset_unlock(pset);
- return KERN_FAILURE;
- }
- pset->active = FALSE;
- ipc_pset_disable(pset);
- /*
- * Now reassign everything in this set to the default set.
- */
- if (pset->task_count > 0) {
- list = &pset->tasks;
- while (!queue_empty(list)) {
- elem = queue_first(list);
- task_reference((task_t) elem);
- pset_unlock(pset);
- task_assign((task_t) elem, &default_pset, FALSE);
- task_deallocate((task_t) elem);
- pset_lock(pset);
- }
- }
- if (pset->thread_count > 0) {
- list = &pset->threads;
- while (!queue_empty(list)) {
- elem = queue_first(list);
- thread_reference((thread_t) elem);
- pset_unlock(pset);
- thread_assign((thread_t) elem, &default_pset);
- thread_deallocate((thread_t) elem);
- pset_lock(pset);
- }
- }
- if (pset->processor_count > 0) {
- list = &pset->processors;
- while(!queue_empty(list)) {
- elem = queue_first(list);
- pset_unlock(pset);
- processor_assign((processor_t) elem, &default_pset, TRUE);
- pset_lock(pset);
- }
- }
- pset_unlock(pset);
- /*
- * Destroy ipc state.
- */
- ipc_pset_terminate(pset);
- /*
- * Deallocate pset's reference to itself.
- */
- pset_deallocate(pset);
- return KERN_SUCCESS;
- }
- #else /* MACH_HOST */
- kern_return_t
- processor_set_create(
- host_t host,
- processor_set_t *new_set,
- processor_set_t *new_name)
- {
- return KERN_FAILURE;
- }
- kern_return_t processor_set_destroy(
- processor_set_t pset)
- {
- return KERN_FAILURE;
- }
- #endif /* MACH_HOST */
- kern_return_t
- processor_get_assignment(
- processor_t processor,
- processor_set_t *pset)
- {
- int state;
- if (processor == PROCESSOR_NULL)
- return KERN_INVALID_ARGUMENT;
- state = processor->state;
- if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE)
- return KERN_FAILURE;
- *pset = processor->processor_set;
- pset_reference(*pset);
- return KERN_SUCCESS;
- }
- kern_return_t
- processor_set_info(
- processor_set_t pset,
- int flavor,
- host_t *host,
- processor_set_info_t info,
- natural_t *count)
- {
- if (pset == PROCESSOR_SET_NULL)
- return KERN_INVALID_ARGUMENT;
- if (flavor == PROCESSOR_SET_BASIC_INFO) {
- processor_set_basic_info_t basic_info;
- if (*count < PROCESSOR_SET_BASIC_INFO_COUNT)
- return KERN_FAILURE;
- basic_info = (processor_set_basic_info_t) info;
- pset_lock(pset);
- basic_info->processor_count = pset->processor_count;
- basic_info->task_count = pset->task_count;
- basic_info->thread_count = pset->thread_count;
- basic_info->mach_factor = pset->mach_factor;
- basic_info->load_average = pset->load_average;
- pset_unlock(pset);
- *count = PROCESSOR_SET_BASIC_INFO_COUNT;
- *host = &realhost;
- return KERN_SUCCESS;
- }
- else if (flavor == PROCESSOR_SET_SCHED_INFO) {
- processor_set_sched_info_t sched_info;
- if (*count < PROCESSOR_SET_SCHED_INFO_COUNT)
- return KERN_FAILURE;
- sched_info = (processor_set_sched_info_t) info;
- pset_lock(pset);
- #if MACH_FIXPRI
- sched_info->policies = pset->policies;
- #else /* MACH_FIXPRI */
- sched_info->policies = POLICY_TIMESHARE;
- #endif /* MACH_FIXPRI */
- sched_info->max_priority = pset->max_priority;
- pset_unlock(pset);
- *count = PROCESSOR_SET_SCHED_INFO_COUNT;
- *host = &realhost;
- return KERN_SUCCESS;
- }
- *host = HOST_NULL;
- return KERN_INVALID_ARGUMENT;
- }
- /*
- * processor_set_max_priority:
- *
- * Specify max priority permitted on processor set. This affects
- * newly created and assigned threads. Optionally change existing
- * ones.
- */
- kern_return_t
- processor_set_max_priority(
- processor_set_t pset,
- int max_priority,
- boolean_t change_threads)
- {
- if (pset == PROCESSOR_SET_NULL || invalid_pri(max_priority))
- return KERN_INVALID_ARGUMENT;
- pset_lock(pset);
- pset->max_priority = max_priority;
- if (change_threads) {
- queue_head_t *list;
- thread_t thread;
- list = &pset->threads;
- queue_iterate(list, thread, thread_t, pset_threads) {
- if (thread->max_priority < max_priority)
- thread_max_priority(thread, pset, max_priority);
- }
- }
- pset_unlock(pset);
- return KERN_SUCCESS;
- }
- /*
- * processor_set_policy_enable:
- *
- * Allow indicated policy on processor set.
- */
- kern_return_t
- processor_set_policy_enable(
- processor_set_t pset,
- int policy)
- {
- if ((pset == PROCESSOR_SET_NULL) || invalid_policy(policy))
- return KERN_INVALID_ARGUMENT;
- #if MACH_FIXPRI
- pset_lock(pset);
- pset->policies |= policy;
- pset_unlock(pset);
- return KERN_SUCCESS;
- #else /* MACH_FIXPRI */
- if (policy == POLICY_TIMESHARE)
- return KERN_SUCCESS;
- else
- return KERN_FAILURE;
- #endif /* MACH_FIXPRI */
- }
- /*
- * processor_set_policy_disable:
- *
- * Forbid indicated policy on processor set. Time sharing cannot
- * be forbidden.
- */
- kern_return_t
- processor_set_policy_disable(
- processor_set_t pset,
- int policy,
- boolean_t change_threads)
- {
- if ((pset == PROCESSOR_SET_NULL) || policy == POLICY_TIMESHARE ||
- invalid_policy(policy))
- return KERN_INVALID_ARGUMENT;
- #if MACH_FIXPRI
- pset_lock(pset);
- /*
- * Check if policy enabled. Disable if so, then handle
- * change_threads.
- */
- if (pset->policies & policy) {
- pset->policies &= ~policy;
- if (change_threads) {
- queue_head_t *list;
- thread_t thread;
- list = &pset->threads;
- queue_iterate(list, thread, thread_t, pset_threads) {
- if (thread->policy == policy)
- thread_policy(thread, POLICY_TIMESHARE, 0);
- }
- }
- }
- pset_unlock(pset);
- #endif /* MACH_FIXPRI */
- return KERN_SUCCESS;
- }
- #define THING_TASK 0
- #define THING_THREAD 1
- /*
- * 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,
- natural_t *count,
- int type)
- {
- unsigned int actual; /* this many things */
- unsigned i;
- vm_size_t size, size_needed;
- vm_offset_t addr;
- if (pset == PROCESSOR_SET_NULL)
- return KERN_INVALID_ARGUMENT;
- size = 0; addr = 0;
- for (;;) {
- pset_lock(pset);
- if (!pset->active) {
- pset_unlock(pset);
- return KERN_FAILURE;
- }
- if (type == THING_TASK)
- actual = pset->task_count;
- else
- actual = pset->thread_count;
- /* do we have the memory we need? */
- size_needed = actual * sizeof(mach_port_t);
- if (size_needed <= size)
- break;
- /* unlock the pset and allocate more memory */
- pset_unlock(pset);
- 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 processor_set is locked & active */
- switch (type) {
- case THING_TASK: {
- task_t *tasks = (task_t *) addr;
- task_t task;
- for (i = 0, task = (task_t) queue_first(&pset->tasks);
- i < actual;
- i++, task = (task_t) queue_next(&task->pset_tasks)) {
- /* take ref for convert_task_to_port */
- task_reference(task);
- tasks[i] = task;
- }
- assert(queue_end(&pset->tasks, (queue_entry_t) task));
- break;
- }
- case THING_THREAD: {
- thread_t *threads = (thread_t *) addr;
- thread_t thread;
- for (i = 0, thread = (thread_t) queue_first(&pset->threads);
- i < actual;
- i++,
- thread = (thread_t) queue_next(&thread->pset_threads)) {
- /* take ref for convert_thread_to_port */
- thread_reference(thread);
- threads[i] = thread;
- }
- assert(queue_end(&pset->threads, (queue_entry_t) thread));
- break;
- }
- }
- /* can unlock processor set now that we have the task/thread refs */
- pset_unlock(pset);
- if (actual == 0) {
- /* no things, so return null pointer and deallocate memory */
- *thing_list = 0;
- *count = 0;
- if (size != 0)
- kfree(addr, size);
- } else {
- /* if we allocated too much, must copy */
- if (size_needed < size) {
- vm_offset_t newaddr;
- newaddr = kalloc(size_needed);
- if (newaddr == 0) {
- switch (type) {
- case THING_TASK: {
- task_t *tasks = (task_t *) addr;
- for (i = 0; i < actual; i++)
- task_deallocate(tasks[i]);
- break;
- }
- case THING_THREAD: {
- thread_t *threads = (thread_t *) addr;
- for (i = 0; i < actual; i++)
- thread_deallocate(threads[i]);
- break;
- }
- }
- kfree(addr, size);
- return KERN_RESOURCE_SHORTAGE;
- }
- memcpy((void *) newaddr, (void *) addr, 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 *tasks = (task_t *) addr;
- for (i = 0; i < actual; i++)
- ((mach_port_t *) tasks)[i] =
- (mach_port_t)convert_task_to_port(tasks[i]);
- break;
- }
- case THING_THREAD: {
- thread_t *threads = (thread_t *) addr;
- for (i = 0; i < actual; i++)
- ((mach_port_t *) threads)[i] =
- (mach_port_t)convert_thread_to_port(threads[i]);
- break;
- }
- }
- }
- return KERN_SUCCESS;
- }
- /*
- * processor_set_tasks:
- *
- * List all tasks in the processor set.
- */
- kern_return_t
- processor_set_tasks(
- processor_set_t pset,
- task_array_t *task_list,
- natural_t *count)
- {
- return processor_set_things(pset, task_list, count, THING_TASK);
- }
- /*
- * processor_set_threads:
- *
- * List all threads in the processor set.
- */
- kern_return_t
- processor_set_threads(
- processor_set_t pset,
- thread_array_t *thread_list,
- natural_t *count)
- {
- return processor_set_things(pset, thread_list, count, THING_THREAD);
- }
|