source: mainline/uspace/srv/taskman/task.c@ 70d28e8

Last change on this file since 70d28e8 was 1be7bee, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

sysman: Move task retval and waiting logic to taskman (partially)

  • two important sessions: NS and taskman
  • depending on boot task vs spawned task those sessions are initiated differently

Conflicts:

uspace/lib/c/generic/async.c
uspace/lib/c/generic/libc.c
uspace/lib/c/generic/task.c
uspace/lib/c/include/ipc/ns.h
uspace/lib/c/include/task.h
uspace/lib/posix/source/sys/wait.c
uspace/srv/loader/main.c
uspace/srv/ns/ns.c

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