/* The enclosed test relies on the current thread being able to create two * threads of unequal priority, both less than the caller's own priority. For * this we need at least 3 priority levels, assuming that the current thread is * running at the highest priority. */ static int test_set_priority(struct env* env) { helper_thread_t thread1; helper_thread_t thread2; ZF_LOGD("test_set_priority starting\n"); create_helper_thread(env, &thread1); set_helper_priority(&thread1, SCHED0005_HIGHEST_PRIO); create_helper_thread(env, &thread2); set_helper_priority(&thread2, SCHED0005_HIGHEST_PRIO - 1); set_priority_step = 0; ZF_LOGD(" "); start_helper(env, &thread1, (helper_fn_t) set_priority_helper_1, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2.thread.tcb.cptr, 0, 0); start_helper(env, &thread2, (helper_fn_t) set_priority_helper_2, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2.thread.tcb.cptr, 0, 0); wait_for_helper(&thread1); wait_for_helper(&thread2); test_check(set_priority_step == 4); ZF_LOGD("\n"); cleanup_helper(env, &thread1); cleanup_helper(env, &thread2); return sel4test_get_result(); }
static int test_suspend(struct env* env) { helper_thread_t thread1; helper_thread_t thread2a; helper_thread_t thread2b; ZF_LOGD("Starting test_suspend\n"); create_helper_thread(env, &thread1); ZF_LOGD("Show me\n"); create_helper_thread(env, &thread2a); create_helper_thread(env, &thread2b); /* First set all the helper threads to have unique priorities * and then start them in order of priority. This is so when * the 'start_helper' function does an IPC to the helper * thread, it doesn't allow one of the already started helper * threads to run at all */ set_helper_priority(&thread1, 0); set_helper_priority(&thread2a, 1); set_helper_priority(&thread2b, 2); start_helper(env, &thread1, (helper_fn_t) suspend_test_helper_1, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2a.thread.tcb.cptr, (seL4_Word) &thread2b.thread.tcb.cptr, 0); start_helper(env, &thread2a, (helper_fn_t) suspend_test_helper_2a, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2a.thread.tcb.cptr, (seL4_Word) &thread2b.thread.tcb.cptr, 0); start_helper(env, &thread2b, (helper_fn_t) suspend_test_helper_2b, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2a.thread.tcb.cptr, (seL4_Word) &thread2b.thread.tcb.cptr, 0); /* Now set their priorities to what we want */ set_helper_priority(&thread1, 100); set_helper_priority(&thread2a, 101); set_helper_priority(&thread2b, 101); suspend_test_step = 0; ZF_LOGD(" "); wait_for_helper(&thread1); wait_for_helper(&thread2b); CHECK_STEP(suspend_test_step, 6); ZF_LOGD("\n"); cleanup_helper(env, &thread1); cleanup_helper(env, &thread2a); cleanup_helper(env, &thread2b); return sel4test_get_result(); }
static int test_ipc_prios(struct env* env) { vka_t *vka = &env->vka; helper_thread_t thread0; helper_thread_t thread1; helper_thread_t thread2; helper_thread_t thread3; int result = 0; ipc_test_data_t data; memset(&data, 0, sizeof(data)); data.ep0 = vka_alloc_endpoint_leaky(vka); data.ep1 = vka_alloc_endpoint_leaky(vka); data.ep2 = vka_alloc_endpoint_leaky(vka); data.ep3 = vka_alloc_endpoint_leaky(vka); create_helper_thread(env, &thread0); set_helper_priority(&thread0, 0); create_helper_thread(env, &thread1); set_helper_priority(&thread1, 1); create_helper_thread(env, &thread2); set_helper_priority(&thread2, 2); create_helper_thread(env, &thread3); set_helper_priority(&thread3, 3); data.tcb0 = thread0.thread.tcb.cptr; data.tcb1 = thread1.thread.tcb.cptr; data.tcb2 = thread2.thread.tcb.cptr; data.tcb3 = thread3.thread.tcb.cptr; ZF_LOGD(" "); ipc_test_step = 0; start_helper(env, &thread0, (helper_fn_t) ipc_test_helper_0, (seL4_Word) &data, 0, 0, 0); start_helper(env, &thread1, (helper_fn_t) ipc_test_helper_1, (seL4_Word) &data, 0, 0, 0); start_helper(env, &thread2, (helper_fn_t) ipc_test_helper_2, (seL4_Word) &data, 0, 0, 0); start_helper(env, &thread3, (helper_fn_t) ipc_test_helper_3, (seL4_Word) &data, 0, 0, 0); result |= (int)wait_for_helper(&thread1); result |= (int)wait_for_helper(&thread3); CHECK_STEP(ipc_test_step, 10); ZF_LOGD("\n"); cleanup_helper(env, &thread0); cleanup_helper(env, &thread1); cleanup_helper(env, &thread2); cleanup_helper(env, &thread3); return result; }
static int test_full_cspace(env_t env) { int error; seL4_CPtr cnode[CONFIG_WORD_SIZE]; seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka); seL4_Word ep_pos = 1; /* Create 32 or 64 cnodes, each resolving one bit. */ for (unsigned int i = 0; i < CONFIG_WORD_SIZE; i++) { cnode[i] = vka_alloc_cnode_object_leaky(&env->vka, 1); assert(cnode[i]); } /* Copy cnode i to alternating slots in cnode i-1. */ seL4_Word slot = 0; for (unsigned int i = 1; i < CONFIG_WORD_SIZE; i++) { error = seL4_CNode_Copy( cnode[i - 1], slot, 1, env->cspace_root, cnode[i], seL4_WordBits, seL4_AllRights); test_assert(!error); ep_pos |= (slot << i); slot ^= 1; } /* In the final cnode, put an IPC endpoint in slot 1. */ error = seL4_CNode_Copy( cnode[CONFIG_WORD_SIZE - 1], slot, 1, env->cspace_root, ep, seL4_WordBits, seL4_AllRights); test_assert(!error); /* Start a helper thread in our own cspace, to let it get set up. */ helper_thread_t t; create_helper_thread(env, &t); start_helper(env, &t, ipc_caller, ep, ep_pos, CONFIG_WORD_SIZE, 0); /* Wait for it. */ seL4_MessageInfo_t tag; seL4_Word sender_badge = 0; tag = seL4_Recv(ep, &sender_badge); test_assert(seL4_MessageInfo_get_length(tag) == 1); test_assert(seL4_GetMR(0) == READY_MAGIC); /* Now switch its cspace. */ error = seL4_TCB_SetSpace(t.thread.tcb.cptr, t.fault_endpoint, cnode[0], seL4_NilData, env->page_directory, seL4_NilData); test_assert(!error); /* And now wait for it to do some tests and return to us. */ tag = seL4_Recv(ep, &sender_badge); test_assert(seL4_MessageInfo_get_length(tag) == 1); test_assert(seL4_GetMR(0) == SUCCESS_MAGIC); cleanup_helper(env, &t); 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(); }
/* * Free all used resources in the tree */ bool syn_tree::cleanup(void) { bool res; // clear all other attributes res = cleanup_helper(&root); if(res) cur = NULL; return res; }
/* * Remove the current token (moves current token to parent token) */ bool syn_tree::remove(void) { token *parent = NULL; // check that current token exists if(!cur) return false; // remove current token and move to parent token if(!cur->get_parent()) { cleanup_helper(&cur); root = cur; } else { parent = cur->get_parent(); for(unsigned int pos = 0; pos < parent->size(); pos++) if(parent->get_child(pos) == cur) { parent->remove_child(pos); break; } cleanup_helper(&cur); cur = parent; } return true; }
int test_tcb_null_cspace_setspace(env_t env) { helper_thread_t thread; int error; create_helper_thread(env, &thread); /* This should fail because we're passing an invalid CSpace cap. */ error = seL4_TCB_SetSpace(thread.thread.tcb.cptr, 0, seL4_CapNull, seL4_CapData_Guard_new(0, 0), env->page_directory, seL4_CapData_Guard_new(0, 0)); cleanup_helper(env, &thread); return error ? sel4test_get_result() : FAILURE; }
static int test_all_priorities(struct env* env) { int i; helper_thread_t **threads = (helper_thread_t **) malloc(sizeof(helper_thread_t*) * NUM_PRIOS); assert(threads != NULL); for (i = 0; i < NUM_PRIOS; i++) { threads[i] = (helper_thread_t*) malloc(sizeof(helper_thread_t)); assert(threads[i]); } vka_t *vka = &env->vka; ZF_LOGD("Testing all thread priorities"); volatile seL4_Word last_prio = MAX_PRIO + 1; seL4_CPtr ep = vka_alloc_endpoint_leaky(vka); for (int prio = MIN_PRIO; prio <= MAX_PRIO; prio++) { int idx = prio - MIN_PRIO; test_check(idx >= 0 && idx < NUM_PRIOS); create_helper_thread(env, threads[idx]); set_helper_priority(threads[idx], prio); start_helper(env, threads[idx], (helper_fn_t) prio_test_func, prio, (seL4_Word) &last_prio, ep, 0); } /* Now block. */ seL4_Word sender_badge = 0; seL4_Recv(ep, &sender_badge); /* When we get woken up, last_prio should be MIN_PRIO. */ test_check(last_prio == MIN_PRIO); for (int prio = MIN_PRIO; prio <= MAX_PRIO; prio++) { int idx = prio - MIN_PRIO; cleanup_helper(env, threads[idx]); free(threads[idx]); } free(threads); return sel4test_get_result(); }
/* * Removes a child node (recursively) from the current token */ bool syn_tree::remove_child(unsigned int index) { // check that current token exists if(!cur) return false; // check that index is with-in-bounds if(!get_size() || index >= get_size()) return false; // cleanup token *child = cur->get_child(index); cur->remove_child(index); cleanup_helper(&child); return true; }
/* * Release resources used by tree */ bool syn_tree::cleanup_helper(token **root) { unsigned int children; // check that root token exists if(!(*root)) return 0; children = (*root)->size(); // remove all children of current token for(unsigned int i = 0; i < children; i++) { token *child = (*root)->get_child(i); if(!cleanup_helper(&child)) return false; } // remove child tokens (*root)->remove_children(); // remove root token delete (*root); (*root) = NULL; return true; }
static int test_ep_recycle(env_t env) { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); struct { helper_thread_t thread; seL4_CPtr badged_ep; seL4_CPtr derived_badged_ep; volatile seL4_Word done; } senders[NUM_BADGED_CLIENTS]; helper_thread_t bouncer; seL4_CPtr bounce_ep; UNUSED int error; seL4_CPtr ep; /* Create the master endpoint. */ ep = vka_alloc_endpoint_leaky(&env->vka); /* Create N badged endpoints, and derive each of them. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { senders[i].badged_ep = get_free_slot(env); assert(senders[i].badged_ep != 0); senders[i].derived_badged_ep = get_free_slot(env); assert(senders[i].derived_badged_ep != 0); seL4_CapData_t cap_data; cap_data = seL4_CapData_Badge_new (i + 200); error = cnode_mint(env, ep, senders[i].badged_ep, seL4_AllRights, cap_data); assert(!error); error = cnode_copy(env, senders[i].badged_ep, senders[i].derived_badged_ep, seL4_AllRights); assert(!error); create_helper_thread(env, &senders[i].thread); set_helper_priority(&senders[i].thread, 100); senders[i].done = -1; } /* Create a bounce thread so we can get lower prio threads to run. */ bounce_ep = vka_alloc_endpoint_leaky(&env->vka); create_helper_thread(env, &bouncer); set_helper_priority(&bouncer, 0); start_helper(env, &bouncer, bouncer_func, bounce_ep, 0, 0, 0); for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { start_helper(env, &senders[i].thread, (helper_fn_t) call_func, senders[i].derived_badged_ep, i + 100, (seL4_Word) &senders[i].done, 0); } /* Let the sender threads run. */ seL4_Call(bounce_ep, tag); /* Receive a message from each endpoint and check the badge. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { seL4_Word sender_badge; seL4_MessageInfo_ptr_set_length(&tag, 1); tag = seL4_Recv(ep, &sender_badge); assert(seL4_MessageInfo_get_length(tag) == 1); assert(seL4_GetMR(0) == sender_badge - 100); seL4_SetMR(0, ~seL4_GetMR(0)); seL4_Reply(tag); } /* Let the sender threads run. */ seL4_Call(bounce_ep, tag); /* Check none of the threads have failed yet. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { assert(senders[i].done == 0); } /* Recycle each endpoint. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { error = cnode_recycle(env, senders[i].badged_ep); assert(!error); /* Let thread run. */ seL4_Call(bounce_ep, tag); /* Check that only the intended threads have now aborted. */ for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { if (j <= i) { assert(senders[j].done == 1); } else { assert(senders[j].done == 0); } } } seL4_Call(bounce_ep, tag); for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { cleanup_helper(env, &senders[i].thread); } cleanup_helper(env, &bouncer); return sel4test_get_result(); }