source: mainline/uspace/srv/ns/task.c@ 40313e4

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

split naming service into multiple files for better readability
add support for waiting on tasks (receives kernel task notifications)

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2009 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ns
30 * @{
31 */
32
33#include <ipc/ipc.h>
34#include <libadt/hash_table.h>
35#include <bool.h>
36#include <errno.h>
37#include <assert.h>
38#include <stdio.h>
39#include <macros.h>
40#include "task.h"
41#include "ns.h"
42
43#define TASK_HASH_TABLE_CHAINS 256
44
45/* TODO:
46 *
47 * The current implementation of waiting on a task is not perfect. If somebody
48 * wants to wait on a task which has already finished before the NS asked
49 * the kernel to receive notifications, it would block indefinitively.
50 *
51 * A solution to this is to fail immediately on a task for which no creation
52 * notification was received yet. However, there is a danger of a race condition
53 * in this solution -- the caller has to make sure that it is not trying to wait
54 * before the NS has a change to receive the task creation notification. This
55 * can be assured by waiting for this event in task_spawn().
56 *
57 * Finally, as there is currently no convention that each task has to be waited
58 * for, the NS can leak memory because of the zombie tasks.
59 *
60 */
61
62/** Task hash table item. */
63typedef struct {
64 link_t link;
65 task_id_t id; /**< Task ID. */
66 bool destroyed;
67} hashed_task_t;
68
69/** Compute hash index into task hash table.
70 *
71 * @param key Pointer keys. However, only the first key (i.e. truncated task
72 * number) is used to compute the hash index.
73 *
74 * @return Hash index corresponding to key[0].
75 *
76 */
77static hash_index_t task_hash(unsigned long *key)
78{
79 assert(key);
80 return (LOWER32(*key) % TASK_HASH_TABLE_CHAINS);
81}
82
83/** Compare a key with hashed item.
84 *
85 * @param key Array of keys.
86 * @param keys Must be lesser or equal to 2.
87 * @param item Pointer to a hash table item.
88 *
89 * @return Non-zero if the key matches the item, zero otherwise.
90 *
91 */
92static int task_compare(unsigned long key[], hash_count_t keys, link_t *item)
93{
94 assert(key);
95 assert(keys <= 2);
96 assert(item);
97
98 hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link);
99
100 if (keys == 2)
101 return ((LOWER32(key[1]) == UPPER32(ht->id))
102 && (LOWER32(key[0]) == LOWER32(ht->id)));
103 else
104 return (LOWER32(key[0]) == LOWER32(ht->id));
105}
106
107/** Perform actions after removal of item from the hash table.
108 *
109 * @param item Item that was removed from the hash table.
110 *
111 */
112static void task_remove(link_t *item)
113{
114 assert(item);
115 free(hash_table_get_instance(item, hashed_task_t, link));
116}
117
118/** Operations for task hash table. */
119static hash_table_operations_t task_hash_table_ops = {
120 .hash = task_hash,
121 .compare = task_compare,
122 .remove_callback = task_remove
123};
124
125/** Task hash table structure. */
126static hash_table_t task_hash_table;
127
128/** Pending task wait structure. */
129typedef struct {
130 link_t link;
131 task_id_t id; /**< Task ID. */
132 ipc_callid_t callid; /**< Call ID waiting for the connection */
133} pending_wait_t;
134
135static link_t pending_wait;
136
137int task_init(void)
138{
139 if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
140 2, &task_hash_table_ops)) {
141 printf(NAME ": No memory available for tasks\n");
142 return ENOMEM;
143 }
144
145 if (event_subscribe(EVENT_WAIT, 0) != EOK)
146 printf(NAME ": Error registering wait notifications\n");
147
148 list_initialize(&pending_wait);
149
150 return EOK;
151}
152
153/** Process pending wait requests */
154void process_pending_wait(void)
155{
156 link_t *cur;
157
158loop:
159 for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
160 pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
161
162 unsigned long keys[2] = {
163 LOWER32(pr->id),
164 UPPER32(pr->id)
165 };
166
167 link_t *link = hash_table_find(&task_hash_table, keys);
168 if (!link)
169 continue;
170
171 hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
172 if (!ht->destroyed)
173 continue;
174
175 if (!(pr->callid & IPC_CALLID_NOTIFICATION))
176 ipc_answer_0(pr->callid, EOK);
177
178 hash_table_remove(&task_hash_table, keys, 2);
179 list_remove(cur);
180 free(pr);
181 goto loop;
182 }
183}
184
185static void fail_pending_wait(task_id_t id, int rc)
186{
187 link_t *cur;
188
189loop:
190 for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
191 pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
192
193 if (pr->id == id) {
194 if (!(pr->callid & IPC_CALLID_NOTIFICATION))
195 ipc_answer_0(pr->callid, rc);
196
197 list_remove(cur);
198 free(pr);
199 goto loop;
200 }
201 }
202}
203
204void wait_notification(wait_type_t et, task_id_t id)
205{
206 unsigned long keys[2] = {
207 LOWER32(id),
208 UPPER32(id)
209 };
210
211 link_t *link = hash_table_find(&task_hash_table, keys);
212
213 if (link == NULL) {
214 hashed_task_t *ht =
215 (hashed_task_t *) malloc(sizeof(hashed_task_t));
216 if (ht == NULL) {
217 fail_pending_wait(id, ENOMEM);
218 return;
219 }
220
221 link_initialize(&ht->link);
222 ht->id = id;
223 ht->destroyed = (et == TASK_CREATE) ? false : true;
224 hash_table_insert(&task_hash_table, keys, &ht->link);
225 } else {
226 hashed_task_t *ht =
227 hash_table_get_instance(link, hashed_task_t, link);
228 ht->destroyed = (et == TASK_CREATE) ? false : true;
229 }
230}
231
232void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid)
233{
234 ipcarg_t retval;
235 unsigned long keys[2] = {
236 LOWER32(id),
237 UPPER32(id)
238 };
239
240 link_t *link = hash_table_find(&task_hash_table, keys);
241 hashed_task_t *ht = (link != NULL) ?
242 hash_table_get_instance(link, hashed_task_t, link) : NULL;
243
244 if ((ht == NULL) || (!ht->destroyed)) {
245 /* Add to pending list */
246 pending_wait_t *pr =
247 (pending_wait_t *) malloc(sizeof(pending_wait_t));
248 if (!pr) {
249 retval = ENOMEM;
250 goto out;
251 }
252
253 pr->id = id;
254 pr->callid = callid;
255 list_append(&pr->link, &pending_wait);
256 return;
257 }
258
259 hash_table_remove(&task_hash_table, keys, 2);
260 retval = EOK;
261
262out:
263 if (!(callid & IPC_CALLID_NOTIFICATION))
264 ipc_answer_0(callid, retval);
265}
266
267/**
268 * @}
269 */
Note: See TracBrowser for help on using the repository browser.