Add per-spawnd message queues to the process manager.
[barrelfish] / usr / proc_mgmt / pending_clients.c
1 /*
2  * \brief Client handling 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
10  */
11
12 #include <collections/hash_table.h>
13
14 #include "domain.h"
15 #include "pending_clients.h"
16
17 static collections_hash_table *spawn_table = NULL;
18 static collections_hash_table *spawn_with_caps_table = NULL;
19 static collections_hash_table *span_table = NULL;
20 static collections_hash_table *kill_table = NULL;
21 static collections_hash_table *exit_table = NULL;
22 static collections_hash_table *cleanup_table = NULL;
23
24 errval_t pending_clients_add(struct capref domain_cap,
25                              struct proc_mgmt_binding *b, enum ClientType type,
26                              coreid_t core_id)
27 {
28     collections_hash_table **table;
29     switch (type) {
30         case ClientType_Spawn:
31             table = &spawn_table;
32             break;
33         case ClientType_SpawnWithCaps:
34             table = &spawn_with_caps_table;
35             break;
36         case ClientType_Span:
37             table = &span_table;
38             break;
39         case ClientType_Kill:
40             table = &kill_table;
41             break;
42         case ClientType_Exit:
43             table = &exit_table;
44             break;
45         case ClientType_Cleanup:
46             table = &cleanup_table;
47             break;
48         default:
49             USER_PANIC("Unhandled client type %d\n", type);
50     }
51
52     if (*table == NULL) {
53         collections_hash_create_with_buckets(table, HASH_INDEX_BUCKETS, NULL);
54         if (*table == NULL) {
55             return PROC_MGMT_ERR_CREATE_CLIENTS_TABLE;
56         }
57     }
58
59     uint64_t key;
60     errval_t err = domain_cap_hash(domain_cap, &key);
61     if (err_is_fail(err)) {
62         return err;
63     }
64
65     struct pending_client *cl = (struct pending_client*) malloc(
66             sizeof(struct pending_client));
67     cl->b = b;
68     cl->domain_cap = domain_cap;
69     cl->core_id = core_id;
70     cl->type = type;
71     cl->next = NULL;
72
73     if (type == ClientType_Kill) {
74         // Special case: multiple clients might have issued a kill for some
75         // domain. Need to chain them together.
76         void *entry = collections_hash_find(*table, key);
77         if (entry != NULL) {
78             struct pending_client* old = (struct pending_client*) entry;
79             collections_hash_delete(*table, key);
80             cl->next = old;
81         }
82     }
83     
84     collections_hash_insert(*table, key, cl);
85
86     return SYS_ERR_OK;
87 }
88
89 errval_t pending_clients_release(struct capref domain_cap, enum ClientType type,
90                                  struct pending_client **ret_cl)
91 {
92     uint64_t key;
93     errval_t err = domain_cap_hash(domain_cap, &key);
94     if (err_is_fail(err)) {
95         return err;
96     }
97
98     collections_hash_table **table;
99     switch (type) {
100         case ClientType_Spawn:
101             table = &spawn_table;
102             break;
103         case ClientType_SpawnWithCaps:
104             table = &spawn_with_caps_table;
105             break;
106         case ClientType_Span:
107             table = &span_table;
108             break;
109         case ClientType_Kill:
110             table = &kill_table;
111             break;
112         case ClientType_Exit:
113             table = &exit_table;
114             break;
115         case ClientType_Cleanup:
116             table = &cleanup_table;
117             break;
118         default:
119             USER_PANIC("Unhandled client type %d\n", type);
120     }
121
122     void *entry = collections_hash_find(*table, key);
123     if (entry == NULL) {
124         return PROC_MGMT_ERR_CLIENTS_TABLE_FIND;
125     }
126     struct pending_client *cl = (struct pending_client*) entry;
127     if (ret_cl != NULL) {
128         *ret_cl = cl;
129     } else {
130         free(cl);
131     }
132
133     collections_hash_delete(*table, key);
134
135     return SYS_ERR_OK;
136 }
137
138 errval_t pending_clients_release_one(struct capref domain_cap,
139                                      enum ClientType type,
140                                      struct proc_mgmt_binding *b,
141                                      struct pending_client **ret_cl)
142 {
143     uint64_t key;
144     errval_t err = domain_cap_hash(domain_cap, &key);
145     if (err_is_fail(err)) {
146         return err;
147     }
148
149     collections_hash_table **table;
150     switch (type) {
151         case ClientType_Spawn:
152             table = &spawn_table;
153             break;
154         case ClientType_SpawnWithCaps:
155             table = &spawn_with_caps_table;
156             break;
157         case ClientType_Span:
158             table = &span_table;
159             break;
160         case ClientType_Kill:
161             table = &kill_table;
162             break;
163         case ClientType_Exit:
164             table = &exit_table;
165             break;
166         case ClientType_Cleanup:
167             table = &cleanup_table;
168             break;
169         default:
170             USER_PANIC("Unhandled client type %d\n", type);
171     }
172
173     void *entry = collections_hash_find(*table, key);
174     if (entry == NULL) {
175         return PROC_MGMT_ERR_CLIENTS_TABLE_FIND;
176     }
177     struct pending_client *cl = (struct pending_client*) entry;
178     if (cl->b == b) {
179         struct pending_client *tmp = cl;
180         cl = cl->next;
181         if (ret_cl != NULL) {
182             *ret_cl = tmp;
183         } else {
184             free(tmp);
185         }
186     } else {
187         while (cl->next != NULL) {
188             if (cl->next->b == b) {
189                 struct pending_client *tmp = cl->next;
190                 cl->next = cl->next->next;
191                 if (ret_cl != NULL) {
192                     *ret_cl = tmp;
193                 } else {
194                     free(tmp);
195                 }
196                 break;
197             }
198             cl = cl->next;
199         }
200     }
201
202     collections_hash_delete(*table, key);
203     if (cl != NULL) {
204         collections_hash_insert(*table, key, cl);
205     }
206
207     return SYS_ERR_OK;
208 }