readme: add NXP iMX8X to supported platforms
[barrelfish] / usr / proc_mgmt / spawnd_state.c
1 /*
2  * \brief Spawnd state internals for the process manager.
3  *
4  * Copyright (c) 2017, ETH Zurich.
5  * All rights reserved.
6  *
7  * This file is distributed under the terms in the attached LICENSE file.
8  * If you do not find this file, copies can be found by writing to:
9  * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
10  */
11
12 #include <barrelfish/barrelfish.h>
13
14 #include "spawnd_state.h"
15
16 static struct spawnd_state *spawnds[MAX_COREID];
17
18 /**
19  * \brief Allocates a state structure for a new spawnd binding.
20  *
21  * \param core_id       core where the spawnd newly bound with runs.
22  * \param spawn_binding Flounder binding structure for the spawnd.
23  */
24 errval_t spawnd_state_alloc(coreid_t core_id, struct spawn_binding *b)
25 {
26     spawnds[core_id] = (struct spawnd_state*) malloc(
27             sizeof(struct spawnd_state));
28     if (spawnds[core_id] == NULL) {
29         return LIB_ERR_MALLOC_FAIL;
30     }
31
32     spawnds[core_id]->b = b;
33     spawnds[core_id]->core_id = core_id;
34     spawnds[core_id]->sendq.head = NULL;
35     spawnds[core_id]->sendq.tail = NULL;
36     spawnds[core_id]->recvq.head = NULL;
37     spawnds[core_id]->recvq.tail = NULL;
38
39     b->st = spawnds[core_id];
40
41     return SYS_ERR_OK;
42 }
43
44 /**
45  * \brief Returns whether connected to spawnd on the given core.
46  */
47 inline bool spawnd_state_exists(coreid_t core_id)
48 {
49     return spawnds[core_id] != NULL;
50 }
51
52 /**
53  * \brief Returns the state element for the spawnd on the given core.
54  */
55 inline struct spawnd_state *spawnd_state_get(coreid_t core_id)
56 {
57     return spawnds[core_id];
58 }
59
60 /**
61  * \brief Enqueue on a waitset queue.
62  *
63  * \param q    Pointer to queue to enqueue on
64  * \param m    Pointer to element to enqueue
65  *
66  * \return true if queue was empty, false if not.
67  */
68 static bool enqueue(struct msg_queue *q, struct msg_queue_elem *m)
69 {
70     assert(m->next == NULL);
71
72     // Enqueue on the queue
73     if(q->tail != NULL) {
74         q->tail->next = m;
75     } else {
76         assert(q->head == NULL);
77         q->head = m;
78     }
79     q->tail = m;
80
81     return q->head == q->tail ? true : false;
82 }
83
84 /**
85  * \brief Dequeues from a waitset queue.
86  *
87  * \param q    Pointer to queue to dequeue from
88  *
89  * \return the newly dequeued element.
90  */
91 static struct msg_queue_elem *dequeue(struct msg_queue *q)
92 {
93     // Queue should have at least one element
94     assert(q->head != NULL && q->tail != NULL);
95
96     struct msg_queue_elem *e = q->head;
97     q->head = e->next;
98     if(q->head == NULL) {
99         q->tail = NULL;
100     }
101
102     return e;
103 }
104
105 /**
106  * \brief Enqueue an element on a waitset queue IN FRONT.
107  *
108  * \param q    Pointer to queue to enqueue on
109  * \param m    Pointer to element to enqueue
110  *
111  * \return true if queue was empty, false if not.
112  */
113 static bool enqueue_at_front(struct msg_queue *q, struct msg_queue_elem *m)
114 {
115     assert(m->next == NULL);
116     if(q->tail == NULL) {
117         assert(q->head == NULL);
118         q->head = m;
119         q->tail = m;
120     } else {
121         m->next = q->head;
122         q->head = m;
123     }
124     return q->head == q->tail ? true : false;
125 }
126
127 /**
128  * \brief Event-based handler for sending requests to spawnd.
129  *
130  * This function pops the next request from the send queue of the targeted
131  * spawnd (wrapped inside arg). It attempts to send the request, re-enqueuing
132  * it at front if sending fails. It then re-registers a new send if the queue
133  * still has pending requests.
134  *
135  * \param arg Wrapper over the spawnd_state structure for the target spawnd.
136  */
137 static void spawnd_send_handler(void *arg)
138 {
139     struct spawnd_state *spawnd = (struct spawnd_state*) arg;
140     struct msg_queue *q = &spawnd->sendq;
141
142     // Dequeue next element from the queue
143     struct msg_queue_elem *m = (struct msg_queue_elem*) dequeue(q);
144
145     assert(m->cont != NULL);
146     if (m->cont(m)) {
147         // Send continuation succeeded, need to enqueue a receive.
148         struct msg_queue_elem *recvm = (struct msg_queue_elem*) malloc(
149                 sizeof(struct msg_queue_elem));
150         recvm->st = m->st;
151         recvm->next = NULL;
152         enqueue(&spawnd->recvq, recvm);
153     } else {
154         // Send continuation failed, need to re-enqueue message.
155         enqueue_at_front(q, m);
156     }
157
158     if (q->head != NULL) {
159         // Queue is non-empty, therefore re-register.
160         errval_t err = spawnd->b->register_send(spawnd->b, spawnd->b->waitset,
161                                                 MKCONT(spawnd_send_handler,
162                                                        arg));
163         if (err_is_fail(err)) {
164             DEBUG_ERR(err, "regitering for spawnd send");
165             return;
166         }
167     }
168 }
169
170 /**
171  * \brief Enqueues a new send request event.
172  *
173  * \param spawnd target spawnd to send the request to.
174  * \param msg    request to enqueue.
175  */
176 errval_t spawnd_state_enqueue_send(struct spawnd_state *spawnd,
177                                    struct msg_queue_elem *msg)
178 {
179     msg->next = NULL;
180
181     // If queue was empty, enqueue on waitset
182     if(enqueue(&spawnd->sendq, msg)) {
183         return spawnd->b->register_send(spawnd->b, spawnd->b->waitset,
184                                         MKCONT(spawnd_send_handler, spawnd));
185     } else {
186         return SYS_ERR_OK;
187     }
188 }
189
190 /**
191  * \brief Dequeues and returns the next message in a receive queue.
192  *
193  * \param spawnd spawnd instance whose receive queue to pop.
194  */
195 void *spawnd_state_dequeue_recv(struct spawnd_state *spawnd)
196 {
197     struct msg_queue_elem *m = dequeue(&spawnd->recvq);
198     assert(m != NULL);
199     return m->st;
200 }