source: mainline/uspace/srv/ns/task.c@ 208db5a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 208db5a was 6769005, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/*
2 * Copyright (c) 2009 Martin Decky
3 * Copyright (c) 2009 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup ns
31 * @{
32 */
33
34#include <adt/hash_table.h>
35#include <async.h>
36#include <stdbool.h>
37#include <errno.h>
38#include <assert.h>
39#include <macros.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <types/task.h>
43#include "task.h"
44#include "ns.h"
45
46/** Task hash table item. */
47typedef struct {
48 ht_link_t link;
49
50 task_id_t id; /**< Task ID. */
51 bool finished; /**< Task is done. */
52 bool have_rval; /**< Task returned a value. */
53 int retval; /**< The return value. */
54} hashed_task_t;
55
56static size_t task_key_hash(void *key)
57{
58 return *(task_id_t *)key;
59}
60
61static size_t task_hash(const ht_link_t *item)
62{
63 hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
64 return ht->id;
65}
66
67static bool task_key_equal(void *key, const ht_link_t *item)
68{
69 hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
70 return ht->id == *(task_id_t *)key;
71}
72
73/** Perform actions after removal of item from the hash table. */
74static void task_remove(ht_link_t *item)
75{
76 free(hash_table_get_inst(item, hashed_task_t, link));
77}
78
79/** Operations for task hash table. */
80static hash_table_ops_t task_hash_table_ops = {
81 .hash = task_hash,
82 .key_hash = task_key_hash,
83 .key_equal = task_key_equal,
84 .equal = NULL,
85 .remove_callback = task_remove
86};
87
88/** Task hash table structure. */
89static hash_table_t task_hash_table;
90
91typedef struct {
92 ht_link_t link;
93 sysarg_t label; /**< Incoming phone label. */
94 task_id_t id; /**< Task ID. */
95} p2i_entry_t;
96
97/* label-to-id hash table operations */
98
99static size_t p2i_key_hash(void *key)
100{
101 sysarg_t label = *(sysarg_t *)key;
102 return label;
103}
104
105static size_t p2i_hash(const ht_link_t *item)
106{
107 p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
108 return entry->label;
109}
110
111static bool p2i_key_equal(void *key, const ht_link_t *item)
112{
113 sysarg_t label = *(sysarg_t *)key;
114 p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
115
116 return (label == entry->label);
117}
118
119/** Perform actions after removal of item from the hash table.
120 *
121 * @param item Item that was removed from the hash table.
122 *
123 */
124static void p2i_remove(ht_link_t *item)
125{
126 assert(item);
127 free(hash_table_get_inst(item, p2i_entry_t, link));
128}
129
130/** Operations for task hash table. */
131static hash_table_ops_t p2i_ops = {
132 .hash = p2i_hash,
133 .key_hash = p2i_key_hash,
134 .key_equal = p2i_key_equal,
135 .equal = NULL,
136 .remove_callback = p2i_remove
137};
138
139/** Map phone label to task ID */
140static hash_table_t phone_to_id;
141
142/** Pending task wait structure. */
143typedef struct {
144 link_t link;
145 task_id_t id; /**< Task ID */
146 ipc_call_t call; /**< Call waiting for the connection */
147} pending_wait_t;
148
149static list_t pending_wait;
150
151errno_t task_init(void)
152{
153 if (!hash_table_create(&task_hash_table, 0, 0, &task_hash_table_ops)) {
154 printf(NAME ": No memory available for tasks\n");
155 return ENOMEM;
156 }
157
158 if (!hash_table_create(&phone_to_id, 0, 0, &p2i_ops)) {
159 printf(NAME ": No memory available for tasks\n");
160 return ENOMEM;
161 }
162
163 list_initialize(&pending_wait);
164 return EOK;
165}
166
167/** Process pending wait requests */
168void process_pending_wait(void)
169{
170 task_exit_t texit;
171
172loop:
173 list_foreach(pending_wait, link, pending_wait_t, pr) {
174 ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);
175 if (!link)
176 continue;
177
178 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
179 if (!ht->finished)
180 continue;
181
182 texit = ht->have_rval ? TASK_EXIT_NORMAL :
183 TASK_EXIT_UNEXPECTED;
184 async_answer_2(&pr->call, EOK, texit, ht->retval);
185
186 list_remove(&pr->link);
187 free(pr);
188 goto loop;
189 }
190}
191
192void wait_for_task(task_id_t id, ipc_call_t *call)
193{
194 ht_link_t *link = hash_table_find(&task_hash_table, &id);
195 hashed_task_t *ht = (link != NULL) ?
196 hash_table_get_inst(link, hashed_task_t, link) : NULL;
197
198 if (ht == NULL) {
199 /* No such task exists. */
200 async_answer_0(call, ENOENT);
201 return;
202 }
203
204 if (ht->finished) {
205 task_exit_t texit = ht->have_rval ? TASK_EXIT_NORMAL :
206 TASK_EXIT_UNEXPECTED;
207 async_answer_2(call, EOK, texit, ht->retval);
208 return;
209 }
210
211 /* Add to pending list */
212 pending_wait_t *pr =
213 (pending_wait_t *) malloc(sizeof(pending_wait_t));
214 if (!pr) {
215 async_answer_0(call, ENOMEM);
216 return;
217 }
218
219 link_initialize(&pr->link);
220 pr->id = id;
221 pr->call = *call;
222 list_append(&pr->link, &pending_wait);
223}
224
225errno_t ns_task_id_intro(ipc_call_t *call)
226{
227 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
228
229 ht_link_t *link = hash_table_find(&phone_to_id, &call->request_label);
230 if (link != NULL)
231 return EEXIST;
232
233 p2i_entry_t *entry = (p2i_entry_t *) malloc(sizeof(p2i_entry_t));
234 if (entry == NULL)
235 return ENOMEM;
236
237 hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
238 if (ht == NULL) {
239 free(entry);
240 return ENOMEM;
241 }
242
243 /*
244 * Insert into the phone-to-id map.
245 */
246
247 assert(call->request_label);
248 entry->label = call->request_label;
249 entry->id = id;
250 hash_table_insert(&phone_to_id, &entry->link);
251
252 /*
253 * Insert into the main table.
254 */
255
256 ht->id = id;
257 ht->finished = false;
258 ht->have_rval = false;
259 ht->retval = -1;
260 hash_table_insert(&task_hash_table, &ht->link);
261
262 return EOK;
263}
264
265static errno_t get_id_by_phone(sysarg_t label, task_id_t *id)
266{
267 assert(label);
268 ht_link_t *link = hash_table_find(&phone_to_id, &label);
269 if (link == NULL)
270 return ENOENT;
271
272 p2i_entry_t *entry = hash_table_get_inst(link, p2i_entry_t, link);
273 *id = entry->id;
274
275 return EOK;
276}
277
278errno_t ns_task_retval(ipc_call_t *call)
279{
280 task_id_t id = call->task_id;
281
282 ht_link_t *link = hash_table_find(&task_hash_table, &id);
283 hashed_task_t *ht = (link != NULL) ?
284 hash_table_get_inst(link, hashed_task_t, link) : NULL;
285
286 if ((ht == NULL) || (ht->finished))
287 return EINVAL;
288
289 ht->finished = true;
290 ht->have_rval = true;
291 ht->retval = IPC_GET_ARG1(*call);
292
293 process_pending_wait();
294
295 return EOK;
296}
297
298errno_t ns_task_disconnect(ipc_call_t *call)
299{
300 task_id_t id;
301 errno_t rc = get_id_by_phone(call->request_label, &id);
302 if (rc != EOK)
303 return rc;
304
305 /* Delete from phone-to-id map. */
306 hash_table_remove(&phone_to_id, &call->request_label);
307
308 /* Mark task as finished. */
309 ht_link_t *link = hash_table_find(&task_hash_table, &id);
310 if (link == NULL)
311 return EOK;
312
313 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
314
315 ht->finished = true;
316
317 process_pending_wait();
318 hash_table_remove(&task_hash_table, &id);
319
320 return EOK;
321}
322
323/**
324 * @}
325 */
Note: See TracBrowser for help on using the repository browser.