blob: cf79ce868edda2a87ba8379e3c01c11ef5925d36 [file]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <autoconf.h>
#include <sel4test-driver/gen_config.h>
#include <assert.h>
#include <stdio.h>
#include <sel4/sel4.h>
#include <vka/object.h>
#include "../helpers.h"
/* FIXME: this is a temporary hack and MIN_BUDGET_US should be exported via libsel4 */
#ifndef MIN_BUDGET_US
#ifdef CONFIG_PLAT_TK1
#define MIN_BUDGET_US (2 * 100)
#else
#define MIN_BUDGET_US (2 * 10)
#endif
#endif
int test_sched_control_configure(env_t env)
{
int error;
vka_object_t sched_context;
error = vka_alloc_sched_context(&env->vka, &sched_context);
test_eq(error, 0);
seL4_CPtr sc = sched_context.cptr;
test_neq(sc, (seL4_Word)seL4_CapNull);
/* test it works */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 5000, 5000, 0, 0);
test_eq(error, seL4_NoError);
/* test calling it on something that isn't a sched context */
seL4_CPtr tcb = vka_alloc_tcb_leaky(&env->vka);
test_neq(tcb, (seL4_Word)seL4_CapNull);
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), tcb, 5000, 5000, 0, 0);
test_eq(error, seL4_InvalidCapability);
/* test a 0 budget doesn't work */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 0, 5000, 0, 0);
test_eq(error, seL4_RangeError);
/* test a period of 0 doesn't work */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 5000, 0, 0, 0);
test_eq(error, seL4_RangeError);
/* test budget > period doesn't work */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 5000, 1000, 0, 0);
test_eq(error, seL4_RangeError);
/* test budget < MIN_BUDGET doesn't work */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, MIN_BUDGET_US - 1, 5000, 0, 0);
test_eq(error, seL4_RangeError);
/* test budget == MIN_BUDGET does work */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, MIN_BUDGET_US, 5000, 0, 0);
test_eq(error, seL4_NoError);
//TODO test refills cases
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0001, "Test api_sched_ctrl_configure", test_sched_control_configure,
config_set(CONFIG_KERNEL_MCS))
static NORETURN int
sched_context_0002_fn(void)
{
while (1);
}
int test_sched_control_reconfigure(env_t env)
{
helper_thread_t thread;
int error;
create_helper_thread(env, &thread);
seL4_CPtr sc = thread.thread.sched_context.cptr;
/* reconfigure a paused thread */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 5000, 5000, 0, 0);
test_eq(error, seL4_NoError);
/* now start the thread */
start_helper(env, &thread, (helper_fn_t) sched_context_0002_fn, 0, 0, 0, 0);
/* let it run a little */
sel4test_sleep(env, 10 * NS_IN_MS);
/* reconfigure a resumed thread */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 10000, 10000, 0, 0);
test_eq(error, seL4_NoError);
/* let it run a little */
sel4test_sleep(env, 10 * NS_IN_MS);
/* less */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sc, 3000, 3000, 0, 0);
test_eq(error, seL4_NoError);
/* done! */
return SUCCESS;
}
DEFINE_TEST(SCHED_CONTEXT_0002, "Test reconfiguring a thread", test_sched_control_reconfigure,
config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER))
int
test_bind_errors(env_t env)
{
seL4_CPtr tcb = vka_alloc_tcb_leaky(&env->vka);
seL4_CPtr sched_context = vka_alloc_sched_context_leaky(&env->vka);
seL4_CPtr notification = vka_alloc_notification_leaky(&env->vka);
seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka);
/* binding an object that is not a tcb or ntfn should fail */
int error = api_sc_bind(sched_context, endpoint);
test_eq(error, seL4_InvalidCapability);
error = api_sc_bind(sched_context, tcb);
test_eq(error, seL4_NoError);
/* so should trying to bind a schedcontext that is already bound to tcb */
error = api_sc_bind(sched_context, tcb);
test_eq(error, seL4_IllegalOperation);
/* we can bind a notification if a tcb is bound, this will automatically
* unbind the tcb when the task waits for the notification */
error = api_sc_bind(sched_context, notification);
test_eq(error, seL4_NoError);
/* you can't bind a notification if a notification is already bound */
error = api_sc_bind(sched_context, notification);
test_eq(error, seL4_IllegalOperation);
/* check that unbinding works */
error = api_sc_unbind_object(sched_context, notification);
test_eq(error, seL4_NoError);
error = api_sc_unbind_object(sched_context, tcb);
test_eq(error, seL4_NoError);
/* check unbinding an object that is not a tcb or notification fails */
error = api_sc_unbind_object(sched_context, endpoint);
test_eq(error, seL4_InvalidCapability);
/* check trying to unbind a valid object that is not bound fails */
error = api_sc_unbind_object(sched_context, notification);
test_eq(error, seL4_IllegalOperation);
error = api_sc_unbind_object(sched_context, tcb);
test_eq(error, seL4_IllegalOperation);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0003, "Basic api_sc_bind/UnbindObject testing", test_bind_errors,
config_set(CONFIG_KERNEL_MCS));
void sched_context_0005_helper_fn(volatile int *state)
{
while (1) {
*state = *state + 1;
}
}
/* test deleting scheduling context from bound tcb stops tcb */
int test_delete_tcb_sched_context(env_t env)
{
helper_thread_t helper;
volatile int state = 0;
create_helper_thread(env, &helper);
start_helper(env, &helper, (helper_fn_t) sched_context_0005_helper_fn, (seL4_Word) &state, 0, 0, 0);
/* let helper run */
sel4test_sleep(env, 1 * NS_IN_S);
printf("Sleep....\n");
int prev_state = state;
test_geq(state, 0);
printf("Awake\n");
vka_free_object(&env->vka, &helper.thread.sched_context);
/* let it run again */
printf("Sleep....\n");
sel4test_sleep(env, 1 * NS_IN_S);
printf("Awake\n");
/* it should not have run */
test_eq(prev_state, state);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0005, "Test deleting a scheduling context prevents the bound tcb from running",
test_delete_tcb_sched_context, config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER));
void sched_context_0006_helper_fn(seL4_CPtr notification, int *state)
{
*state = 1;
seL4_Wait(notification, NULL);
*state = 2;
while (1);
}
/* test deleting tcb running on notification sched context returns it */
int test_delete_tcb_on_notification_context(env_t env)
{
helper_thread_t one, two;
volatile int state_one;
volatile int state_two;
seL4_CPtr notification = vka_alloc_notification_leaky(&env->vka);
create_helper_thread(env, &one);
create_helper_thread(env, &two);
/* set helpers to our prio so we can seL4_Yield to let them run */
set_helper_priority(env, &one, env->priority);
set_helper_priority(env, &two, env->priority);
start_helper(env, &one, (helper_fn_t) sched_context_0006_helper_fn, notification,
(seL4_Word) &state_one, 0, 0);
/* let the other thread run */
seL4_Yield();
test_eq(state_one, 1);
/* take away its sc and assign to notification */
int error = api_sc_unbind(one.thread.sched_context.cptr);
test_eq(error, seL4_NoError);
error = api_sc_bind(one.thread.sched_context.cptr, notification);
test_eq(error, seL4_NoError);
/* let it run and receive the notifications scheduling context */
seL4_Signal(notification);
seL4_Yield();
test_eq(error, seL4_NoError);
test_eq(state_one, 2);
/* kill it */
vka_free_object(&env->vka, &one.thread.tcb);
seL4_Yield();
test_eq(error, seL4_NoError);
/* now start the other thread */
start_helper(env, &two, (helper_fn_t) sched_context_0006_helper_fn, notification,
(seL4_Word) &state_two, 0, 0);
/* let it initialise */
seL4_Yield();
test_eq(error, 0);
test_eq(state_two, 1);
/* take away its sc */
vka_free_object(&env->vka, &two.thread.sched_context);
/* signal the notification */
seL4_Signal(notification);
/* signal the notification */
seL4_Signal(notification);
/* now let the other thread run - if the first thread gave the scheduling context back on deletion
* this should work */
seL4_Yield();
test_eq(error, seL4_NoError);
test_eq(state_two, 2);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0006, "Test deleting a tcb running on a notifications scheduling context returns it",
test_delete_tcb_on_notification_context, config_set(CONFIG_KERNEL_MCS));
int sched_context_007_helper_fn(void)
{
return 1;
}
void sched_context_007_lazy_fn(seL4_CPtr notification)
{
seL4_Wait(notification, NULL);
}
int test_passive_thread_start(env_t env)
{
helper_thread_t helper;
seL4_CPtr notification = vka_alloc_notification_leaky(&env->vka);
int error;
ZF_LOGD("z");
create_helper_thread(env, &helper);
ZF_LOGD("z");
error = api_sc_unbind(helper.thread.sched_context.cptr);
test_eq(error, seL4_NoError);
/* resume then bind */
start_helper(env, &helper, (helper_fn_t) sched_context_007_helper_fn, 0, 0, 0, 0);
error = api_sc_bind(helper.thread.sched_context.cptr, helper.thread.tcb.cptr);
test_eq(error, seL4_NoError);
error = wait_for_helper(&helper);
test_eq(error, 1);
/* bind then resume */
create_helper_thread(env, &helper);
error = api_sc_unbind(helper.thread.sched_context.cptr);
test_eq(error, seL4_NoError);
error = api_sc_bind(helper.thread.sched_context.cptr, helper.thread.tcb.cptr);
test_eq(error, seL4_NoError);
start_helper(env, &helper, (helper_fn_t) sched_context_007_helper_fn, 0, 0, 0, 0);
error = seL4_TCB_Resume(helper.thread.tcb.cptr);
test_eq(error, seL4_NoError);
error = wait_for_helper(&helper);
test_eq(error, 1);
/* lazy unbind: Bind scheduling context to both tcb and notification */
error = api_sc_bind(helper.thread.sched_context.cptr, notification);
test_eq(error, seL4_NoError);
/* set helper to higher prio to make behaviour deterministic */
set_helper_priority(env, &helper, env->priority + 1);
/* double check that the tcb is still bound */
error = api_sc_bind(helper.thread.sched_context.cptr, helper.thread.tcb.cptr);
test_eq(error, seL4_IllegalOperation);
start_helper(env, &helper, (helper_fn_t)sched_context_007_lazy_fn, notification, 0, 0, 0);
/* the tcb should have been unbound lazily when the helper called seL4_Wait */
error = api_sc_bind(helper.thread.sched_context.cptr, helper.thread.tcb.cptr);
test_eq(error, seL4_NoError);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0007, "test resuming a passive thread and binding scheduling context",
test_passive_thread_start, config_set(CONFIG_KERNEL_MCS))
static void
sched_context0008_client_fn(seL4_CPtr send_ep, seL4_CPtr wait_ep)
{
ZF_LOGD("Client send\n");
api_nbsend_wait(send_ep, seL4_MessageInfo_new(0, 0, 0, 0), wait_ep, NULL);
}
static void sched_context0008_proxy_fn(seL4_CPtr send_ep, seL4_CPtr wait_ep)
{
/* signal to test runner that we are initialised and waiting for client */
ZF_LOGD("Proxy init\n");
api_nbsend_wait(send_ep, seL4_MessageInfo_new(0, 0, 0, 0), wait_ep, NULL);
/* forward on the message we got */
ZF_LOGD("Proxy fwd\n");
api_nbsend_wait(send_ep, seL4_MessageInfo_new(0, 0, 0, 0), wait_ep, NULL);
ZF_LOGF("Should not get here");
}
static void sched_context0008_server_fn(seL4_CPtr init_ep, seL4_CPtr wait_ep)
{
ZF_LOGD("Server init\n");
/* tell test runner we are done by sending to init ep, then wait for proxy message */
api_nbsend_wait(init_ep, seL4_MessageInfo_new(0, 0, 0, 0), wait_ep, NULL);
ZF_LOGD("Server exit\n");
/* hold on to scheduling context */
}
static int test_delete_sendwait_tcb(env_t env)
{
helper_thread_t client, proxy, server;
seL4_CPtr client_send = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr client_wait = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr proxy_send = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr server_ep = vka_alloc_endpoint_leaky(&env->vka);
/* set up and start server */
ZF_LOGD("Create server\n");
int error = create_passive_thread(env, &server, (helper_fn_t) sched_context0008_server_fn,
server_ep, proxy_send, 0, 0);
test_eq(error, 0);
/* setup and start proxy */
ZF_LOGD("Create proxy\n");
error = create_passive_thread(env, &proxy, (helper_fn_t) sched_context0008_proxy_fn, proxy_send,
client_send, 0, 0);
test_eq(error, 0);
ZF_LOGD("Create client\n");
/* create and start the client */
create_helper_thread(env, &client);
start_helper(env, &client, (helper_fn_t) sched_context0008_client_fn, client_send,
client_wait, 0, 0);
ZF_LOGD("Wait for server\n");
/* wait for the server to finish, who has stolen the scheduling context */
wait_for_helper(&server);
ZF_LOGD("Kill server\n");
/* kill the server */
vka_free_object(&env->vka, &server.thread.tcb);
/* give client back its sc */
error = api_sc_bind(client.thread.sched_context.cptr, client.thread.tcb.cptr);
test_eq(error, seL4_NoError);
ZF_LOGD("Signal client\n");
seL4_Signal(client_wait);
ZF_LOGD("Wait for client\n");
/* now the client should finish */
wait_for_helper(&client);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0008, "Test deleting a tcb running on donated sc",
test_delete_sendwait_tcb, config_set(CONFIG_KERNEL_MCS))
void
sched_context_0009_server_fn(seL4_CPtr ep, volatile int *state, seL4_CPtr reply)
{
ZF_LOGD("Server init\n");
api_nbsend_recv(ep, seL4_MessageInfo_new(0, 0, 0, 0), ep, NULL, reply);
while (1) {
*state = *state + 1;
}
}
void sched_context_0009_client_fn(seL4_CPtr ep, volatile int *state)
{
ZF_LOGD("Client call\n");
seL4_Call(ep, seL4_MessageInfo_new(0, 0, 0, 0));
if (state != NULL) {
*state = *state + 1;
}
}
int test_sched_context_goes_to_to_caller_on_reply_cap_delete(env_t env)
{
helper_thread_t client, server;
seL4_CPtr ep, reply;
volatile int state = 0;
int prev_state = state;
int error;
ep = vka_alloc_endpoint_leaky(&env->vka);
test_neq(ep, (seL4_CPtr) seL4_CapNull);
reply = vka_alloc_reply_leaky(&env->vka);
test_neq(reply, (seL4_CPtr) seL4_CapNull);
/* create server */
create_passive_thread(env, &server, (helper_fn_t) sched_context_0009_server_fn, ep,
(seL4_Word) &state, reply, 0);
/* create client */
create_helper_thread(env, &client);
/* client calls blocking server */
start_helper(env, &client, (helper_fn_t) sched_context_0009_client_fn, ep, 0, 0, 0);
/* wait a bit, client should have called server */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_gt(state, prev_state);
prev_state = state;
/* delete reply cap */
error = cnode_delete(env, reply);
test_eq(error, seL4_NoError);
prev_state = state;
/* wait a bit, check server not running anymore */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_eq(state, prev_state);
/* save and resume client */
restart_after_syscall(env, &client);
printf("Waiting for client\n");
wait_for_helper(&client);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0009, "Test scheduling context goes to caller if reply cap deleted",
test_sched_context_goes_to_to_caller_on_reply_cap_delete, config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER))
void
sched_context_0010_client_fn(seL4_CPtr ep)
{
api_nbsend_wait(ep, seL4_MessageInfo_new(0, 0, 0, 0), ep, NULL);
}
int test_sched_context_unbind_server(env_t env)
{
helper_thread_t client, server;
volatile int state = 0;
int prev_state = state;
seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka);
test_neq(ep, (seL4_CPtr) seL4_CapNull);
seL4_CPtr reply = vka_alloc_reply_leaky(&env->vka);
test_neq(reply, (seL4_CPtr) seL4_CapNull);
/* create server */
create_passive_thread(env, &server, (helper_fn_t) sched_context_0009_server_fn, ep,
(seL4_Word) &state, reply, 0);
/* create client */
create_helper_thread(env, &client);
/* client calls blocking server */
start_helper(env, &client, (helper_fn_t) sched_context_0010_client_fn, ep, 0, 0, 0);
/* wait a bit, client should have called server */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_gt(state, prev_state);
prev_state = state;
/* unbind scheduling context */
int error = api_sc_unbind_object(client.thread.sched_context.cptr, server.thread.tcb.cptr);
test_eq(error, seL4_NoError);
/* wait a bit, check server not running anymore */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_eq(state, prev_state);
/* rebind the scheduling context to the client */
error = api_sc_bind(client.thread.sched_context.cptr, client.thread.tcb.cptr);
test_eq(error, seL4_NoError);
/* save and resume client */
restart_after_syscall(env, &client);
printf("Waiting for client\n");
wait_for_helper(&client);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0010, "Test unbinding scheduling context from server", test_sched_context_unbind_server,
config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER))
void
sched_context_0011_proxy_fn(seL4_CPtr in, seL4_CPtr out, seL4_CPtr reply)
{
ZF_LOGD("Proxy init\n");
api_nbsend_recv(in, seL4_MessageInfo_new(0, 0, 0, 0), in, NULL, reply);
ZF_LOGD("Proxy call\n");
seL4_Call(out, seL4_MessageInfo_new(0, 0, 0, 0));
ZF_LOGD("Proxy here\n");
}
int test_revoke_reply_on_call_chain_returns_sc(env_t env)
{
helper_thread_t client, proxy, server;
volatile int state = 0;
int error;
seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr ep2 = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr proxy_reply = vka_alloc_reply_leaky(&env->vka);
seL4_CPtr server_reply = vka_alloc_reply_leaky(&env->vka);
create_passive_thread(env, &server, (helper_fn_t) sched_context_0009_server_fn, ep2,
(seL4_Word) &state, server_reply, 0);
create_passive_thread(env, &proxy, (helper_fn_t) sched_context_0011_proxy_fn, ep, ep2, proxy_reply, 0);
create_helper_thread(env, &client);
start_helper(env, &client, (helper_fn_t) sched_context_0009_client_fn, ep, 0, 0, 0);
/* let a call b which calls the server, let the server run a bit */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_gt(state, 0);
/* kill the servers reply cap */
error = cnode_delete(env, server_reply);
test_eq(error, seL4_NoError);
/* check server stopped running */
int prev_state = state;
sel4test_sleep(env, 0.2 * NS_IN_S);
test_eq(prev_state, state);
/* kill the proxies reply cap */
error = cnode_delete(env, proxy_reply);
test_eq(error, seL4_NoError);
/* save and resume client */
restart_after_syscall(env, &client);
ZF_LOGD("Waiting for client\n");
wait_for_helper(&client);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0011, "Test revoking a reply on a call chain returns scheduling context along chain",
test_revoke_reply_on_call_chain_returns_sc, config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER))
/* sched 0011 but unordered */
int
test_revoke_reply_on_call_chain_unordered(env_t env)
{
helper_thread_t client, proxy, server;
volatile int state = 0;
volatile int client_state = 0;
int error;
seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr ep2 = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr proxy_reply = vka_alloc_reply_leaky(&env->vka);
seL4_CPtr server_reply = vka_alloc_reply_leaky(&env->vka);
create_passive_thread(env, &server, (helper_fn_t) sched_context_0009_server_fn, ep2,
(seL4_Word) &state, server_reply, 0);
create_passive_thread(env, &proxy, (helper_fn_t) sched_context_0011_proxy_fn, ep, ep2, proxy_reply, 0);
create_helper_thread(env, &client);
start_helper(env, &client, (helper_fn_t) sched_context_0009_client_fn, ep, (seL4_Word) &client_state, 0, 0);
/* let a call b which calls the server, let the server run a bit */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_gt(state, 0);
/* kill the proxies reply cap */
ZF_LOGD("Nuke proxy reply cap");
error = cnode_delete(env, proxy_reply);
test_eq(error, seL4_NoError);
/* kill the servers reply cap */
ZF_LOGD("Nuke server reply cap\n");
error = cnode_delete(env, server_reply);
test_eq(error, seL4_NoError);
/* check server is not still running */
int prev_state = state;
sel4test_sleep(env, 0.2 * NS_IN_S);
test_eq(state, prev_state);
/* save and resume client */
restart_after_syscall(env, &client);
/* check the client lost its scheduling context and isn't running */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_eq(client_state, 0);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0012, "Test revoking a reply on a call chain unorderd",
test_revoke_reply_on_call_chain_unordered, config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER))
int
test_revoke_sched_context_on_call_chain(env_t env)
{
helper_thread_t client, proxy, server;
volatile int state = 0;
int error;
seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr ep2 = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr proxy_reply = vka_alloc_reply_leaky(&env->vka);
seL4_CPtr server_reply = vka_alloc_reply_leaky(&env->vka);
create_passive_thread(env, &server, (helper_fn_t) sched_context_0009_server_fn, ep2,
(seL4_Word) &state, server_reply, 0);
create_passive_thread(env, &proxy, (helper_fn_t) sched_context_0011_proxy_fn, ep, ep2, proxy_reply, 0);
create_helper_thread(env, &client);
start_helper(env, &client, (helper_fn_t) sched_context_0009_client_fn, ep, 0, 0, 0);
/* let client call proxy which calls the server, let the server run a bit */
sel4test_sleep(env, 0.2 * NS_IN_S);
test_gt(state, 0);
/* nuke the scheduling context */
vka_free_object(&env->vka, &client.thread.sched_context);
/* check server stopped running */
int prev_state = state;
sel4test_sleep(env, 0.2 * NS_IN_S);
test_eq(prev_state, state);
/* nuke the reply cap */
error = cnode_delete(env, server_reply);
test_eq(error, seL4_NoError);
/* give the proxy a scheduling context */
seL4_CPtr sched_context = vka_alloc_sched_context_leaky(&env->vka);
test_neq(sched_context, (seL4_CPtr) seL4_CapNull);
error = api_sc_bind(sched_context, proxy.thread.tcb.cptr);
test_eq(error, seL4_NoError);
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sched_context,
5 * US_IN_S, 5 * US_IN_S, 0, 0);
test_eq(error, seL4_NoError);
restart_after_syscall(env, &proxy);
ZF_LOGD("Waiting for proxy\n");
wait_for_helper(&proxy);
error = api_sc_unbind_object(sched_context, proxy.thread.tcb.cptr);
test_eq(error, seL4_NoError);
/* give the client a scheduling context */
error = api_sc_bind(sched_context, client.thread.tcb.cptr);
test_eq(error, seL4_NoError);
restart_after_syscall(env, &client);
ZF_LOGD("Waiting for Client\n");
wait_for_helper(&client);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0013, "Test revoking a scheduling context on a call chain",
test_revoke_sched_context_on_call_chain, config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_HAVE_TIMER))
/* Try to recreate race situation of issue 633 */
int test_smp_delete_sched_context(env_t env)
{
seL4_Error error;
helper_thread_t helper;
volatile int state = 0;
int prev_state = state;
create_helper_thread(env, &helper);
set_helper_priority(env, &helper, env->priority - 1);
/* Run it on another core and time it such that it runs out of budget during the SC free */
error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, CONFIG_MAX_NUM_NODES - 1),
helper.thread.sched_context.cptr, MIN_BUDGET_US, 10 * US_IN_MS, 0, 0);
test_eq(error, seL4_NoError);
start_helper(env, &helper, (helper_fn_t)sched_context_0005_helper_fn, (seL4_Word)&state, 0, 0, 0);
/* Wait till helper runs */
while (state == prev_state);
vka_free_object(&env->vka, &helper.thread.sched_context);
return sel4test_get_result();
}
DEFINE_TEST(SCHED_CONTEXT_0014, "Test deleting a scheduling context while it runs out of budget on another core",
test_smp_delete_sched_context, config_set(CONFIG_KERNEL_MCS) &&CONFIG_MAX_NUM_NODES > 1);