void run_benchmark(void *faulter_fn, void *handler_fn, seL4_CPtr done_ep) { int error = sel4utils_start_thread(&fault_handler, (sel4utils_thread_entry_fn) handler_fn, (void *) N_HANDLER_ARGS, (void *) handler_argv, true); ZF_LOGF_IF(error, "Failed to start handler"); if (config_set(CONFIG_KERNEL_RT)) { /* convert the fault handler to passive */ ZF_LOGD("Waiting to convert handler to passive"); seL4_Wait(done_ep, NULL); ZF_LOGD("unbound sc\n"); error = api_sc_unbind(fault_handler.sched_context.cptr); ZF_LOGF_IF(error, "Failed to convert to passive"); } error = sel4utils_start_thread(&faulter, (sel4utils_thread_entry_fn) faulter_fn, (void *) N_FAULTER_ARGS, (void *) faulter_argv, true); ZF_LOGF_IF(error, "Failed to start faulter"); /* benchmark runs */ benchmark_wait_children(done_ep, "faulter", 1); if (config_set(CONFIG_KERNEL_RT)) { /* convert the fault handler to active */ ZF_LOGD("Rebound sc\n"); error = api_sc_bind(fault_handler.sched_context.cptr, fault_handler.tcb.cptr); ZF_LOGF_IF(error, "Failed to convert to active"); } benchmark_wait_children(done_ep, "fault handler", 1); error = seL4_TCB_Suspend(faulter.tcb.cptr); ZF_LOGF_IF(error, "Failed to suspend faulter"); error = seL4_TCB_Suspend(fault_handler.tcb.cptr); ZF_LOGF_IF(error, "Failed to suspend fault handler"); }
static int suspend_test_helper_2a(seL4_CPtr *t1, seL4_CPtr *t2a, seL4_CPtr *t2b) { /* Helper function that runs at a higher priority. */ /* Start here. */ CHECK_STEP(suspend_test_step, 0); /* Wait for a timer tick to make 2b run. */ while (suspend_test_step == 1) /* spin */{ ; } /* Suspend helper 2b. */ int error = seL4_TCB_Suspend(*t2b); test_check(!error); CHECK_STEP(suspend_test_step, 2); /* Now suspend ourselves, passing control to the low priority process to * resume 2b. */ error = seL4_TCB_Suspend(*t2a); test_check(!error); return sel4test_get_result(); }
/* * Test that thread suspending works when idling the system. * Note: This test non-deterministically fails. If you find only this test * try re-running the test suite. */ static int test_thread_suspend(env_t env) { helper_thread_t t1; volatile seL4_Word counter; ZF_LOGD("test_thread_suspend\n"); create_helper_thread(env, &t1); set_helper_priority(&t1, 100); start_helper(env, &t1, (helper_fn_t) counter_func, (seL4_Word) &counter, 0, 0, 0); timer_periodic(env->timer->timer, 10 * NS_IN_MS); timer_start(env->timer->timer); sel4_timer_handle_single_irq(env->timer); seL4_Word old_counter; /* Let the counter thread run. We might have a pending interrupt, so * wait twice. */ wait_for_timer_interrupt(env); wait_for_timer_interrupt(env); old_counter = counter; /* Let it run again. */ wait_for_timer_interrupt(env); /* Now, counter should have moved. */ test_check(counter != old_counter); old_counter = counter; /* Suspend the thread, and wait again. */ seL4_TCB_Suspend(t1.thread.tcb.cptr); wait_for_timer_interrupt(env); /* Counter should not have moved. */ test_check(counter == old_counter); old_counter = counter; /* Check once more for good measure. */ wait_for_timer_interrupt(env); /* Counter should not have moved. */ test_check(counter == old_counter); old_counter = counter; /* Resume the thread and check it does move. */ seL4_TCB_Resume(t1.thread.tcb.cptr); wait_for_timer_interrupt(env); test_check(counter != old_counter); /* Done. */ timer_stop(env->timer->timer); sel4_timer_handle_single_irq(env->timer); cleanup_helper(env, &t1); return sel4test_get_result(); }
static void sel4_abort(void) { /* Suspend ourselves. This will cap fault if a setup routine has not saved * our TCB cap in the TLS region. */ seL4_TCB_Suspend(camkes_get_tls()->tcb_cap); /* We expect to never be woken up. */ while (1); /* Shut the compiler up about noreturn. */ }
int vm_stop(vm_t* vm) { return seL4_TCB_Suspend(vm_get_tcb(vm)); }
int main(int argc, char **argv) { env_t *env; irquser_results_t *results; vka_object_t endpoint = {0}; static size_t object_freq[seL4_ObjectTypeCount] = { [seL4_TCBObject] = 2, [seL4_EndpointObject] = 1, #ifdef CONFIG_KERNEL_RT [seL4_SchedContextObject] = 2, [seL4_ReplyObject] = 2 #endif }; env = benchmark_get_env(argc, argv, sizeof(irquser_results_t), object_freq); benchmark_init_timer(env); results = (irquser_results_t *) env->results; if (vka_alloc_endpoint(&env->slab_vka, &endpoint) != 0) { ZF_LOGF("Failed to allocate endpoint\n"); } /* set up globals */ done_ep = endpoint.cptr; timer = &env->timer; timer_signal = env->ntfn.cptr; int error = ltimer_reset(&env->timer.ltimer); ZF_LOGF_IF(error, "Failed to start timer"); error = ltimer_set_timeout(&env->timer.ltimer, INTERRUPT_PERIOD_NS, TIMEOUT_PERIODIC); ZF_LOGF_IF(error, "Failed to configure timer"); sel4bench_init(); sel4utils_thread_t ticker, spinner; /* measurement overhead */ ccnt_t start, end; for (int i = 0; i < N_RUNS; i++) { SEL4BENCH_READ_CCNT(start); SEL4BENCH_READ_CCNT(end); results->overheads[i] = end - start; } /* create a frame for the shared time variable so we can share it between processes */ ccnt_t *local_current_time = (ccnt_t *) vspace_new_pages(&env->vspace, seL4_AllRights, 1, seL4_PageBits); if (local_current_time == NULL) { ZF_LOGF("Failed to allocate page"); } /* first run the benchmark between two threads in the current address space */ benchmark_configure_thread(env, endpoint.cptr, seL4_MaxPrio - 1, "ticker", &ticker); benchmark_configure_thread(env, endpoint.cptr, seL4_MaxPrio - 2, "spinner", &spinner); error = sel4utils_start_thread(&ticker, (sel4utils_thread_entry_fn) ticker_fn, (void *) results->thread_results, (void *) local_current_time, true); if (error) { ZF_LOGF("Failed to start ticker"); } char strings[1][WORD_STRING_SIZE]; char *spinner_argv[1]; sel4utils_create_word_args(strings, spinner_argv, 1, (seL4_Word) local_current_time); error = sel4utils_start_thread(&spinner, (sel4utils_thread_entry_fn) spinner_fn, (void *) 1, (void *) spinner_argv, true); assert(!error); benchmark_wait_children(endpoint.cptr, "child of irq-user", 1); /* stop spinner thread */ error = seL4_TCB_Suspend(spinner.tcb.cptr); assert(error == seL4_NoError); error = seL4_TCB_Suspend(ticker.tcb.cptr); assert(error == seL4_NoError); /* now run the benchmark again, but run the spinner in another address space */ /* restart ticker */ error = sel4utils_start_thread(&ticker, (sel4utils_thread_entry_fn) ticker_fn, (void *) results->process_results, (void *) local_current_time, true); assert(!error); sel4utils_process_t spinner_process; benchmark_shallow_clone_process(env, &spinner_process, seL4_MaxPrio - 2, spinner_fn, "spinner"); /* share the current time variable with the spinner process */ void *current_time_remote = vspace_share_mem(&env->vspace, &spinner_process.vspace, (void *) local_current_time, 1, seL4_PageBits, seL4_AllRights, true); assert(current_time_remote != NULL); /* start the spinner process */ sel4utils_create_word_args(strings, spinner_argv, 1, (seL4_Word) current_time_remote); error = sel4utils_spawn_process(&spinner_process, &env->slab_vka, &env->vspace, 1, spinner_argv, 1); if (error) { ZF_LOGF("Failed to start spinner process"); } benchmark_wait_children(endpoint.cptr, "child of irq-user", 1); /* done -> results are stored in shared memory so we can now return */ benchmark_finished(EXIT_SUCCESS); return 0; }