1/**
2 * \file
3 * \brief Queue for stack-ripped inter-monitor code
4 */
5
6/*
7 * Copyright (c) 2009, 2010, 2011, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <monitor.h>
16
17/**
18 * \brief Enqueue on a waitset queue.
19 *
20 * \param qs    Pointer to queue to enqueue on
21 * \param ms    Pointer to element to enqueue
22 *
23 * \return true if queue was empty, false if not.
24 */
25static bool enqueue_send(struct msg_queue *q, struct msg_queue_elem *m)
26{
27    assert(m->next == NULL);
28
29    // Enqueue on the queue
30    if(q->tail != NULL) {
31        q->tail->next = m;
32    } else {
33        assert(q->head == NULL);
34        q->head = m;
35    }
36    q->tail = m;
37
38    return q->head == q->tail ? true : false;
39}
40
41/**
42 * \brief Enqueue an element on a waitset queue IN FRONT.
43 *
44 * \param qs    Pointer to queue to enqueue on
45 * \param ms    Pointer to element to enqueue
46 *
47 * \return true if queue was empty, false if not.
48 */
49static bool enqueue_send_at_front(struct msg_queue *q, struct msg_queue_elem *m)
50{
51    assert(m->next == NULL);
52    if(q->tail == NULL) {
53        assert(q->head == NULL);
54    	q->head = m;
55    	q->tail = m;
56    } else {
57    	m->next = q->head;
58    	q->head = m;
59    }
60    return q->head == q->tail ? true : false;
61}
62
63static struct msg_queue_elem *dequeue_send(struct msg_queue *q)
64{
65    // Queue should have at least one element
66    assert(q->head != NULL && q->tail != NULL);
67
68    struct msg_queue_elem *e = q->head;
69    q->head = e->next;
70    if(q->head == NULL) {
71        q->tail = NULL;
72    }
73
74    return e;
75}
76
77static void intermon_send_handler(void *arg)
78{
79    struct intermon_binding *b = arg;
80    struct intermon_state *is = b->st;
81    struct msg_queue *mq = &is->queue;
82
83    // Dequeue next element from the queue
84    struct intermon_msg_queue_elem *e =
85        (struct intermon_msg_queue_elem *)dequeue_send(mq);
86
87    // If the queue is non-empty, re-register
88    if (!msg_queue_is_empty(mq)) {
89        struct waitset *ws = get_default_waitset(); // XXX: store this on the q?
90        errval_t err = b->register_send(b, ws, MKCONT(intermon_send_handler,b));
91        assert(err_is_ok(err));
92    }
93
94    assert(e->cont != NULL);
95    e->cont(b, e);
96}
97
98errval_t intermon_enqueue_send(struct intermon_binding *b, struct msg_queue *q,
99                               struct waitset *ws, struct msg_queue_elem *ms)
100{
101    ms->next = NULL;
102
103    // If queue was empty, enqueue on waitset
104    if(enqueue_send(q, ms)) {
105        return b->register_send(b, ws, MKCONT(intermon_send_handler,b));
106    } else {
107        return SYS_ERR_OK;
108    }
109}
110
111errval_t intermon_enqueue_send_at_front(struct intermon_binding *b, struct msg_queue *q,
112                               struct waitset *ws, struct msg_queue_elem *ms)
113{
114    ms->next = NULL;
115
116    // If queue was empty, enqueue on waitset
117    if(enqueue_send_at_front(q, ms)) {
118        return b->register_send(b, ws, MKCONT(intermon_send_handler,b));
119    } else {
120        return SYS_ERR_OK;
121    }
122}
123
124static void monitor_send_handler(void *arg)
125{
126    struct monitor_binding *b = arg;
127    struct monitor_state *is = b->st;
128    struct msg_queue *mq = &is->queue;
129
130    // Dequeue next element from the queue
131    struct monitor_msg_queue_elem *e =
132        (struct monitor_msg_queue_elem *)dequeue_send(mq);
133
134    // If the queue is non-empty, re-register
135    if (!msg_queue_is_empty(mq)) {
136        struct waitset *ws = get_default_waitset(); // XXX: store this on the q?
137        errval_t err = b->register_send(b, ws, MKCONT(monitor_send_handler,b));
138        assert(err_is_ok(err));
139    }
140
141    assert(e->cont != NULL);
142    e->cont(b, e);
143}
144
145errval_t monitor_enqueue_send(struct monitor_binding *b, struct msg_queue *q,
146                              struct waitset *ws, struct msg_queue_elem *ms)
147{
148    ms->next = NULL;
149
150    // If queue was empty, enqueue on waitset
151    if(enqueue_send(q, ms)) {
152        return b->register_send(b, ws, MKCONT(monitor_send_handler,b));
153    } else {
154        return SYS_ERR_OK;
155    }
156}
157
158errval_t monitor_enqueue_send_at_front(struct monitor_binding *b, struct msg_queue *q,
159                              struct waitset *ws, struct msg_queue_elem *ms)
160{
161    ms->next = NULL;
162
163    // If queue was empty, enqueue on waitset
164    if(enqueue_send_at_front(q, ms)) {
165        return b->register_send(b, ws, MKCONT(monitor_send_handler,b));
166    } else {
167        return SYS_ERR_OK;
168    }
169}
170
171/// Common send continuation function to destroy a cap that has been sent
172/// NB: Not part of the queue functionality
173void destroy_outgoing_cap(void *arg)
174{
175    DEBUG_CAPOPS("cleaning up outgoing cap\n");
176    struct capref *cap = arg;
177    assert(cap != NULL);
178    assert(!capref_is_null(*cap));
179
180    DEBUG_CAPOPS("cleaning up outgoing cap: cap_destroy\n");
181    errval_t err = cap_destroy(*cap);
182    if (err_is_fail(err)) {
183        if(err_no(err) != SYS_ERR_CAP_NOT_FOUND) {
184            DEBUG_ERR(err, "cap_destroy failed");
185        }
186    }
187
188    DEBUG_CAPOPS("cleaning up outgoing cap: free\n");
189    free(cap);
190}
191
192/// Returns a copy of the given capref in a malloc'ed buffer
193struct capref *caprefdup(struct capref cap)
194{
195    struct capref *p = malloc(sizeof(struct capref));
196    assert(p != NULL);
197    *p = cap;
198    return p;
199}
200