/* * Routine: port_name_to_clock * Purpose: * Convert from a clock name to a clock pointer. */ clock_t port_name_to_clock( mach_port_name_t clock_name) { clock_t clock = CLOCK_NULL; ipc_space_t space; ipc_port_t port; if (clock_name == 0) return (clock); space = current_space(); if (ipc_port_translate_send(space, clock_name, &port) != KERN_SUCCESS) return (clock); if (ip_active(port) && (ip_kotype(port) == IKOT_CLOCK)) clock = (clock_t) port->ip_kobject; ip_unlock(port); return (clock); }
/* * thread_switch: * * Context switch. User may supply thread hint. */ kern_return_t thread_switch( struct thread_switch_args *args) { thread_t thread = THREAD_NULL; thread_t self = current_thread(); mach_port_name_t thread_name = args->thread_name; int option = args->option; mach_msg_timeout_t option_time = args->option_time; uint32_t scale_factor = NSEC_PER_MSEC; boolean_t reenable_workq_callback = FALSE; boolean_t depress_option = FALSE; boolean_t wait_option = FALSE; /* * Validate and process option. */ switch (option) { case SWITCH_OPTION_NONE: workqueue_thread_yielded(); break; case SWITCH_OPTION_WAIT: wait_option = TRUE; workqueue_thread_yielded(); break; case SWITCH_OPTION_DEPRESS: depress_option = TRUE; workqueue_thread_yielded(); break; case SWITCH_OPTION_DISPATCH_CONTENTION: scale_factor = NSEC_PER_USEC; wait_option = TRUE; if (thread_switch_disable_workqueue_sched_callback()) reenable_workq_callback = TRUE; break; case SWITCH_OPTION_OSLOCK_DEPRESS: depress_option = TRUE; if (thread_switch_disable_workqueue_sched_callback()) reenable_workq_callback = TRUE; break; case SWITCH_OPTION_OSLOCK_WAIT: wait_option = TRUE; if (thread_switch_disable_workqueue_sched_callback()) reenable_workq_callback = TRUE; break; default: return (KERN_INVALID_ARGUMENT); } /* * Translate the port name if supplied. */ if (thread_name != MACH_PORT_NULL) { ipc_port_t port; if (ipc_port_translate_send(self->task->itk_space, thread_name, &port) == KERN_SUCCESS) { ip_reference(port); ip_unlock(port); thread = convert_port_to_thread(port); ip_release(port); if (thread == self) { thread_deallocate(thread); thread = THREAD_NULL; } } } if (option == SWITCH_OPTION_OSLOCK_DEPRESS || option == SWITCH_OPTION_OSLOCK_WAIT) { if (thread != THREAD_NULL) { if (thread->task != self->task) { /* * OSLock boosting only applies to other threads * in your same task (even if you have a port for * a thread in another task) */ thread_deallocate(thread); thread = THREAD_NULL; } else { /* * Attempt to kick the lock owner up to our same IO throttling tier. * If the thread is currently blocked in throttle_lowpri_io(), * it will immediately break out. * * TODO: SFI break out? */ int new_policy = proc_get_effective_thread_policy(self, TASK_POLICY_IO); set_thread_iotier_override(thread, new_policy); } } } /* * Try to handoff if supplied. */ if (thread != THREAD_NULL) { spl_t s = splsched(); /* This may return a different thread if the target is pushing on something */ thread_t pulled_thread = thread_run_queue_remove_for_handoff(thread); KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED_THREAD_SWITCH)|DBG_FUNC_NONE, thread_tid(thread), thread->state, pulled_thread ? TRUE : FALSE, 0, 0); if (pulled_thread != THREAD_NULL) { /* We can't be dropping the last ref here */ thread_deallocate_safe(thread); if (wait_option) assert_wait_timeout((event_t)assert_wait_timeout, THREAD_ABORTSAFE, option_time, scale_factor); else if (depress_option) thread_depress_ms(option_time); self->saved.swtch.option = option; self->saved.swtch.reenable_workq_callback = reenable_workq_callback; thread_run(self, (thread_continue_t)thread_switch_continue, NULL, pulled_thread); /* NOTREACHED */ panic("returned from thread_run!"); } splx(s); thread_deallocate(thread); } if (wait_option) assert_wait_timeout((event_t)assert_wait_timeout, THREAD_ABORTSAFE, option_time, scale_factor); else if (depress_option) thread_depress_ms(option_time); self->saved.swtch.option = option; self->saved.swtch.reenable_workq_callback = reenable_workq_callback; thread_block_reason((thread_continue_t)thread_switch_continue, NULL, AST_YIELD); if (depress_option) thread_depress_abort_internal(self); if (reenable_workq_callback) thread_switch_enable_workqueue_sched_callback(); return (KERN_SUCCESS); }
/* * thread_switch: * * Context switch. User may supply thread hint. * * Fixed priority threads that call this get what they asked for * even if that violates priority order. */ kern_return_t thread_switch( mach_port_t thread_name, int option, mach_msg_timeout_t option_time) { thread_t cur_thread = current_thread(); processor_t myprocessor; ipc_port_t port; /* * Process option. */ switch (option) { case SWITCH_OPTION_NONE: /* * Nothing to do. */ break; case SWITCH_OPTION_DEPRESS: /* * Depress priority for given time. */ thread_depress_priority(cur_thread, option_time); break; case SWITCH_OPTION_WAIT: thread_will_wait_with_timeout(cur_thread, option_time); break; default: return(KERN_INVALID_ARGUMENT); } #ifndef MIGRATING_THREADS /* XXX thread_run defunct */ /* * Check and act on thread hint if appropriate. */ if ((thread_name != 0) && (ipc_port_translate_send(cur_thread->task->itk_space, thread_name, &port) == KERN_SUCCESS)) { /* port is locked, but it might not be active */ /* * Get corresponding thread. */ if (ip_active(port) && (ip_kotype(port) == IKOT_THREAD)) { thread_t thread; spl_t s; thread = (thread_t) port->ip_kobject; /* * Check if the thread is in the right pset. Then * pull it off its run queue. If it * doesn't come, then it's not eligible. */ s = splsched(); thread_lock(thread); if ((thread->processor_set == cur_thread->processor_set) && (rem_runq(thread) != RUN_QUEUE_NULL)) { /* * Hah, got it!! */ thread_unlock(thread); (void) splx(s); ip_unlock(port); /* XXX thread might disappear on us now? */ #if MACH_FIXPRI if (thread->policy == POLICY_FIXEDPRI) { myprocessor = current_processor(); myprocessor->quantum = thread->sched_data; myprocessor->first_quantum = TRUE; } #endif /* MACH_FIXPRI */ counter(c_thread_switch_handoff++); thread_run(thread_switch_continue, thread); /* * Restore depressed priority */ if (cur_thread->depress_priority >= 0) (void) thread_depress_abort(cur_thread); return(KERN_SUCCESS); } thread_unlock(thread); (void) splx(s); } ip_unlock(port); } #endif /* not MIGRATING_THREADS */ /* * No handoff hint supplied, or hint was wrong. Call thread_block() in * hopes of running something else. If nothing else is runnable, * thread_block will detect this. WARNING: thread_switch with no * option will not do anything useful if the thread calling it is the * highest priority thread (can easily happen with a collection * of timesharing threads). */ #if NCPUS > 1 myprocessor = current_processor(); if (myprocessor->processor_set->runq.count > 0 || myprocessor->runq.count > 0) #endif /* NCPUS > 1 */ { counter(c_thread_switch_block++); thread_block(thread_switch_continue); } /* * Restore depressed priority */ if (cur_thread->depress_priority >= 0) (void) thread_depress_abort(cur_thread); return(KERN_SUCCESS); }