kern_return_t task_swapin(task_t task, boolean_t make_unswappable) { register queue_head_t *list; register thread_act_t thr_act, next; thread_t thread; int s; boolean_t swappable = TRUE; task_lock(task); switch (task->swap_state) { case TASK_SW_OUT: { vm_map_t map = task->map; /* * Task has made it all the way out, which means * that vm_map_res_deallocate has been done; set * state to TASK_SW_COMING_IN, then bring map * back in. We could actually be racing with * the thread_swapout_enqueue, which does the * vm_map_res_deallocate, but that race is covered. */ task->swap_state = TASK_SW_COMING_IN; assert(task->swap_ast_waiting == 0); assert(map->res_count >= 0); task_unlock(task); mutex_lock(&map->s_lock); vm_map_res_reference(map); mutex_unlock(&map->s_lock); task_lock(task); assert(task->swap_state == TASK_SW_COMING_IN); } break; case TASK_SW_GOING_OUT: /* * Task isn't all the way out yet. There is * still at least one thread not swapped, and * vm_map_res_deallocate has not been done. */ task->swap_state = TASK_SW_COMING_IN; assert(task->swap_ast_waiting > 0 || (task->swap_ast_waiting == 0 && task->thr_act_count == 0)); assert(task->map->res_count > 0); TASK_STATS_INCR(task_sw_race_going_out); break; case TASK_SW_IN: assert(task->map->res_count > 0); #if TASK_SW_DEBUG task_swapper_lock(); if (task_swap_debug && on_swapped_list(task)) { printf("task 0x%X on list, state is SW_IN\n", task); Debugger(""); } task_swapper_unlock(); #endif /* TASK_SW_DEBUG */ TASK_STATS_INCR(task_sw_race_in); if (make_unswappable) { task->swap_state = TASK_SW_UNSWAPPABLE; task_unlock(task); task_swapout_ineligible(task); } else task_unlock(task); return(KERN_SUCCESS); case TASK_SW_COMING_IN: /* * Raced with another task_swapin and lost; * wait for other one to complete first */ assert(task->map->res_count >= 0); /* * set MAKE_UNSWAPPABLE so that whoever is swapping * the task in will make it unswappable, and return */ if (make_unswappable) task->swap_flags |= TASK_SW_MAKE_UNSWAPPABLE; task->swap_flags |= TASK_SW_WANT_IN; assert_wait((event_t)&task->swap_state, FALSE); task_unlock(task); thread_block((void (*)(void)) 0); TASK_STATS_INCR(task_sw_race_coming_in); return(KERN_SUCCESS); case TASK_SW_UNSWAPPABLE: /* * This can happen, since task_terminate * unconditionally calls task_swapin. */ task_unlock(task); return(KERN_SUCCESS); default: panic("task_swapin bad state"); break; } if (make_unswappable) task->swap_flags |= TASK_SW_MAKE_UNSWAPPABLE; assert(task->swap_state == TASK_SW_COMING_IN); task_swapper_lock(); #if TASK_SW_DEBUG if (task_swap_debug && !on_swapped_list(task)) { printf("task 0x%X not on list\n", task); Debugger(""); } #endif /* TASK_SW_DEBUG */ queue_remove(&swapped_tasks, task, task_t, swapped_tasks); tasks_swapped_out--; task_swapins++; task_swapper_unlock(); /* * Iterate through all threads for this task and * release them, as required. They may not have been swapped * out yet. The task remains locked throughout. */ list = &task->thr_acts; thr_act = (thread_act_t) queue_first(list); while (!queue_end(list, (queue_entry_t) thr_act)) { boolean_t need_to_release; next = (thread_act_t) queue_next(&thr_act->thr_acts); /* * Keep task_swapper_lock across thread handling * to synchronize with task_swap_swapout_thread */ task_swapper_lock(); thread = act_lock_thread(thr_act); s = splsched(); if (thr_act->ast & AST_SWAPOUT) { /* thread hasn't gotten the AST yet, just clear it */ thread_ast_clear(thr_act, AST_SWAPOUT); need_to_release = FALSE; TASK_STATS_INCR(task_sw_before_ast); splx(s); act_unlock_thread(thr_act); } else { /* * If AST_SWAPOUT was cleared, then thread_hold, * or equivalent was done. */ need_to_release = TRUE; /* * Thread has hit AST, but it may not have * been dequeued yet, so we need to check. * NOTE: the thread may have been dequeued, but * has not yet been swapped (the task_swapper_lock * has been dropped, but the thread is not yet * locked), and the TH_SW_TASK_SWAPPING flag may * not have been cleared. In this case, we will do * an extra remque, which the task_swap_swapout_thread * has made safe, and clear the flag, which is also * checked by the t_s_s_t before doing the swapout. */ if (thread) thread_lock(thread); if (thr_act->swap_state & TH_SW_TASK_SWAPPING) { /* * hasn't yet been dequeued for swapout, * so clear flags and dequeue it first. */ thr_act->swap_state &= ~TH_SW_TASK_SWAPPING; assert(thr_act->thread == THREAD_NULL || !(thr_act->thread->state & TH_SWAPPED_OUT)); queue_remove(&swapout_thread_q, thr_act, thread_act_t, swap_queue); TASK_STATS_INCR(task_sw_before_swap); } else { TASK_STATS_INCR(task_sw_after_swap); /* * It's possible that the thread was * made unswappable before hitting the * AST, in which case it's still running. */ if (thr_act->swap_state == TH_SW_UNSWAPPABLE) { need_to_release = FALSE; TASK_STATS_INCR(task_sw_unswappable); } } if (thread) thread_unlock(thread); splx(s); act_unlock_thread(thr_act); } task_swapper_unlock(); /* * thread_release will swap in the thread if it's been * swapped out. */ if (need_to_release) { act_lock_thread(thr_act); thread_release(thr_act); act_unlock_thread(thr_act); } thr_act = next; } if (task->swap_flags & TASK_SW_MAKE_UNSWAPPABLE) { task->swap_flags &= ~TASK_SW_MAKE_UNSWAPPABLE; task->swap_state = TASK_SW_UNSWAPPABLE; swappable = FALSE; } else { task->swap_state = TASK_SW_IN; } task_swaprss_in += pmap_resident_count(task->map->pmap); task_swap_total_time += sched_tick - task->swap_stamp; /* note when task came back in */ task->swap_stamp = sched_tick; if (task->swap_flags & TASK_SW_WANT_IN) { task->swap_flags &= ~TASK_SW_WANT_IN; thread_wakeup((event_t)&task->swap_state); } assert((task->swap_flags & TASK_SW_ELIGIBLE) == 0); task_unlock(task); #if TASK_SW_DEBUG task_swapper_lock(); if (task_swap_debug && on_swapped_list(task)) { printf("task 0x%X on list at end of swap in\n", task); Debugger(""); } task_swapper_unlock(); #endif /* TASK_SW_DEBUG */ /* * Make the task eligible to be swapped again */ if (swappable) task_swapout_eligible(task); return(KERN_SUCCESS); }
task_t pick_outtask(void) { register task_t task; register task_t target_task = TASK_NULL; unsigned long task_rss; unsigned long target_rss = 0; boolean_t wired; boolean_t active; int nactive = 0; task_swapout_lock(); if (queue_empty(&eligible_tasks)) { /* not likely to happen */ task_swapout_unlock(); return(TASK_NULL); } task = (task_t)queue_first(&eligible_tasks); while (!queue_end(&eligible_tasks, (queue_entry_t)task)) { int s; register thread_act_t thr_act; thread_t th; task_lock(task); #if MACH_RT /* * Don't swap real-time tasks. * XXX Should we enforce that or can we let really critical * tasks use task_swappable() to make sure they never end up * n the eligible list ? */ if (task->policy & POLICYCLASS_FIXEDPRI) { goto tryagain; } #endif /* MACH_RT */ if (!task->active) { TASK_STATS_INCR(inactive_task_count); goto tryagain; } if (task->res_act_count == 0) { TASK_STATS_INCR(empty_task_count); goto tryagain; } assert(!queue_empty(&task->thr_acts)); thr_act = (thread_act_t)queue_first(&task->thr_acts); active = FALSE; th = act_lock_thread(thr_act); s = splsched(); if (th != THREAD_NULL) thread_lock(th); if ((th == THREAD_NULL) || (th->state == TH_RUN) || (th->state & TH_WAIT)) { /* * thread is "active": either runnable * or sleeping. Count it and examine * it further below. */ nactive++; active = TRUE; } if (th != THREAD_NULL) thread_unlock(th); splx(s); act_unlock_thread(thr_act); if (active && (task->swap_state == TASK_SW_IN) && ((sched_tick - task->swap_stamp) > min_res_time)) { long rescount = pmap_resident_count(task->map->pmap); /* * thread must be "active", task must be swapped * in and resident for at least min_res_time */ #if 0 /* DEBUG Test round-robin strategy. Picking biggest task could cause extreme * unfairness to such large interactive programs as xterm. Instead, pick the * first task that has any pages resident: */ if (rescount > 1) { task->ref_count++; target_task = task; task_unlock(task); task_swapout_unlock(); return(target_task); } #else if (rescount > target_rss) { /* * task is not swapped, and it has the * largest rss seen so far. */ task->ref_count++; target_rss = rescount; assert(target_task != task); if (target_task != TASK_NULL) task_deallocate(target_task); target_task = task; } #endif } tryagain: task_unlock(task); task = (task_t)queue_next(&task->swapped_tasks); } task_swapout_unlock(); /* only swap out if there are at least min_active_tasks */ if (nactive < min_active_tasks) { if (target_task != TASK_NULL) { task_deallocate(target_task); target_task = TASK_NULL; } } return(target_task); }
kern_return_t host_lockgroup_info( host_t host, lockgroup_info_array_t *lockgroup_infop, mach_msg_type_number_t *lockgroup_infoCntp) { lockgroup_info_t *lockgroup_info_base; lockgroup_info_t *lockgroup_info; vm_offset_t lockgroup_info_addr; vm_size_t lockgroup_info_size; vm_size_t lockgroup_info_vmsize; lck_grp_t *lck_grp; unsigned int i; vm_map_copy_t copy; kern_return_t kr; if (host == HOST_NULL) return KERN_INVALID_HOST; lck_mtx_lock(&lck_grp_lock); lockgroup_info_size = lck_grp_cnt * sizeof(*lockgroup_info); lockgroup_info_vmsize = round_page(lockgroup_info_size); kr = kmem_alloc_pageable(ipc_kernel_map, &lockgroup_info_addr, lockgroup_info_vmsize, VM_KERN_MEMORY_IPC); if (kr != KERN_SUCCESS) { lck_mtx_unlock(&lck_grp_lock); return(kr); } lockgroup_info_base = (lockgroup_info_t *) lockgroup_info_addr; lck_grp = (lck_grp_t *)queue_first(&lck_grp_queue); lockgroup_info = lockgroup_info_base; for (i = 0; i < lck_grp_cnt; i++) { lockgroup_info->lock_spin_cnt = lck_grp->lck_grp_spincnt; lockgroup_info->lock_spin_util_cnt = lck_grp->lck_grp_stat.lck_grp_spin_stat.lck_grp_spin_util_cnt; lockgroup_info->lock_spin_held_cnt = lck_grp->lck_grp_stat.lck_grp_spin_stat.lck_grp_spin_held_cnt; lockgroup_info->lock_spin_miss_cnt = lck_grp->lck_grp_stat.lck_grp_spin_stat.lck_grp_spin_miss_cnt; lockgroup_info->lock_spin_held_max = lck_grp->lck_grp_stat.lck_grp_spin_stat.lck_grp_spin_held_max; lockgroup_info->lock_spin_held_cum = lck_grp->lck_grp_stat.lck_grp_spin_stat.lck_grp_spin_held_cum; lockgroup_info->lock_mtx_cnt = lck_grp->lck_grp_mtxcnt; lockgroup_info->lock_mtx_util_cnt = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_util_cnt; lockgroup_info->lock_mtx_held_cnt = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_held_cnt; lockgroup_info->lock_mtx_miss_cnt = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_miss_cnt; lockgroup_info->lock_mtx_wait_cnt = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_wait_cnt; lockgroup_info->lock_mtx_held_max = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_held_max; lockgroup_info->lock_mtx_held_cum = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_held_cum; lockgroup_info->lock_mtx_wait_max = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_wait_max; lockgroup_info->lock_mtx_wait_cum = lck_grp->lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_wait_cum; lockgroup_info->lock_rw_cnt = lck_grp->lck_grp_rwcnt; lockgroup_info->lock_rw_util_cnt = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_util_cnt; lockgroup_info->lock_rw_held_cnt = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_held_cnt; lockgroup_info->lock_rw_miss_cnt = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_miss_cnt; lockgroup_info->lock_rw_wait_cnt = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_wait_cnt; lockgroup_info->lock_rw_held_max = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_held_max; lockgroup_info->lock_rw_held_cum = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_held_cum; lockgroup_info->lock_rw_wait_max = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_wait_max; lockgroup_info->lock_rw_wait_cum = lck_grp->lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_wait_cum; (void) strncpy(lockgroup_info->lockgroup_name,lck_grp->lck_grp_name, LOCKGROUP_MAX_NAME); lck_grp = (lck_grp_t *)(queue_next((queue_entry_t)(lck_grp))); lockgroup_info++; } *lockgroup_infoCntp = lck_grp_cnt; lck_mtx_unlock(&lck_grp_lock); if (lockgroup_info_size != lockgroup_info_vmsize) bzero((char *)lockgroup_info, lockgroup_info_vmsize - lockgroup_info_size); kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)lockgroup_info_addr, (vm_map_size_t)lockgroup_info_size, TRUE, ©); assert(kr == KERN_SUCCESS); *lockgroup_infop = (lockgroup_info_t *) copy; return(KERN_SUCCESS); }
/* * task_swapout: * A reference to the task must be held. * * Start swapping out a task by sending an AST_SWAPOUT to each thread. * When the threads reach a clean point, they queue themselves up on the * swapout_thread_q to be swapped out by the task_swap_swapout_thread. * The task can be swapped in at any point in this process. * * A task will not be fully swapped out (i.e. its map residence count * at zero) until all currently-swapped threads run and reach * a clean point, at which time they will be swapped again, * decrementing the swap_ast_waiting count on the task. * * Locking: no locks held upon entry and exit. * Task_lock is held throughout this function. */ kern_return_t task_swapout(task_t task) { thread_act_t thr_act; thread_t thread; queue_head_t *list; int s; task_swapout_lock(); task_lock(task); /* * NOTE: look into turning these into assertions if they * are invariants. */ if ((task->swap_state != TASK_SW_IN) || (!task->active)) { task_unlock(task); task_swapout_unlock(); return(KERN_FAILURE); } if (task->swap_flags & TASK_SW_ELIGIBLE) { queue_remove(&eligible_tasks, task, task_t, swapped_tasks); task->swap_flags &= ~TASK_SW_ELIGIBLE; } task_swapout_unlock(); /* set state to avoid races with task_swappable(FALSE) */ task->swap_state = TASK_SW_GOING_OUT; task->swap_rss = pmap_resident_count(task->map->pmap); task_swaprss_out += task->swap_rss; task->swap_ast_waiting = task->thr_act_count; /* * halt all threads in this task: * We don't need the thread list lock for traversal. */ list = &task->thr_acts; thr_act = (thread_act_t) queue_first(list); while (!queue_end(list, (queue_entry_t) thr_act)) { boolean_t swappable; thread_act_t ract; thread = act_lock_thread(thr_act); s = splsched(); if (!thread) swappable = (thr_act->swap_state != TH_SW_UNSWAPPABLE); else { thread_lock(thread); swappable = TRUE; for (ract = thread->top_act; ract; ract = ract->lower) if (ract->swap_state == TH_SW_UNSWAPPABLE) { swappable = FALSE; break; } } if (swappable) thread_ast_set(thr_act, AST_SWAPOUT); if (thread) thread_unlock(thread); splx(s); assert((thr_act->ast & AST_TERMINATE) == 0); act_unlock_thread(thr_act); thr_act = (thread_act_t) queue_next(&thr_act->thr_acts); } task->swap_stamp = sched_tick; task->swap_nswap++; assert((task->swap_flags&TASK_SW_WANT_IN) == 0); /* put task on the queue of swapped out tasks */ task_swapper_lock(); #if TASK_SW_DEBUG if (task_swap_debug && on_swapped_list(task)) { printf("task 0x%X already on list\n", task); Debugger(""); } #endif /* TASK_SW_DEBUG */ queue_enter(&swapped_tasks, task, task_t, swapped_tasks); tasks_swapped_out++; task_swapouts++; task_swapper_unlock(); task_unlock(task); return(KERN_SUCCESS); }
/* * timer_queue_migrate() is called by etimer_queue_migrate() * to move timer requests from the local processor (queue_from) * to a target processor's (queue_to). */ int timer_queue_migrate(mpqueue_head_t *queue_from, mpqueue_head_t *queue_to) { timer_call_t call; timer_call_t head_to; int timers_migrated = 0; DBG("timer_queue_migrate(%p,%p)\n", queue_from, queue_to); assert(!ml_get_interrupts_enabled()); assert(queue_from != queue_to); if (serverperfmode) { /* * if we're running a high end server * avoid migrations... they add latency * and don't save us power under typical * server workloads */ return -4; } /* * Take both local (from) and target (to) timer queue locks while * moving the timers from the local queue to the target processor. * We assume that the target is always the boot processor. * But only move if all of the following is true: * - the target queue is non-empty * - the local queue is non-empty * - the local queue's first deadline is later than the target's * - the local queue contains no non-migrateable "local" call * so that we need not have the target resync. */ timer_call_lock_spin(queue_to); head_to = TIMER_CALL(queue_first(&queue_to->head)); if (queue_empty(&queue_to->head)) { timers_migrated = -1; goto abort1; } timer_call_lock_spin(queue_from); if (queue_empty(&queue_from->head)) { timers_migrated = -2; goto abort2; } call = TIMER_CALL(queue_first(&queue_from->head)); if (CE(call)->deadline < CE(head_to)->deadline) { timers_migrated = 0; goto abort2; } /* perform scan for non-migratable timers */ do { if (call->flags & TIMER_CALL_LOCAL) { timers_migrated = -3; goto abort2; } call = TIMER_CALL(queue_next(qe(call))); } while (!queue_end(&queue_from->head, qe(call))); /* migration loop itself -- both queues are locked */ while (!queue_empty(&queue_from->head)) { call = TIMER_CALL(queue_first(&queue_from->head)); if (!simple_lock_try(&call->lock)) { /* case (2b) lock order inversion, dequeue only */ timer_queue_migrate_lock_skips++; (void) remque(qe(call)); call->async_dequeue = TRUE; continue; } timer_call_entry_dequeue(call); timer_call_entry_enqueue_deadline( call, queue_to, CE(call)->deadline); timers_migrated++; simple_unlock(&call->lock); } abort2: timer_call_unlock(queue_from); abort1: timer_call_unlock(queue_to); return timers_migrated; }
static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) { jb_frame *frame; long diff; /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */ /* get jitter info */ history_get(jb); /* target */ jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra; /* if a hard clamp was requested, use it */ if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) { jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf); jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf; } diff = jb->info.target - jb->info.current; /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */ /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ /* let's work on non-silent case first */ if (!jb->info.silence_begin_ts) { /* we want to grow */ if ((diff > 0) && /* we haven't grown in the delay length */ (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || /* we need to grow more than the "length" we have left */ (diff > queue_last(jb) - queue_next(jb)) ) ) { /* grow by interp frame length */ jb->info.current += interpl; jb->info.next_voice_ts += interpl; jb->info.last_voice_ms = interpl; jb->info.last_adjustment = now; jb->info.cnt_contig_interp++; /* assume silence instead of continuing to interpolate */ if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) { jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; } jb_dbg("G"); return JB_INTERP; } frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current); /* not a voice frame; just return it. */ if (frame && frame->type != JB_TYPE_VOICE) { /* track start of silence */ if (frame->type == JB_TYPE_SILENCE) { jb->info.silence_begin_ts = frame->ts; jb->info.cnt_contig_interp = 0; } *frameout = *frame; jb->info.frames_out++; jb_dbg("o"); return JB_OK; } /* voice frame is later than expected */ if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) { if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) { /* either we interpolated past this frame in the last jb_get */ /* or the frame is still in order, but came a little too quick */ *frameout = *frame; /* reset expectation for next frame */ jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; jb->info.frames_out++; decrement_losspct(jb); jb->info.cnt_contig_interp = 0; jb_dbg("v"); return JB_OK; } else { /* voice frame is late */ *frameout = *frame; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_late++; jb->info.frames_lost--; jb_dbg("l"); /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); jb_warninfo(jb); */ return JB_DROP; } } /* keep track of frame sizes, to allow for variable sized-frames */ if (frame && frame->ms > 0) { jb->info.last_voice_ms = frame->ms; } /* we want to shrink; shrink at 1 frame / 500ms */ /* unless we don't have a frame, then shrink 1 frame */ /* every 80ms (though perhaps we can shrink even faster */ /* in this case) */ if (diff < -jb->info.conf.target_extra && ((!frame && jb->info.last_adjustment + 80 < now) || (jb->info.last_adjustment + 500 < now))) { jb->info.last_adjustment = now; jb->info.cnt_contig_interp = 0; if (frame) { *frameout = *frame; /* shrink by frame size we're throwing out */ jb->info.current -= frame->ms; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_dropped++; jb_dbg("s"); return JB_DROP; } else { /* shrink by last_voice_ms */ jb->info.current -= jb->info.last_voice_ms; jb->info.frames_lost++; increment_losspct(jb); jb_dbg("S"); return JB_NOFRAME; } } /* lost frame */ if (!frame) { /* this is a bit of a hack for now, but if we're close to * target, and we find a missing frame, it makes sense to * grow, because the frame might just be a bit late; * otherwise, we presently get into a pattern where we return * INTERP for the lost frame, then it shows up next, and we * throw it away because it's late */ /* I've recently only been able to replicate this using * iaxclient talking to app_echo on asterisk. In this case, * my outgoing packets go through asterisk's (old) * jitterbuffer, and then might get an unusual increasing delay * there if it decides to grow?? */ /* Update: that might have been a different bug, that has been fixed.. * But, this still seemed like a good idea, except that it ended up making a single actual * lost frame get interpolated two or more times, when there was "room" to grow, so it might * be a bit of a bad idea overall */ /*if (diff > -1 * jb->info.last_voice_ms) { jb->info.current += jb->info.last_voice_ms; jb->info.last_adjustment = now; jb_warn("g"); return JB_INTERP; } */ jb->info.frames_lost++; increment_losspct(jb); jb->info.next_voice_ts += interpl; jb->info.last_voice_ms = interpl; jb->info.cnt_contig_interp++; /* assume silence instead of continuing to interpolate */ if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) { jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; } jb_dbg("L"); return JB_INTERP; } /* normal case; return the frame, increment stuff */ *frameout = *frame; jb->info.next_voice_ts += frame->ms; jb->info.frames_out++; jb->info.cnt_contig_interp = 0; decrement_losspct(jb); jb_dbg("v"); return JB_OK; } else { /* TODO: after we get the non-silent case down, we'll make the * silent case -- basically, we'll just grow and shrink faster * here, plus handle next_voice_ts a bit differently */ /* to disable silent special case altogether, just uncomment this: */ /* jb->info.silence_begin_ts = 0; */ /* shrink interpl len every 10ms during silence */ if (diff < -jb->info.conf.target_extra && jb->info.last_adjustment + 10 <= now) { jb->info.current -= interpl; jb->info.last_adjustment = now; } frame = queue_get(jb, now - jb->info.current); if (!frame) { return JB_NOFRAME; } else if (frame->type != JB_TYPE_VOICE) { /* normal case; in silent mode, got a non-voice frame */ *frameout = *frame; jb->info.frames_out++; return JB_OK; } if (frame->ts < jb->info.silence_begin_ts) { /* voice frame is late */ *frameout = *frame; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_late++; jb->info.frames_lost--; jb_dbg("l"); /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); jb_warninfo(jb); */ return JB_DROP; } else { /* voice frame */ /* try setting current to target right away here */ jb->info.current = jb->info.target; jb->info.silence_begin_ts = 0; jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; jb->info.last_voice_ms = frame->ms; jb->info.frames_out++; decrement_losspct(jb); *frameout = *frame; jb_dbg("V"); return JB_OK; } } }
// an exact copy of processor_set_things() except no mig conversion at the end! static kern_return_t chudxnu_private_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; 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 processor_set is locked & active */ 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)) { task_reference_internal(task); task_list[actual++] = task; } break; } case THING_THREAD: { thread_t thread, *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[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; } return (KERN_SUCCESS); }
// 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); }
/* * 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 (;;) { lck_mtx_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; 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 list is locked */ thread_list = (thread_t *) addr; for (i = 0, thread = (thread_t)(void *) queue_first(&threads); !queue_end(&threads, (queue_entry_t) thread); thread = (thread_t)(void *) queue_next(&thread->threads)) { thread_reference_internal(thread); thread_list[i++] = thread; } assert(i <= actual); lck_mtx_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 */ }
/******************************************************************************* * This function is executed in the main thread after its run loop gets * kicked from within kextd_kernel_request_loop(). *******************************************************************************/ void kextd_handle_kernel_request(void * info) { PTLockTakeLock(gKernelRequestQueueLock); while (!queue_empty(&g_request_queue)) { request_t * load_request = NULL; // must free request_t * this_load_request = NULL; // free if duplicate unsigned int type; char * kmod_name = NULL; // must release load_request = (request_t *)queue_first(&g_request_queue); queue_remove(&g_request_queue, load_request, request_t *, link); /***** * Scan the request queue for duplicates of the first one and * pull them out. */ this_load_request = (request_t *)queue_first(&g_request_queue); while (!queue_end((request_t *)&g_request_queue, this_load_request)) { request_t * next_load_request = NULL; // don't free next_load_request = (request_t *) queue_next(&this_load_request->link); if (load_request_equal(load_request, this_load_request)) { queue_remove(&g_request_queue, this_load_request, request_t *, link); free(this_load_request->kmodname); free(this_load_request); } this_load_request = next_load_request; } PTLockUnlock(gKernelRequestQueueLock); type = load_request->type; kmod_name = load_request->kmodname; free(load_request); if (kmod_name) { KXKextManagerError load_result; static boolean_t have_signalled_load = FALSE; kextd_load_kext(kmod_name, &load_result); free(kmod_name); if ((load_result == kKXKextManagerErrorNone || load_result == kKXKextManagerErrorAlreadyLoaded) && !have_signalled_load && (getppid() > 1)) { // ppid == 1 => parent is no longer waiting have_signalled_load = TRUE; int ret; if (g_verbose_level >= 1) { kextd_log("running kextcache"); } ret = system(KEXTCACHE_COMMAND); if (ret != 0) { kextd_error_log("kextcache exec(%d)", ret); } } } PTLockTakeLock(gKernelRequestQueueLock); } PTLockUnlock(gKernelRequestQueueLock); return; }
void queue_move_all(thread_queue *dst, thread_queue *src) { thread *th; while(th = queue_next(src)) queue_move(dst, src, th); }
thread *scheduler_next() { thread *ret = queue_next(&main_queue); return ret; }
gboolean spop_mpris2_player_next(Mpris2Player* obj, GDBusMethodInvocation* invoc) { g_debug("mpris2: next"); queue_next(TRUE); mpris2_player_complete_next(obj, invoc); return TRUE; }