source: mainline/uspace/srv/ns/task.c@ 63d46341

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 63d46341 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • 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
47/** Task hash table item. */
48typedef struct {
49 ht_link_t link;
50
51 task_id_t id; /**< Task ID. */
52 bool finished; /**< Task is done. */
53 bool have_rval; /**< Task returned a value. */
54 int retval; /**< The return value. */
55} hashed_task_t;
56
57
58static size_t task_key_hash(void *key)
59{
60 return *(task_id_t *)key;
61}
62
63static size_t task_hash(const ht_link_t *item)
64{
65 hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
66 return ht->id;
67}
68
69static bool task_key_equal(void *key, const ht_link_t *item)
70{
71 hashed_task_t *ht = hash_table_get_inst(item, hashed_task_t, link);
72 return ht->id == *(task_id_t *)key;
73}
74
75/** Perform actions after removal of item from the hash table. */
76static void task_remove(ht_link_t *item)
77{
78 free(hash_table_get_inst(item, hashed_task_t, link));
79}
80
81/** Operations for task hash table. */
82static hash_table_ops_t task_hash_table_ops = {
83 .hash = task_hash,
84 .key_hash = task_key_hash,
85 .key_equal = task_key_equal,
86 .equal = NULL,
87 .remove_callback = task_remove
88};
89
90/** Task hash table structure. */
91static hash_table_t task_hash_table;
92
93typedef struct {
94 ht_link_t link;
95 sysarg_t in_phone_hash; /**< Incoming phone hash. */
96 task_id_t id; /**< Task ID. */
97} p2i_entry_t;
98
99/* phone-to-id hash table operations */
100
101static size_t p2i_key_hash(void *key)
102{
103 sysarg_t in_phone_hash = *(sysarg_t *)key;
104 return in_phone_hash;
105}
106
107static size_t p2i_hash(const ht_link_t *item)
108{
109 p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
110 return entry->in_phone_hash;
111}
112
113static bool p2i_key_equal(void *key, const ht_link_t *item)
114{
115 sysarg_t in_phone_hash = *(sysarg_t *)key;
116 p2i_entry_t *entry = hash_table_get_inst(item, p2i_entry_t, link);
117
118 return (in_phone_hash == entry->in_phone_hash);
119}
120
121/** Perform actions after removal of item from the hash table.
122 *
123 * @param item Item that was removed from the hash table.
124 *
125 */
126static void p2i_remove(ht_link_t *item)
127{
128 assert(item);
129 free(hash_table_get_inst(item, p2i_entry_t, link));
130}
131
132/** Operations for task hash table. */
133static hash_table_ops_t p2i_ops = {
134 .hash = p2i_hash,
135 .key_hash = p2i_key_hash,
136 .key_equal = p2i_key_equal,
137 .equal = NULL,
138 .remove_callback = p2i_remove
139};
140
141/** Map phone hash to task ID */
142static hash_table_t phone_to_id;
143
144/** Pending task wait structure. */
145typedef struct {
146 link_t link;
147 task_id_t id; /**< Task ID */
148 ipc_call_t call; /**< Call waiting for the connection */
149} pending_wait_t;
150
151static list_t pending_wait;
152
153errno_t task_init(void)
154{
155 if (!hash_table_create(&task_hash_table, 0, 0, &task_hash_table_ops)) {
156 printf(NAME ": No memory available for tasks\n");
157 return ENOMEM;
158 }
159
160 if (!hash_table_create(&phone_to_id, 0, 0, &p2i_ops)) {
161 printf(NAME ": No memory available for tasks\n");
162 return ENOMEM;
163 }
164
165 list_initialize(&pending_wait);
166 return EOK;
167}
168
169/** Process pending wait requests */
170void process_pending_wait(void)
171{
172 task_exit_t texit;
173
174loop:
175 list_foreach(pending_wait, link, pending_wait_t, pr) {
176 ht_link_t *link = hash_table_find(&task_hash_table, &pr->id);
177 if (!link)
178 continue;
179
180 hashed_task_t *ht = hash_table_get_inst(link, hashed_task_t, link);
181 if (!ht->finished)
182 continue;
183
184 texit = ht->have_rval ? TASK_EXIT_NORMAL :
185 TASK_EXIT_UNEXPECTED;
186 async_answer_2(&pr->call, EOK, texit, ht->retval);
187
188 list_remove(&pr->link);
189 free(pr);
190 goto loop;
191 }
192}
193
194void wait_for_task(task_id_t id, ipc_call_t *call)
195{
196 ht_link_t *link = hash_table_find(&task_hash_table, &id);
197 hashed_task_t *ht = (link != NULL) ?
198 hash_table_get_inst(link, hashed_task_t, link) : NULL;
199
200 if (ht == NULL) {
201 /* No such task exists. */
202 async_answer_0(call, ENOENT);
203 return;
204 }
205
206 if (ht->finished) {
207 task_exit_t texit = ht->have_rval ? TASK_EXIT_NORMAL :
208 TASK_EXIT_UNEXPECTED;
209 async_answer_2(call, EOK, texit, ht->retval);
210 return;
211 }
212
213 /* Add to pending list */
214 pending_wait_t *pr =
215 (pending_wait_t *) malloc(sizeof(pending_wait_t));
216 if (!pr) {
217 async_answer_0(call, ENOMEM);
218 return;
219 }
220
221 link_initialize(&pr->link);
222 pr->id = id;
223 pr->call = *call;
224 list_append(&pr->link, &pending_wait);
225}
226
227errno_t ns_task_id_intro(ipc_call_t *call)
228{
229 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
230
231 ht_link_t *link = hash_table_find(&phone_to_id, &call->in_phone_hash);
232 if (link != NULL)
233 return EEXIST;
234
235 p2i_entry_t *entry = (p2i_entry_t *) malloc(sizeof(p2i_entry_t));
236 if (entry == NULL)
237 return ENOMEM;
238
239 hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
240 if (ht == NULL) {
241 free(entry);
242 return ENOMEM;
243 }
244
245 /*
246 * Insert into the phone-to-id map.
247 */
248
249 entry->in_phone_hash = call->in_phone_hash;
250 entry->id = id;
251 hash_table_insert(&phone_to_id, &entry->link);
252
253 /*
254 * Insert into the main table.
255 */
256
257 ht->id = id;
258 ht->finished = false;
259 ht->have_rval = false;
260 ht->retval = -1;
261 hash_table_insert(&task_hash_table, &ht->link);
262
263 return EOK;
264}
265
266static errno_t get_id_by_phone(sysarg_t phone_hash, task_id_t *id)
267{
268 ht_link_t *link = hash_table_find(&phone_to_id, &phone_hash);
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->in_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->in_phone_hash, &id);
302 if (rc != EOK)
303 return rc;
304
305 /* Delete from phone-to-id map. */
306 hash_table_remove(&phone_to_id, &call->in_phone_hash);
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.