2 * Copyright (c) 2012 ETH Zurich.
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
10 #include <barrelfish/barrelfish.h>
16 #include "delete_int.h"
17 #include "dom_invocations.h"
18 #include "monitor_debug.h"
20 struct revoke_slave_st *slaves_head = 0, *slaves_tail = 0;
22 struct revoke_master_st {
23 struct delete_queue_node del_qn;
25 struct capability rawcap;
26 struct capsend_mc_st revoke_mc_st;
27 struct capsend_destset dests;
28 revoke_result_handler_t result_handler;
30 bool local_fin, remote_fin;
33 struct revoke_slave_st {
34 struct intermon_msg_queue_elem im_qn;
35 struct delete_queue_node del_qn;
36 struct capability rawcap;
41 struct revoke_slave_st *next;
44 static void revoke_result__rx(errval_t result,
45 struct revoke_master_st *st,
47 static void revoke_retrieve__rx(errval_t result, void *st_);
48 static void revoke_local(struct revoke_master_st *st);
49 static void revoke_no_remote(struct revoke_master_st *st);
50 static errval_t revoke_mark__send(struct intermon_binding *b,
51 intermon_caprep_t *caprep,
52 struct capsend_mc_st *mc_st);
53 static void revoke_ready__send(struct intermon_binding *b,
54 struct intermon_msg_queue_elem *e);
55 static errval_t revoke_commit__send(struct intermon_binding *b,
56 intermon_caprep_t *caprep,
57 struct capsend_mc_st *mc_st);
58 static void revoke_slave_steps__fin(void *st);
59 static void revoke_done__send(struct intermon_binding *b,
60 struct intermon_msg_queue_elem *e);
61 static void revoke_master_steps__fin(void *st);
64 capops_revoke(struct domcapref cap,
65 revoke_result_handler_t result_handler,
70 distcap_state_t state;
71 err = dom_cnode_get_state(cap, &state);
72 GOTO_IF_ERR(err, report_error);
74 if (distcap_state_is_busy(state)) {
75 err = MON_ERR_REMOTE_CAP_RETRY;
79 struct revoke_master_st *rst;
80 err = calloce(1, sizeof(*rst), &rst);
81 GOTO_IF_ERR(err, report_error);
83 err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.bits, &rst->rawcap);
84 GOTO_IF_ERR(err, free_st);
85 rst->result_handler = result_handler;
88 if (distcap_state_is_foreign(state)) {
89 // need to retrieve ownership
90 capops_retrieve(rst->cap, revoke_retrieve__rx, rst);
93 if (num_monitors_online() == 1) {
94 DEBUG_CAPOPS("%s: only one monitor: do simpler revoke\n",
96 // no remote monitors exist; do simplified revocation process
97 revoke_no_remote(rst);
101 // have ownership, initiate revoke
111 result_handler(err, st);
115 revoke_result__rx(errval_t result,
116 struct revoke_master_st *st,
119 DEBUG_CAPOPS("%s\n", __FUNCTION__);
123 caplock_unlock(st->cap);
126 if (err_is_ok(result)) {
127 // clear the remote copies bit
128 err = monitor_domcap_remote_relations(st->cap.croot, st->cap.cptr,
129 st->cap.bits, 0, RRELS_COPY_BIT,
131 if (err_is_fail(err) && err_no(err) != SYS_ERR_CAP_NOT_FOUND) {
132 DEBUG_ERR(err, "resetting remote copies bit after revoke");
136 st->result_handler(result, st->st);
141 revoke_retrieve__rx(errval_t result, void *st_)
143 struct revoke_master_st *st = (struct revoke_master_st*)st_;
145 if (err_is_fail(result)) {
146 revoke_result__rx(result, st, false);
150 distcap_state_t state;
151 errval_t err = dom_cnode_get_state(st->cap, &state);
152 PANIC_IF_ERR(err, "dom_cnode_get_state");
153 assert(!distcap_state_is_foreign(state));
160 revoke_local(struct revoke_master_st *st)
162 DEBUG_CAPOPS("%s: called from %p\n", __FUNCTION__,
163 __builtin_return_address(0));
166 delete_steps_pause();
168 err = monitor_revoke_mark_target(st->cap.croot,
171 PANIC_IF_ERR(err, "marking revoke");
173 // XXX: could check whether remote copies exist here(?), -SG, 2014-11-05
174 err = capsend_relations(&st->rawcap, revoke_mark__send,
175 &st->revoke_mc_st, &st->dests);
176 PANIC_IF_ERR(err, "initiating revoke mark multicast");
180 revoke_no_remote(struct revoke_master_st *st)
182 assert(num_monitors_online() == 1);
184 if (!delete_steps_get_waitset()) {
185 delete_steps_init(get_default_waitset());
189 DEBUG_CAPOPS("%s\n", __FUNCTION__);
191 // pause deletion steps
192 DEBUG_CAPOPS("%s: delete_steps_pause()\n", __FUNCTION__);
193 delete_steps_pause();
195 // mark target of revoke
196 DEBUG_CAPOPS("%s: mon_revoke_mark_tgt()\n", __FUNCTION__);
197 err = monitor_revoke_mark_target(st->cap.croot,
200 PANIC_IF_ERR(err, "marking revoke");
203 // resume delete steps
204 DEBUG_CAPOPS("%s: delete_steps_resume()\n", __FUNCTION__);
205 delete_steps_resume();
207 // wait on delete queue, marking that remote cores are done
208 st->remote_fin = true;
209 DEBUG_CAPOPS("%s: delete_queue_wait()\n", __FUNCTION__);
210 struct event_closure steps_fin_cont
211 = MKCLOSURE(revoke_master_steps__fin, st);
212 delete_queue_wait(&st->del_qn, steps_fin_cont);
216 revoke_mark__send(struct intermon_binding *b,
217 intermon_caprep_t *caprep,
218 struct capsend_mc_st *mc_st)
220 struct revoke_master_st *st;
221 ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
222 st = (struct revoke_master_st*)((uintptr_t)mc_st - off);
223 return intermon_capops_revoke_mark__tx(b, NOP_CONT, *caprep, (lvaddr_t)st);
227 revoke_mark__rx(struct intermon_binding *b,
228 intermon_caprep_t caprep,
231 DEBUG_CAPOPS("%s\n", __FUNCTION__);
233 struct intermon_state *inter_st = (struct intermon_state*)b->st;
235 struct revoke_slave_st *rvk_st;
236 err = calloce(1, sizeof(*rvk_st), &rvk_st);
237 PANIC_IF_ERR(err, "allocating revoke slave state");
239 rvk_st->from = inter_st->core_id;
241 caprep_to_capability(&caprep, &rvk_st->rawcap);
244 assert(!slaves_tail);
245 slaves_head = slaves_tail = rvk_st;
249 assert(!slaves_tail->next);
250 slaves_tail->next = rvk_st;
251 slaves_tail = rvk_st;
254 // pause any ongoing "delete stepping" as mark phases on other nodes need
255 // to delete all foreign copies before we can delete locally owned caps
256 delete_steps_pause();
258 // XXX: this invocation could create a scheduling hole that could be
259 // problematic in RT systems and should probably be done in a loop.
260 err = monitor_revoke_mark_relations(&rvk_st->rawcap);
261 if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
262 // found no copies or descendants of capability on this core,
264 DEBUG_CAPOPS("no copies on core %d\n", disp_get_core_id());
265 } else if (err_is_fail(err)) {
266 USER_PANIC_ERR(err, "marking revoke");
269 rvk_st->im_qn.cont = revoke_ready__send;
270 err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
271 PANIC_IF_ERR(err, "enqueing revoke_ready");
275 revoke_ready__send(struct intermon_binding *b,
276 struct intermon_msg_queue_elem *e)
279 struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
280 err = intermon_capops_revoke_ready__tx(b, NOP_CONT, rvk_st->st);
281 PANIC_IF_ERR(err, "sending revoke_ready");
285 revoke_ready__rx(struct intermon_binding *b, genvaddr_t st)
287 DEBUG_CAPOPS("%s\n", __FUNCTION__);
290 struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
291 if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
292 DEBUG_CAPOPS("%s: waiting for remote cores\n", __FUNCTION__);
293 // multicast not complete
297 DEBUG_CAPOPS("%s: sending commit\n", __FUNCTION__);
298 err = capsend_relations(&rvk_st->rawcap, revoke_commit__send,
299 &rvk_st->revoke_mc_st, &rvk_st->dests);
300 PANIC_IF_ERR(err, "enqueing revoke_commit multicast");
302 delete_steps_resume();
304 struct event_closure steps_fin_cont
305 = MKCLOSURE(revoke_master_steps__fin, rvk_st);
306 delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
310 revoke_commit__send(struct intermon_binding *b,
311 intermon_caprep_t *caprep,
312 struct capsend_mc_st *mc_st)
314 struct revoke_master_st *st;
315 ptrdiff_t off = offsetof(struct revoke_master_st, revoke_mc_st);
316 st = (struct revoke_master_st*)((char*)mc_st - off);
317 return intermon_capops_revoke_commit__tx(b, NOP_CONT, (lvaddr_t)st);
321 revoke_commit__rx(struct intermon_binding *b,
326 assert(!slaves_tail->next);
328 struct revoke_slave_st *rvk_st = slaves_head;
329 while (rvk_st && rvk_st->st != st) { rvk_st = rvk_st->next; }
332 delete_steps_resume();
334 struct event_closure steps_fin_cont
335 = MKCLOSURE(revoke_slave_steps__fin, rvk_st);
336 delete_queue_wait(&rvk_st->del_qn, steps_fin_cont);
340 revoke_slave_steps__fin(void *st)
343 struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)st;
345 rvk_st->im_qn.cont = revoke_done__send;
346 err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st);
347 PANIC_IF_ERR(err, "enqueueing revoke_done");
351 remove_slave_from_list(struct revoke_slave_st *rvk_st)
353 // remove from slave list
354 if (slaves_head == slaves_tail) {
355 // only one element in list
356 if (rvk_st == slaves_head) {
357 // we're only, clear list
358 slaves_head = slaves_tail = 0;
360 // we're not the element in list??
361 printf("rvk_st: %p; head&tail: %p\n", rvk_st, slaves_head);
364 // more than one element in list
365 if (rvk_st == slaves_head) {
366 // we're first, remove from head of list
367 slaves_head=slaves_head->next;
371 struct revoke_slave_st *p = slaves_head;
372 for (;p&&p->next!=rvk_st;p=p->next);
373 // make sure we found prev of us
374 assert(p&&p->next==rvk_st);
376 p->next = rvk_st->next;
377 if (rvk_st == slaves_tail) {
378 // we were last, set last to prev
386 revoke_done__send(struct intermon_binding *b,
387 struct intermon_msg_queue_elem *e)
390 struct revoke_slave_st *rvk_st = (struct revoke_slave_st*)e;
391 err = intermon_capops_revoke_done__tx(b, NOP_CONT, rvk_st->st);
392 PANIC_IF_ERR(err, "sending revoke_done");
393 remove_slave_from_list(rvk_st);
398 revoke_done__rx(struct intermon_binding *b,
401 struct revoke_master_st *rvk_st = (struct revoke_master_st*)(lvaddr_t)st;
402 if (!capsend_handle_mc_reply(&rvk_st->revoke_mc_st)) {
403 // multicast not complete
407 rvk_st->remote_fin = true;
408 if (rvk_st->local_fin) {
409 revoke_result__rx(SYS_ERR_OK, rvk_st, true);
414 revoke_master_steps__fin(void *st)
416 struct revoke_master_st *rvk_st = (struct revoke_master_st*)st;
417 rvk_st->local_fin = true;
418 if (rvk_st->remote_fin) {
419 revoke_result__rx(SYS_ERR_OK, rvk_st, true);