00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00034 #include <ipc/ipc.h>
00035 #include <adt/hash_table.h>
00036 #include <bool.h>
00037 #include <errno.h>
00038 #include <assert.h>
00039 #include <stdio.h>
00040 #include <macros.h>
00041 #include <malloc.h>
00042 #include "task.h"
00043 #include "ns.h"
00044
00045 #define TASK_HASH_TABLE_CHAINS 256
00046 #define P2I_HASH_TABLE_CHAINS 256
00047
00048
00049
00050
00051
00052
00053
00054
00056 typedef struct {
00057 link_t link;
00058
00059 task_id_t id;
00060 bool finished;
00061 bool have_rval;
00062 int retval;
00063 } hashed_task_t;
00064
00073 static hash_index_t task_hash(unsigned long key[])
00074 {
00075 assert(key);
00076 return (LOWER32(key[0]) % TASK_HASH_TABLE_CHAINS);
00077 }
00078
00088 static int task_compare(unsigned long key[], hash_count_t keys, link_t *item)
00089 {
00090 assert(key);
00091 assert(keys <= 2);
00092 assert(item);
00093
00094 hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link);
00095
00096 if (keys == 2)
00097 return ((LOWER32(key[1]) == UPPER32(ht->id))
00098 && (LOWER32(key[0]) == LOWER32(ht->id)));
00099 else
00100 return (LOWER32(key[0]) == LOWER32(ht->id));
00101 }
00102
00108 static void task_remove(link_t *item)
00109 {
00110 assert(item);
00111 free(hash_table_get_instance(item, hashed_task_t, link));
00112 }
00113
00115 static hash_table_operations_t task_hash_table_ops = {
00116 .hash = task_hash,
00117 .compare = task_compare,
00118 .remove_callback = task_remove
00119 };
00120
00122 static hash_table_t task_hash_table;
00123
00124 typedef struct {
00125 link_t link;
00126 sysarg_t in_phone_hash;
00127 task_id_t id;
00128 } p2i_entry_t;
00129
00137 static hash_index_t p2i_hash(unsigned long key[])
00138 {
00139 assert(key);
00140 return (key[0] % TASK_HASH_TABLE_CHAINS);
00141 }
00142
00152 static int p2i_compare(unsigned long key[], hash_count_t keys, link_t *item)
00153 {
00154 assert(key);
00155 assert(keys == 1);
00156 assert(item);
00157
00158 p2i_entry_t *entry = hash_table_get_instance(item, p2i_entry_t, link);
00159
00160 return (key[0] == entry->in_phone_hash);
00161 }
00162
00168 static void p2i_remove(link_t *item)
00169 {
00170 assert(item);
00171 free(hash_table_get_instance(item, p2i_entry_t, link));
00172 }
00173
00175 static hash_table_operations_t p2i_ops = {
00176 .hash = p2i_hash,
00177 .compare = p2i_compare,
00178 .remove_callback = p2i_remove
00179 };
00180
00182 static hash_table_t phone_to_id;
00183
00185 typedef struct {
00186 link_t link;
00187 task_id_t id;
00188 ipc_callid_t callid;
00189 } pending_wait_t;
00190
00191 static link_t pending_wait;
00192
00193 int task_init(void)
00194 {
00195 if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
00196 2, &task_hash_table_ops)) {
00197 printf(NAME ": No memory available for tasks\n");
00198 return ENOMEM;
00199 }
00200
00201 if (!hash_table_create(&phone_to_id, P2I_HASH_TABLE_CHAINS,
00202 1, &p2i_ops)) {
00203 printf(NAME ": No memory available for tasks\n");
00204 return ENOMEM;
00205 }
00206
00207 list_initialize(&pending_wait);
00208 return EOK;
00209 }
00210
00212 void process_pending_wait(void)
00213 {
00214 link_t *cur;
00215 task_exit_t texit;
00216
00217 loop:
00218 for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
00219 pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
00220
00221 unsigned long keys[2] = {
00222 LOWER32(pr->id),
00223 UPPER32(pr->id)
00224 };
00225
00226 link_t *link = hash_table_find(&task_hash_table, keys);
00227 if (!link)
00228 continue;
00229
00230 hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
00231 if (!ht->finished)
00232 continue;
00233
00234 if (!(pr->callid & IPC_CALLID_NOTIFICATION)) {
00235 texit = ht->have_rval ? TASK_EXIT_NORMAL :
00236 TASK_EXIT_UNEXPECTED;
00237 ipc_answer_2(pr->callid, EOK, texit,
00238 ht->retval);
00239 }
00240
00241 hash_table_remove(&task_hash_table, keys, 2);
00242 list_remove(cur);
00243 free(pr);
00244 goto loop;
00245 }
00246 }
00247
00248 void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid)
00249 {
00250 sysarg_t retval;
00251 task_exit_t texit;
00252
00253 unsigned long keys[2] = {
00254 LOWER32(id),
00255 UPPER32(id)
00256 };
00257
00258 link_t *link = hash_table_find(&task_hash_table, keys);
00259 hashed_task_t *ht = (link != NULL) ?
00260 hash_table_get_instance(link, hashed_task_t, link) : NULL;
00261
00262 if (ht == NULL) {
00263
00264 ipc_answer_0(callid, ENOENT);
00265 return;
00266 }
00267
00268 if (!ht->finished) {
00269
00270 pending_wait_t *pr =
00271 (pending_wait_t *) malloc(sizeof(pending_wait_t));
00272 if (!pr) {
00273 retval = ENOMEM;
00274 goto out;
00275 }
00276
00277 link_initialize(&pr->link);
00278 pr->id = id;
00279 pr->callid = callid;
00280 list_append(&pr->link, &pending_wait);
00281 return;
00282 }
00283
00284 hash_table_remove(&task_hash_table, keys, 2);
00285 retval = EOK;
00286
00287 out:
00288 if (!(callid & IPC_CALLID_NOTIFICATION)) {
00289 texit = ht->have_rval ? TASK_EXIT_NORMAL : TASK_EXIT_UNEXPECTED;
00290 ipc_answer_2(callid, retval, texit, ht->retval);
00291 }
00292 }
00293
00294 int ns_task_id_intro(ipc_call_t *call)
00295 {
00296 unsigned long keys[2];
00297
00298 task_id_t id = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
00299 keys[0] = call->in_phone_hash;
00300
00301 link_t *link = hash_table_find(&phone_to_id, keys);
00302 if (link != NULL)
00303 return EEXISTS;
00304
00305 p2i_entry_t *entry = (p2i_entry_t *) malloc(sizeof(p2i_entry_t));
00306 if (entry == NULL)
00307 return ENOMEM;
00308
00309 hashed_task_t *ht = (hashed_task_t *) malloc(sizeof(hashed_task_t));
00310 if (ht == NULL)
00311 return ENOMEM;
00312
00313
00314
00315
00316
00317 link_initialize(&entry->link);
00318 entry->in_phone_hash = call->in_phone_hash;
00319 entry->id = id;
00320 hash_table_insert(&phone_to_id, keys, &entry->link);
00321
00322
00323
00324
00325
00326 keys[0] = LOWER32(id);
00327 keys[1] = UPPER32(id);
00328
00329 link_initialize(&ht->link);
00330 ht->id = id;
00331 ht->finished = false;
00332 ht->have_rval = false;
00333 ht->retval = -1;
00334 hash_table_insert(&task_hash_table, keys, &ht->link);
00335
00336 return EOK;
00337 }
00338
00339 static int get_id_by_phone(sysarg_t phone_hash, task_id_t *id)
00340 {
00341 unsigned long keys[1] = {phone_hash};
00342
00343 link_t *link = hash_table_find(&phone_to_id, keys);
00344 if (link == NULL)
00345 return ENOENT;
00346
00347 p2i_entry_t *entry = hash_table_get_instance(link, p2i_entry_t, link);
00348 *id = entry->id;
00349
00350 return EOK;
00351 }
00352
00353 int ns_task_retval(ipc_call_t *call)
00354 {
00355 task_id_t id;
00356 int rc = get_id_by_phone(call->in_phone_hash, &id);
00357 if (rc != EOK)
00358 return rc;
00359
00360 unsigned long keys[2] = {
00361 LOWER32(id),
00362 UPPER32(id)
00363 };
00364
00365 link_t *link = hash_table_find(&task_hash_table, keys);
00366 hashed_task_t *ht = (link != NULL) ?
00367 hash_table_get_instance(link, hashed_task_t, link) : NULL;
00368
00369 if ((ht == NULL) || (ht->finished))
00370 return EINVAL;
00371
00372 ht->finished = true;
00373 ht->have_rval = true;
00374 ht->retval = IPC_GET_ARG1(*call);
00375
00376 return EOK;
00377 }
00378
00379 int ns_task_disconnect(ipc_call_t *call)
00380 {
00381 unsigned long keys[2];
00382
00383 task_id_t id;
00384 int rc = get_id_by_phone(call->in_phone_hash, &id);
00385 if (rc != EOK)
00386 return rc;
00387
00388
00389 keys[0] = call->in_phone_hash;
00390 hash_table_remove(&phone_to_id, keys, 1);
00391
00392
00393 keys[0] = LOWER32(id);
00394 keys[1] = UPPER32(id);
00395
00396 link_t *link = hash_table_find(&task_hash_table, keys);
00397 hashed_task_t *ht =
00398 hash_table_get_instance(link, hashed_task_t, link);
00399 if (ht == NULL)
00400 return EOK;
00401
00402 ht->finished = true;
00403
00404 return EOK;
00405 }
00406