248 lines
6.8 KiB
C
248 lines
6.8 KiB
C
/**
|
|
* \file
|
|
* \brief Distops delete step implementation
|
|
* from (usr/monitor/capops/deletestep.c)
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2016, ETH Zurich.
|
|
* All rights reserved.
|
|
*
|
|
* This file is distributed under the terms in the attached LICENSE file.
|
|
* If you do not find this file, copies can be found by writing to:
|
|
* ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
|
|
*/
|
|
|
|
#include "internal.h"
|
|
#include "distops/invocations.h"
|
|
#include "distops/caplock.h"
|
|
#include "distops/debug.h"
|
|
#include <aos/aos.h>
|
|
#include <aos/event_queue.h>
|
|
#include <aos/slot_alloc.h>
|
|
|
|
#include "mem_alloc.h" // for aos_ram_free()
|
|
|
|
#include "deletestep.h"
|
|
|
|
struct delete_st {
|
|
struct delete_queue_node qn;
|
|
struct event_queue_node lock_qn;
|
|
struct domcapref capref;
|
|
struct capability cap;
|
|
struct capref newcap;
|
|
void *result_handler;
|
|
bool wait;
|
|
void *st;
|
|
};
|
|
|
|
static struct event_queue trigger_queue;
|
|
static bool triggered;
|
|
static bool enqueued;
|
|
static int suspended;
|
|
static struct event_queue_node trigger_qn;
|
|
static struct event_closure step_closure;
|
|
static struct event_queue_node caplock_qn;
|
|
static struct delete_st delete_step_st;
|
|
static struct capref delcap;
|
|
static struct event_queue delete_queue;
|
|
static struct delete_queue_node *pending_head, *pending_tail;
|
|
|
|
static void delete_steps_cont(void *st);
|
|
static void delete_steps_clear(void *st);
|
|
static void delete_queue_notify(void);
|
|
|
|
struct waitset*
|
|
delete_steps_get_waitset(void)
|
|
{
|
|
return delete_queue.waitset;
|
|
}
|
|
|
|
void
|
|
delete_steps_init(struct waitset *ws)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
errval_t err;
|
|
|
|
struct waitset *myws = delete_steps_get_waitset();
|
|
if (myws != NULL) {
|
|
DEBUG_CAPOPS("delete stepping already initialized with ws=%p, doing nothing\n", myws);
|
|
return;
|
|
}
|
|
|
|
event_queue_init(&trigger_queue, ws, EVENT_QUEUE_CONTINUOUS);
|
|
triggered = false;
|
|
enqueued = false;
|
|
suspended = 0;
|
|
step_closure = MKCLOSURE(delete_steps_cont, NULL);
|
|
|
|
event_queue_init(&delete_queue, ws, EVENT_QUEUE_CONTINUOUS);
|
|
pending_head = pending_tail = NULL;
|
|
|
|
delete_step_st.wait = false;
|
|
delete_step_st.result_handler = NULL;
|
|
err = slot_alloc(&delcap);
|
|
PANIC_IF_ERR(err, "allocating delete_steps slot");
|
|
delete_step_st.capref = get_cap_domref(delcap);
|
|
err = slot_alloc(&delete_step_st.newcap);
|
|
PANIC_IF_ERR(err, "allocating delete_steps new cap slot");
|
|
}
|
|
|
|
void
|
|
delete_steps_trigger(void)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
if (!triggered) {
|
|
triggered = true;
|
|
if (!suspended && !enqueued) {
|
|
event_queue_add(&trigger_queue, &trigger_qn, step_closure);
|
|
enqueued = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
delete_steps_pause(void)
|
|
{
|
|
DEBUG_CAPOPS("%s: called from %p\n", __FUNCTION__,
|
|
__builtin_return_address(0));
|
|
suspended++;
|
|
}
|
|
|
|
void
|
|
delete_steps_resume(void)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
assert(suspended > 0);
|
|
suspended--;
|
|
if (!suspended) {
|
|
DEBUG_CAPOPS("%s: !suspended, continuing\n", __FUNCTION__);
|
|
event_queue_add(&trigger_queue, &trigger_qn, step_closure);
|
|
enqueued = true;
|
|
}
|
|
}
|
|
|
|
static void
|
|
delete_steps_delete_result(errval_t status, void *st)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
assert(err_is_ok(status));
|
|
delete_steps_resume();
|
|
}
|
|
|
|
static void
|
|
delete_steps_cont(void *st)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
errval_t err;
|
|
assert(triggered);
|
|
assert(enqueued);
|
|
enqueued = false;
|
|
if (suspended) {
|
|
DEBUG_CAPOPS("%s: suspended (%d); return\n", __FUNCTION__, suspended);
|
|
return;
|
|
}
|
|
|
|
err = monitor_delete_step(delcap);
|
|
if (err_no(err) == SYS_ERR_CAP_LOCKED) {
|
|
// XXX
|
|
DEBUG_CAPOPS("%s: cap locked\n", __FUNCTION__);
|
|
caplock_wait(get_cap_domref(NULL_CAP), &caplock_qn, step_closure);
|
|
}
|
|
if (err_no(err) == SYS_ERR_DELETE_LAST_OWNED) {
|
|
DEBUG_CAPOPS("%s: deleting last owned\n", __FUNCTION__);
|
|
assert(!delete_step_st.result_handler);
|
|
delete_step_st.result_handler = delete_steps_delete_result;
|
|
delete_step_st.st = NULL;
|
|
USER_PANIC("capops_delete_int() NYI");
|
|
//capops_delete_int(&delete_step_st);
|
|
}
|
|
else if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
|
|
DEBUG_CAPOPS("%s: cap not found, starting clear step\n", __FUNCTION__);
|
|
delete_steps_clear(st);
|
|
}
|
|
else if (err_is_fail(err)) {
|
|
USER_PANIC_ERR(err, "while performing delete steps");
|
|
}
|
|
else {
|
|
if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) {
|
|
DEBUG_CAPOPS("%s: sending reclaimed RAM to memserv.\n", __FUNCTION__);
|
|
aos_ram_free(delcap);
|
|
}
|
|
if (!enqueued) {
|
|
DEBUG_CAPOPS("%s: !enqueued, adding to queue\n", __FUNCTION__);
|
|
event_queue_add(&trigger_queue, &trigger_qn, step_closure);
|
|
enqueued = true;
|
|
}
|
|
}
|
|
DEBUG_CAPOPS("%s: done\n", __FUNCTION__);
|
|
}
|
|
|
|
static void
|
|
delete_steps_clear(void *st)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
errval_t err;
|
|
while (true) {
|
|
err = monitor_clear_step(delcap);
|
|
if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
|
|
break;
|
|
}
|
|
else if (err_is_fail(err)) {
|
|
USER_PANIC_ERR(err, "while performing clear steps");
|
|
}
|
|
else if (err_no(err) == SYS_ERR_RAM_CAP_CREATED) {
|
|
DEBUG_CAPOPS("%s: sending reclaimed RAM to memserv.\n", __FUNCTION__);
|
|
aos_ram_free(delcap);
|
|
}
|
|
}
|
|
DEBUG_CAPOPS("%s: finished, calling delete_queue_notify\n", __FUNCTION__);
|
|
triggered = false;
|
|
delete_queue_notify();
|
|
}
|
|
|
|
void
|
|
delete_queue_wait(struct delete_queue_node *qn, struct event_closure cont)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
// enqueue the node in the list of pending events
|
|
if (!pending_head) {
|
|
assert(!pending_tail);
|
|
pending_head = pending_tail = qn;
|
|
qn->next = NULL;
|
|
}
|
|
else {
|
|
assert(pending_tail);
|
|
assert(!pending_tail->next);
|
|
pending_tail->next = qn;
|
|
pending_tail = qn;
|
|
qn->next = NULL;
|
|
}
|
|
qn->cont = cont;
|
|
|
|
// trigger "stepping" mode of the delete/revoke state machine
|
|
delete_steps_trigger();
|
|
}
|
|
|
|
static void
|
|
delete_queue_notify(void)
|
|
{
|
|
DEBUG_CAPOPS("%s\n", __FUNCTION__);
|
|
// this should only be triggered when the "stepping" mode of the
|
|
// delete/revoke state machine completes, so a notify without any
|
|
// operations pending would be very strange and is probably a bug
|
|
assert(pending_head);
|
|
assert(pending_tail);
|
|
|
|
// extract the contents of the queue of currently pending delete operations
|
|
struct delete_queue_node *curr = pending_head;
|
|
pending_head = pending_tail = NULL;
|
|
|
|
// put them all in the event queue so they are executed
|
|
for ( ; curr; curr = curr->next) {
|
|
DEBUG_CAPOPS("%s: adding %p to ev q.\n", __FUNCTION__, curr);
|
|
event_queue_add(&delete_queue, &curr->qn, curr->cont);
|
|
}
|
|
}
|
|
|