Rev 1435 | Rev 1452 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1435 | Rev 1441 | ||
---|---|---|---|
Line 88... | Line 88... | ||
88 | #include <libadt/hash_table.h> |
88 | #include <libadt/hash_table.h> |
89 | #include <libadt/list.h> |
89 | #include <libadt/list.h> |
90 | #include <ipc/ipc.h> |
90 | #include <ipc/ipc.h> |
91 | #include <assert.h> |
91 | #include <assert.h> |
92 | #include <errno.h> |
92 | #include <errno.h> |
- | 93 | #include <time.h> |
|
- | 94 | #include <arch/barrier.h> |
|
93 | 95 | ||
94 | static atomic_t async_futex = FUTEX_INITIALIZER; |
96 | static atomic_t async_futex = FUTEX_INITIALIZER; |
95 | static hash_table_t conn_hash_table; |
97 | static hash_table_t conn_hash_table; |
- | 98 | static LIST_INITIALIZE(timeout_list); |
|
96 | 99 | ||
97 | typedef struct { |
100 | typedef struct { |
98 | pstid_t ptid; /**< Thread waiting for this message */ |
101 | pstid_t ptid; /**< Thread waiting for this message */ |
99 | int active; /**< If this thread is currently active */ |
102 | int active; /**< If this thread is currently active */ |
100 | int done; /**< If reply was received */ |
103 | int done; /**< If reply was received */ |
101 | ipc_call_t *dataptr; /**< Pointer where the answer data |
104 | ipc_call_t *dataptr; /**< Pointer where the answer data |
102 | * should be stored */ |
105 | * should be stored */ |
- | 106 | struct timeval expires; /**< Expiration time for waiting thread */ |
|
- | 107 | int has_timeout; /**< If true, this struct is in timeout list */ |
|
- | 108 | link_t link; |
|
- | 109 | ||
103 | ipcarg_t retval; |
110 | ipcarg_t retval; |
104 | } amsg_t; |
111 | } amsg_t; |
105 | 112 | ||
106 | typedef struct { |
113 | typedef struct { |
107 | link_t link; |
114 | link_t link; |
Line 121... | Line 128... | ||
121 | void (*cthread)(ipc_callid_t,ipc_call_t *); |
128 | void (*cthread)(ipc_callid_t,ipc_call_t *); |
122 | } connection_t; |
129 | } connection_t; |
123 | 130 | ||
124 | __thread connection_t *PS_connection; |
131 | __thread connection_t *PS_connection; |
125 | 132 | ||
- | 133 | /** Add microseconds to give timeval */ |
|
- | 134 | static void tv_add(struct timeval *tv, suseconds_t usecs) |
|
- | 135 | { |
|
- | 136 | tv->tv_sec += usecs / 1000000; |
|
- | 137 | tv->tv_usec += usecs % 1000000; |
|
- | 138 | if (tv->tv_usec > 1000000) { |
|
- | 139 | tv->tv_sec++; |
|
- | 140 | tv->tv_usec -= 1000000; |
|
- | 141 | } |
|
- | 142 | } |
|
- | 143 | ||
- | 144 | /** Subtract 2 timevals, return microseconds difference */ |
|
- | 145 | static suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2) |
|
- | 146 | { |
|
- | 147 | suseconds_t result; |
|
- | 148 | ||
- | 149 | result = tv1->tv_usec - tv2->tv_usec; |
|
- | 150 | result += (tv1->tv_sec - tv2->tv_sec) * 1000000; |
|
- | 151 | ||
- | 152 | return result; |
|
- | 153 | } |
|
- | 154 | ||
- | 155 | /** Compare timeval |
|
- | 156 | * |
|
- | 157 | * @return 1 if tv1 > tv2, otherwise 0 |
|
- | 158 | */ |
|
- | 159 | static int tv_gt(struct timeval *tv1, struct timeval *tv2) |
|
- | 160 | { |
|
- | 161 | if (tv1->tv_sec > tv2->tv_sec) |
|
- | 162 | return 1; |
|
- | 163 | if (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec > tv2->tv_usec) |
|
- | 164 | return 1; |
|
- | 165 | return 0; |
|
- | 166 | } |
|
- | 167 | ||
126 | /* Hash table functions */ |
168 | /* Hash table functions */ |
127 | #define CONN_HASH_TABLE_CHAINS 32 |
169 | #define CONN_HASH_TABLE_CHAINS 32 |
128 | 170 | ||
129 | static hash_index_t conn_hash(unsigned long *key) |
171 | static hash_index_t conn_hash(unsigned long *key) |
130 | { |
172 | { |
Line 324... | Line 366... | ||
324 | default: |
366 | default: |
325 | ipc_answer_fast(callid, EHANGUP, 0, 0); |
367 | ipc_answer_fast(callid, EHANGUP, 0, 0); |
326 | } |
368 | } |
327 | } |
369 | } |
328 | 370 | ||
- | 371 | /** Fire all timeouts that expired */ |
|
- | 372 | static void handle_expired_timeouts(void) |
|
- | 373 | { |
|
- | 374 | struct timeval tv; |
|
- | 375 | amsg_t *amsg; |
|
- | 376 | link_t *cur; |
|
- | 377 | ||
- | 378 | gettimeofday(&tv,NULL); |
|
- | 379 | futex_down(&async_futex); |
|
- | 380 | ||
- | 381 | cur = timeout_list.next; |
|
- | 382 | while (cur != &timeout_list) { |
|
- | 383 | amsg = list_get_instance(cur,amsg_t,link); |
|
- | 384 | if (tv_gt(&amsg->expires, &tv)) |
|
- | 385 | break; |
|
- | 386 | cur = cur->next; |
|
- | 387 | list_remove(&amsg->link); |
|
- | 388 | amsg->has_timeout = 0; |
|
- | 389 | /* Redundant condition? The thread should not |
|
- | 390 | * be active when it gets here. |
|
- | 391 | */ |
|
- | 392 | if (!amsg->active) { |
|
- | 393 | amsg->active = 1; |
|
- | 394 | psthread_add_ready(amsg->ptid); |
|
- | 395 | } |
|
- | 396 | } |
|
- | 397 | ||
- | 398 | futex_up(&async_futex); |
|
- | 399 | } |
|
- | 400 | ||
329 | /** Endless loop dispatching incoming calls and answers */ |
401 | /** Endless loop dispatching incoming calls and answers */ |
330 | int async_manager() |
402 | int async_manager(void) |
331 | { |
403 | { |
332 | ipc_call_t call; |
404 | ipc_call_t call; |
333 | ipc_callid_t callid; |
405 | ipc_callid_t callid; |
334 | int timeout; |
406 | int timeout; |
- | 407 | amsg_t *amsg; |
|
- | 408 | struct timeval tv; |
|
335 | 409 | ||
336 | while (1) { |
410 | while (1) { |
337 | if (psthread_schedule_next_adv(PS_FROM_MANAGER)) { |
411 | if (psthread_schedule_next_adv(PS_FROM_MANAGER)) { |
338 | futex_up(&async_futex); /* async_futex is always held |
412 | futex_up(&async_futex); /* async_futex is always held |
339 | * when entering manager thread |
413 | * when entering manager thread |
340 | */ |
414 | */ |
341 | continue; |
415 | continue; |
342 | } |
416 | } |
343 | /* |
- | |
- | 417 | futex_down(&async_futex); |
|
- | 418 | if (!list_empty(&timeout_list)) { |
|
- | 419 | amsg = list_get_instance(timeout_list.next,amsg_t,link); |
|
- | 420 | gettimeofday(&tv,NULL); |
|
344 | if (expires) |
421 | if (tv_gt(&tv, &amsg->expires)) { |
- | 422 | handle_expired_timeouts(); |
|
345 | timeout = .... ; |
423 | continue; |
346 | else |
424 | } else |
- | 425 | timeout = tv_sub(&amsg->expires, &tv); |
|
347 | */ |
426 | } else |
348 | timeout = SYNCH_NO_TIMEOUT; |
427 | timeout = SYNCH_NO_TIMEOUT; |
- | 428 | futex_up(&async_futex); |
|
- | 429 | ||
349 | callid = ipc_wait_cycle(&call, timeout, SYNCH_BLOCKING); |
430 | callid = ipc_wait_cycle(&call, timeout, SYNCH_BLOCKING); |
350 | 431 | ||
351 | if (!callid) { |
432 | if (!callid) { |
352 | // handle_expired_timeouts.......; |
433 | handle_expired_timeouts(); |
353 | continue; |
434 | continue; |
354 | } |
435 | } |
355 | 436 | ||
356 | if (callid & IPC_CALLID_ANSWERED) |
437 | if (callid & IPC_CALLID_ANSWERED) |
357 | continue; |
438 | continue; |
Line 415... | Line 496... | ||
415 | * call was detached |
496 | * call was detached |
416 | */ |
497 | */ |
417 | if (msg->dataptr) |
498 | if (msg->dataptr) |
418 | *msg->dataptr = *data; |
499 | *msg->dataptr = *data; |
419 | 500 | ||
- | 501 | write_barrier(); |
|
420 | /* TODO: memory barrier?? */ |
502 | /* Remove message from timeout list */ |
- | 503 | if (msg->has_timeout) |
|
- | 504 | list_remove(&msg->link); |
|
421 | msg->done = 1; |
505 | msg->done = 1; |
422 | if (! msg->active) { |
506 | if (! msg->active) { |
423 | msg->active = 1; |
507 | msg->active = 1; |
424 | psthread_add_ready(msg->ptid); |
508 | psthread_add_ready(msg->ptid); |
425 | } |
509 | } |
Line 463... | Line 547... | ||
463 | goto done; |
547 | goto done; |
464 | } |
548 | } |
465 | 549 | ||
466 | msg->ptid = psthread_get_id(); |
550 | msg->ptid = psthread_get_id(); |
467 | msg->active = 0; |
551 | msg->active = 0; |
- | 552 | msg->has_timeout = 0; |
|
468 | /* Leave locked async_futex when entering this function */ |
553 | /* Leave locked async_futex when entering this function */ |
469 | psthread_schedule_next_adv(PS_TO_MANAGER); |
554 | psthread_schedule_next_adv(PS_TO_MANAGER); |
470 | /* futex is up automatically after psthread_schedule_next...*/ |
555 | /* futex is up automatically after psthread_schedule_next...*/ |
471 | done: |
556 | done: |
472 | if (retval) |
557 | if (retval) |
473 | *retval = msg->retval; |
558 | *retval = msg->retval; |
474 | free(msg); |
559 | free(msg); |
475 | } |
560 | } |
476 | 561 | ||
- | 562 | /** Insert sort timeout msg into timeouts list |
|
- | 563 | * |
|
- | 564 | * Assume async_futex is held |
|
- | 565 | */ |
|
- | 566 | static void insert_timeout(amsg_t *msg) |
|
- | 567 | { |
|
- | 568 | link_t *tmp; |
|
- | 569 | amsg_t *cur; |
|
477 | 570 | ||
- | 571 | tmp = timeout_list.next; |
|
- | 572 | while (tmp != &timeout_list) { |
|
- | 573 | cur = list_get_instance(tmp, amsg_t, link); |
|
- | 574 | if (tv_gt(&cur->expires, &msg->expires)) |
|
- | 575 | break; |
|
- | 576 | tmp = tmp->next; |
|
- | 577 | } |
|
- | 578 | list_append(&msg->link, tmp); |
|
- | 579 | } |
|
- | 580 | ||
- | 581 | /** Wait for a message sent by async framework with timeout |
|
- | 582 | * |
|
- | 583 | * @param amsgid Message ID to wait for |
|
- | 584 | * @param retval Pointer to variable where will be stored retval |
|
- | 585 | * of the answered message. If NULL, it is ignored. |
|
- | 586 | * @param timeout Timeout in usecs |
|
- | 587 | * @return 0 on success, ETIMEOUT if timeout expired |
|
- | 588 | * |
|
- | 589 | */ |
|
478 | /* int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, int timeout) */ |
590 | int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout) |
479 | /* { */ |
591 | { |
480 | /* amsg_t *msg = (amsg_t *) amsgid; */ |
592 | amsg_t *msg = (amsg_t *) amsgid; |
481 | /* connection_t *conn; */ |
593 | connection_t *conn; |
482 | 594 | ||
483 | /* futex_down(&async_futex); */ |
595 | futex_down(&async_futex); |
484 | /* if (msg->done) { */ |
596 | if (msg->done) { |
485 | /* futex_up(&async_futex); */ |
597 | futex_up(&async_futex); |
486 | /* goto done; */ |
598 | goto done; |
487 | /* } */ |
599 | } |
488 | 600 | ||
489 | /* msg->ptid = psthread_get_id(); */ |
601 | msg->ptid = psthread_get_id(); |
490 | /* msg->active = 0; */ |
602 | msg->active = 0; |
- | 603 | msg->has_timeout = 1; |
|
- | 604 | ||
- | 605 | gettimeofday(&msg->expires, NULL); |
|
491 | /* msg->expires = gettime() + timeout; */ |
606 | tv_add(&msg->expires, timeout); |
492 | /* setup_timeouts_etc...(); */ |
607 | insert_timeout(msg); |
493 | 608 | ||
494 | /* /\* Leave locked async_futex when entering this function *\/ */ |
609 | /* Leave locked async_futex when entering this function */ |
495 | /* psthread_schedule_next_adv(PS_TO_MANAGER); */ |
610 | psthread_schedule_next_adv(PS_TO_MANAGER); |
496 | /* /\* futex is up automatically after psthread_schedule_next...*\/ */ |
611 | /* futex is up automatically after psthread_schedule_next...*/ |
497 | 612 | ||
498 | /* if (!msg->done) */ |
613 | if (!msg->done) |
499 | /* return casy-casy; */ |
614 | return ETIMEOUT; |
500 | 615 | ||
501 | /* /\* TODO: When memory barrier in reply_received, we can skip this *\/ */ |
- | |
502 | /* futex_down(&async_futex); */ |
- | |
503 | /* futex_up(&async_futex); */ |
- | |
504 | /* done: */ |
616 | done: |
505 | - | ||
506 | /* if (retval) */ |
617 | if (retval) |
507 | /* *retval = msg->retval; */ |
618 | *retval = msg->retval; |
508 | /* free(msg); */ |
619 | free(msg); |
- | 620 | ||
509 | /* } */ |
621 | return 0; |
- | 622 | } |
|
510 | 623 |