2
* Copyright (c) 2009 Martin Decky
3
* Copyright (c) 2009 Jiri Svoboda
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
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.
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.
35
#include <adt/hash_table.h>
44
#define TASK_HASH_TABLE_CHAINS 256
45
#define P2I_HASH_TABLE_CHAINS 256
47
static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id);
51
* As there is currently no convention that each task has to be waited
52
* for, the NS can leak memory because of the zombie tasks.
56
/** Task hash table item. */
59
task_id_t id; /**< Task ID. */
60
bool finished; /**< Task is done. */
61
bool have_rval; /**< Task returned a value. */
62
int retval; /**< The return value. */
65
/** Compute hash index into task hash table.
67
* @param key Pointer keys. However, only the first key (i.e. truncated task
68
* number) is used to compute the hash index.
70
* @return Hash index corresponding to key[0].
73
static hash_index_t task_hash(unsigned long *key)
76
return (LOWER32(*key) % TASK_HASH_TABLE_CHAINS);
79
/** Compare a key with hashed item.
81
* @param key Array of keys.
82
* @param keys Must be less than or equal to 2.
83
* @param item Pointer to a hash table item.
85
* @return Non-zero if the key matches the item, zero otherwise.
88
static int task_compare(unsigned long key[], hash_count_t keys, link_t *item)
94
hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link);
97
return ((LOWER32(key[1]) == UPPER32(ht->id))
98
&& (LOWER32(key[0]) == LOWER32(ht->id)));
100
return (LOWER32(key[0]) == LOWER32(ht->id));
103
/** Perform actions after removal of item from the hash table.
105
* @param item Item that was removed from the hash table.
108
static void task_remove(link_t *item)
111
free(hash_table_get_instance(item, hashed_task_t, link));
114
/** Operations for task hash table. */
115
static hash_table_operations_t task_hash_table_ops = {
117
.compare = task_compare,
118
.remove_callback = task_remove
121
/** Task hash table structure. */
122
static hash_table_t task_hash_table;
126
ipcarg_t phash; /**< Task ID. */
127
task_id_t id; /**< Task ID. */
130
/** Compute hash index into task hash table.
132
* @param key Array of keys.
133
* @return Hash index corresponding to key[0].
136
static hash_index_t p2i_hash(unsigned long *key)
139
return (*key % TASK_HASH_TABLE_CHAINS);
142
/** Compare a key with hashed item.
144
* @param key Array of keys.
145
* @param keys Must be less than or equal to 1.
146
* @param item Pointer to a hash table item.
148
* @return Non-zero if the key matches the item, zero otherwise.
151
static int p2i_compare(unsigned long key[], hash_count_t keys, link_t *item)
157
p2i_entry_t *e = hash_table_get_instance(item, p2i_entry_t, link);
159
return (key[0] == e->phash);
162
/** Perform actions after removal of item from the hash table.
164
* @param item Item that was removed from the hash table.
167
static void p2i_remove(link_t *item)
170
free(hash_table_get_instance(item, p2i_entry_t, link));
173
/** Operations for task hash table. */
174
static hash_table_operations_t p2i_ops = {
176
.compare = p2i_compare,
177
.remove_callback = p2i_remove
180
/** Map phone hash to task ID */
181
static hash_table_t phone_to_id;
183
/** Pending task wait structure. */
186
task_id_t id; /**< Task ID. */
187
ipc_callid_t callid; /**< Call ID waiting for the connection */
190
static link_t pending_wait;
194
if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
195
2, &task_hash_table_ops)) {
196
printf(NAME ": No memory available for tasks\n");
200
if (!hash_table_create(&phone_to_id, P2I_HASH_TABLE_CHAINS,
202
printf(NAME ": No memory available for tasks\n");
206
list_initialize(&pending_wait);
211
/** Process pending wait requests */
212
void process_pending_wait(void)
218
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
219
pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
221
unsigned long keys[2] = {
226
link_t *link = hash_table_find(&task_hash_table, keys);
230
hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
234
if (!(pr->callid & IPC_CALLID_NOTIFICATION)) {
235
texit = ht->have_rval ? TASK_EXIT_NORMAL :
236
TASK_EXIT_UNEXPECTED;
237
ipc_answer_2(pr->callid, EOK, texit,
241
hash_table_remove(&task_hash_table, keys, 2);
248
void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid)
253
unsigned long keys[2] = {
258
link_t *link = hash_table_find(&task_hash_table, keys);
259
hashed_task_t *ht = (link != NULL) ?
260
hash_table_get_instance(link, hashed_task_t, link) : NULL;
263
/* No such task exists. */
269
/* Add to pending list */
271
(pending_wait_t *) malloc(sizeof(pending_wait_t));
279
list_append(&pr->link, &pending_wait);
283
hash_table_remove(&task_hash_table, keys, 2);
287
if (!(callid & IPC_CALLID_NOTIFICATION)) {
288
texit = ht->have_rval ? TASK_EXIT_NORMAL : TASK_EXIT_UNEXPECTED;
289
ipc_answer_2(callid, retval, texit, ht->retval);
293
int ns_task_id_intro(ipc_call_t *call)
296
unsigned long keys[2];
301
id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
303
keys[0] = call->in_phone_hash;
305
link = hash_table_find(&phone_to_id, keys);
309
e = (p2i_entry_t *) malloc(sizeof(p2i_entry_t));
313
ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
317
/* Insert to phone-to-id map. */
319
link_initialize(&e->link);
320
e->phash = call->in_phone_hash;
322
hash_table_insert(&phone_to_id, keys, &e->link);
324
/* Insert to main table. */
326
keys[0] = LOWER32(id);
327
keys[1] = UPPER32(id);
329
link_initialize(&ht->link);
331
ht->finished = false;
332
ht->have_rval = false;
334
hash_table_insert(&task_hash_table, keys, &ht->link);
339
int ns_task_retval(ipc_call_t *call)
342
unsigned long keys[2];
345
rc = get_id_by_phone(call->in_phone_hash, &id);
349
keys[0] = LOWER32(id);
350
keys[1] = UPPER32(id);
352
link_t *link = hash_table_find(&task_hash_table, keys);
353
hashed_task_t *ht = (link != NULL) ?
354
hash_table_get_instance(link, hashed_task_t, link) : NULL;
356
if ((ht == NULL) || ht->finished)
360
ht->have_rval = true;
361
ht->retval = IPC_GET_ARG1(*call);
366
int ns_task_disconnect(ipc_call_t *call)
368
unsigned long keys[2];
372
rc = get_id_by_phone(call->in_phone_hash, &id);
376
/* Delete from phone-to-id map. */
377
keys[0] = call->in_phone_hash;
378
hash_table_remove(&phone_to_id, keys, 1);
380
/* Mark task as finished. */
381
keys[0] = LOWER32(id);
382
keys[1] = UPPER32(id);
384
link_t *link = hash_table_find(&task_hash_table, keys);
386
hash_table_get_instance(link, hashed_task_t, link);
395
static int get_id_by_phone(ipcarg_t phone_hash, task_id_t *id)
397
unsigned long keys[1];
401
keys[0] = phone_hash;
402
link = hash_table_find(&phone_to_id, keys);
406
e = hash_table_get_instance(link, p2i_entry_t, link);