Add extra layer of queuing above the Flounder UMP one.
[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     assert(table != NULL);
123
124     void *entry = collections_hash_find(table, key);
125     if (entry == NULL) {
126         return PROC_MGMT_ERR_CLIENTS_TABLE_FIND;
127     }
128     struct pending_client *cl = (struct pending_client*) entry;
129     if (ret_cl != NULL) {
130         *ret_cl = cl;
131     } else {
132         free(cl);
133     }
134
135     collections_hash_delete(table, key);
136
137     return SYS_ERR_OK;
138 }
139
140 errval_t pending_clients_release_one(struct capref domain_cap,
141                                      enum ClientType type,
142                                      struct proc_mgmt_binding *b,
143                                      struct pending_client **ret_cl)
144 {
145     uint64_t key;
146     errval_t err = domain_cap_hash(domain_cap, &key);
147     if (err_is_fail(err)) {
148         return err;
149     }
150
151     collections_hash_table **table;
152     switch (type) {
153         case ClientType_Spawn:
154             table = &spawn_table;
155             break;
156         case ClientType_SpawnWithCaps:
157             table = &spawn_with_caps_table;
158             break;
159         case ClientType_Span:
160             table = &span_table;
161             break;
162         case ClientType_Kill:
163             table = &kill_table;
164             break;
165         case ClientType_Exit:
166             table = &exit_table;
167             break;
168         case ClientType_Cleanup:
169             table = &cleanup_table;
170             break;
171         default:
172             USER_PANIC("Unhandled client type %d\n", type);
173     }
174
175     void *entry = collections_hash_find(*table, key);
176     if (entry == NULL) {
177         return PROC_MGMT_ERR_CLIENTS_TABLE_FIND;
178     }
179     struct pending_client *cl = (struct pending_client*) entry;
180     if (cl->b == b) {
181         struct pending_client *tmp = cl;
182         cl = cl->next;
183         if (ret_cl != NULL) {
184             *ret_cl = tmp;
185         } else {
186             free(tmp);
187         }
188     } else {
189         while (cl->next != NULL) {
190             if (cl->next->b == b) {
191                 struct pending_client *tmp = cl->next;
192                 cl->next = cl->next->next;
193                 if (ret_cl != NULL) {
194                     *ret_cl = tmp;
195                 } else {
196                     free(tmp);
197                 }
198                 break;
199             }
200             cl = cl->next;
201         }
202     }
203
204     collections_hash_delete(*table, key);
205     if (cl != NULL) {
206         collections_hash_insert(*table, key, cl);
207     }
208
209     return SYS_ERR_OK;
210 }