Rev 4420 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 4420 | Rev 4537 | ||
|---|---|---|---|
| Line 93... | Line 93... | ||
| 93 | 93 | ||
| 94 | #include <futex.h> |
94 | #include <futex.h> |
| 95 | #include <async.h> |
95 | #include <async.h> |
| 96 | #include <fibril.h> |
96 | #include <fibril.h> |
| 97 | #include <stdio.h> |
97 | #include <stdio.h> |
| 98 | #include <libadt/hash_table.h> |
98 | #include <adt/hash_table.h> |
| 99 | #include <libadt/list.h> |
99 | #include <adt/list.h> |
| 100 | #include <ipc/ipc.h> |
100 | #include <ipc/ipc.h> |
| 101 | #include <assert.h> |
101 | #include <assert.h> |
| 102 | #include <errno.h> |
102 | #include <errno.h> |
| 103 | #include <sys/time.h> |
103 | #include <sys/time.h> |
| 104 | #include <arch/barrier.h> |
104 | #include <arch/barrier.h> |
| Line 172... | Line 172... | ||
| 172 | /** Fibril function that will be used to handle the connection. */ |
172 | /** Fibril function that will be used to handle the connection. */ |
| 173 | void (*cfibril)(ipc_callid_t, ipc_call_t *); |
173 | void (*cfibril)(ipc_callid_t, ipc_call_t *); |
| 174 | } connection_t; |
174 | } connection_t; |
| 175 | 175 | ||
| 176 | /** Identifier of the incoming connection handled by the current fibril. */ |
176 | /** Identifier of the incoming connection handled by the current fibril. */ |
| 177 | __thread connection_t *FIBRIL_connection; |
177 | fibril_local connection_t *FIBRIL_connection; |
| 178 | 178 | ||
| 179 | static void default_client_connection(ipc_callid_t callid, ipc_call_t *call); |
179 | static void default_client_connection(ipc_callid_t callid, ipc_call_t *call); |
| 180 | static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call); |
180 | static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call); |
| - | 181 | static void default_pending(void); |
|
| 181 | 182 | ||
| 182 | /** |
183 | /** |
| 183 | * Pointer to a fibril function that will be used to handle connections. |
184 | * Pointer to a fibril function that will be used to handle connections. |
| 184 | */ |
185 | */ |
| 185 | static async_client_conn_t client_connection = default_client_connection; |
186 | static async_client_conn_t client_connection = default_client_connection; |
| Line 188... | Line 189... | ||
| 188 | * Pointer to a fibril function that will be used to handle interrupt |
189 | * Pointer to a fibril function that will be used to handle interrupt |
| 189 | * notifications. |
190 | * notifications. |
| 190 | */ |
191 | */ |
| 191 | static async_client_conn_t interrupt_received = default_interrupt_received; |
192 | static async_client_conn_t interrupt_received = default_interrupt_received; |
| 192 | 193 | ||
| - | 194 | /** |
|
| - | 195 | * Pointer to a fibril function that will be used to handle pending |
|
| - | 196 | * operations. |
|
| - | 197 | */ |
|
| - | 198 | static async_pending_t pending = default_pending; |
|
| 193 | 199 | ||
| 194 | static hash_table_t conn_hash_table; |
200 | static hash_table_t conn_hash_table; |
| 195 | static LIST_INITIALIZE(timeout_list); |
201 | static LIST_INITIALIZE(timeout_list); |
| 196 | 202 | ||
| 197 | - | ||
| 198 | #define CONN_HASH_TABLE_CHAINS 32 |
203 | #define CONN_HASH_TABLE_CHAINS 32 |
| 199 | 204 | ||
| 200 | /** Compute hash into the connection hash table based on the source phone hash. |
205 | /** Compute hash into the connection hash table based on the source phone hash. |
| 201 | * |
206 | * |
| 202 | * @param key Pointer to source phone hash. |
207 | * @param key Pointer to source phone hash. |
| Line 374... | Line 379... | ||
| 374 | 379 | ||
| 375 | futex_up(&async_futex); |
380 | futex_up(&async_futex); |
| 376 | return true; |
381 | return true; |
| 377 | } |
382 | } |
| 378 | 383 | ||
| - | 384 | /** Pending fibril. |
|
| - | 385 | * |
|
| - | 386 | * After each call the pending operations are executed in a separate |
|
| - | 387 | * fibril. The function pending() is c. |
|
| - | 388 | * |
|
| - | 389 | * @param arg Unused. |
|
| - | 390 | * |
|
| - | 391 | * @return Always zero. |
|
| - | 392 | * |
|
| - | 393 | */ |
|
| - | 394 | static int pending_fibril(void *arg) |
|
| - | 395 | { |
|
| - | 396 | pending(); |
|
| - | 397 | ||
| - | 398 | return 0; |
|
| - | 399 | } |
|
| - | 400 | ||
| - | 401 | /** Process pending actions. |
|
| - | 402 | * |
|
| - | 403 | * A new fibril is created which would process the pending operations. |
|
| - | 404 | * |
|
| - | 405 | * @return False if an error occured. |
|
| - | 406 | * True if the execution was passed to the pending fibril. |
|
| - | 407 | * |
|
| - | 408 | */ |
|
| - | 409 | static bool process_pending(void) |
|
| - | 410 | { |
|
| - | 411 | futex_down(&async_futex); |
|
| - | 412 | ||
| - | 413 | fid_t fid = fibril_create(pending_fibril, NULL); |
|
| - | 414 | fibril_add_ready(fid); |
|
| - | 415 | ||
| - | 416 | futex_up(&async_futex); |
|
| - | 417 | return true; |
|
| - | 418 | } |
|
| - | 419 | ||
| 379 | /** Return new incoming message for the current (fibril-local) connection. |
420 | /** Return new incoming message for the current (fibril-local) connection. |
| 380 | * |
421 | * |
| 381 | * @param call Storage where the incoming call data will be stored. |
422 | * @param call Storage where the incoming call data will be stored. |
| 382 | * @param usecs Timeout in microseconds. Zero denotes no timeout. |
423 | * @param usecs Timeout in microseconds. Zero denotes no timeout. |
| 383 | * |
424 | * |
| Line 470... | Line 511... | ||
| 470 | */ |
511 | */ |
| 471 | static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call) |
512 | static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call) |
| 472 | { |
513 | { |
| 473 | } |
514 | } |
| 474 | 515 | ||
| - | 516 | /** Default fibril function that gets called to handle pending operations. |
|
| - | 517 | * |
|
| - | 518 | * This function is defined as a weak symbol - to be redefined in user code. |
|
| - | 519 | * |
|
| - | 520 | */ |
|
| - | 521 | static void default_pending(void) |
|
| - | 522 | { |
|
| - | 523 | } |
|
| - | 524 | ||
| 475 | /** Wrapper for client connection fibril. |
525 | /** Wrapper for client connection fibril. |
| 476 | * |
526 | * |
| 477 | * When a new connection arrives, a fibril with this implementing function is |
527 | * When a new connection arrives, a fibril with this implementing function is |
| 478 | * created. It calls client_connection() and does the final cleanup. |
528 | * created. It calls client_connection() and does the final cleanup. |
| 479 | * |
529 | * |
| Line 498... | Line 548... | ||
| 498 | hash_table_remove(&conn_hash_table, &key, 1); |
548 | hash_table_remove(&conn_hash_table, &key, 1); |
| 499 | futex_up(&async_futex); |
549 | futex_up(&async_futex); |
| 500 | 550 | ||
| 501 | /* Answer all remaining messages with EHANGUP */ |
551 | /* Answer all remaining messages with EHANGUP */ |
| 502 | while (!list_empty(&FIBRIL_connection->msg_queue)) { |
552 | while (!list_empty(&FIBRIL_connection->msg_queue)) { |
| 503 | msg_t *msg |
553 | msg_t *msg; |
| 504 | = list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link); |
- | |
| 505 | 554 | ||
| - | 555 | msg = list_get_instance(FIBRIL_connection->msg_queue.next, |
|
| - | 556 | msg_t, link); |
|
| 506 | list_remove(&msg->link); |
557 | list_remove(&msg->link); |
| 507 | ipc_answer_0(msg->callid, EHANGUP); |
558 | ipc_answer_0(msg->callid, EHANGUP); |
| 508 | free(msg); |
559 | free(msg); |
| 509 | } |
560 | } |
| 510 | 561 | ||
| Line 561... | Line 612... | ||
| 561 | ipc_answer_0(callid, ENOMEM); |
612 | ipc_answer_0(callid, ENOMEM); |
| 562 | return NULL; |
613 | return NULL; |
| 563 | } |
614 | } |
| 564 | 615 | ||
| 565 | /* Add connection to the connection hash table */ |
616 | /* Add connection to the connection hash table */ |
| 566 | ipcarg_t key = conn->in_phone_hash; |
617 | unsigned long key = conn->in_phone_hash; |
| 567 | 618 | ||
| 568 | futex_down(&async_futex); |
619 | futex_down(&async_futex); |
| 569 | hash_table_insert(&conn_hash_table, &key, &conn->link); |
620 | hash_table_insert(&conn_hash_table, &key, &conn->link); |
| 570 | futex_up(&async_futex); |
621 | futex_up(&async_futex); |
| 571 | 622 | ||
| Line 586... | Line 637... | ||
| 586 | static void handle_call(ipc_callid_t callid, ipc_call_t *call) |
637 | static void handle_call(ipc_callid_t callid, ipc_call_t *call) |
| 587 | { |
638 | { |
| 588 | /* Unrouted call - do some default behaviour */ |
639 | /* Unrouted call - do some default behaviour */ |
| 589 | if ((callid & IPC_CALLID_NOTIFICATION)) { |
640 | if ((callid & IPC_CALLID_NOTIFICATION)) { |
| 590 | process_notification(callid, call); |
641 | process_notification(callid, call); |
| 591 | return; |
642 | goto out; |
| 592 | } |
643 | } |
| 593 | 644 | ||
| 594 | switch (IPC_GET_METHOD(*call)) { |
645 | switch (IPC_GET_METHOD(*call)) { |
| 595 | case IPC_M_CONNECT_ME: |
646 | case IPC_M_CONNECT_ME: |
| 596 | case IPC_M_CONNECT_ME_TO: |
647 | case IPC_M_CONNECT_ME_TO: |
| 597 | /* Open new connection with fibril etc. */ |
648 | /* Open new connection with fibril etc. */ |
| 598 | async_new_connection(IPC_GET_ARG5(*call), callid, call, |
649 | async_new_connection(IPC_GET_ARG5(*call), callid, call, |
| 599 | client_connection); |
650 | client_connection); |
| 600 | return; |
651 | goto out; |
| 601 | } |
652 | } |
| 602 | 653 | ||
| 603 | /* Try to route the call through the connection hash table */ |
654 | /* Try to route the call through the connection hash table */ |
| 604 | if (route_call(callid, call)) |
655 | if (route_call(callid, call)) |
| 605 | return; |
656 | goto out; |
| 606 | 657 | ||
| 607 | /* Unknown call from unknown phone - hang it up */ |
658 | /* Unknown call from unknown phone - hang it up */ |
| 608 | ipc_answer_0(callid, EHANGUP); |
659 | ipc_answer_0(callid, EHANGUP); |
| - | 660 | return; |
|
| - | 661 | ||
| - | 662 | out: |
|
| - | 663 | process_pending(); |
|
| 609 | } |
664 | } |
| 610 | 665 | ||
| 611 | /** Fire all timeouts that expired. */ |
666 | /** Fire all timeouts that expired. */ |
| 612 | static void handle_expired_timeouts(void) |
667 | static void handle_expired_timeouts(void) |
| 613 | { |
668 | { |
| Line 661... | Line 716... | ||
| 661 | 716 | ||
| 662 | futex_down(&async_futex); |
717 | futex_down(&async_futex); |
| 663 | 718 | ||
| 664 | suseconds_t timeout; |
719 | suseconds_t timeout; |
| 665 | if (!list_empty(&timeout_list)) { |
720 | if (!list_empty(&timeout_list)) { |
| 666 | awaiter_t *waiter |
721 | awaiter_t *waiter = list_get_instance(timeout_list.next, |
| 667 | = list_get_instance(timeout_list.next, awaiter_t, link); |
722 | awaiter_t, link); |
| 668 | 723 | ||
| 669 | struct timeval tv; |
724 | struct timeval tv; |
| 670 | gettimeofday(&tv, NULL); |
725 | gettimeofday(&tv, NULL); |
| 671 | 726 | ||
| 672 | if (tv_gteq(&tv, &waiter->expires)) { |
727 | if (tv_gteq(&tv, &waiter->expires)) { |
| Line 679... | Line 734... | ||
| 679 | timeout = SYNCH_NO_TIMEOUT; |
734 | timeout = SYNCH_NO_TIMEOUT; |
| 680 | 735 | ||
| 681 | futex_up(&async_futex); |
736 | futex_up(&async_futex); |
| 682 | 737 | ||
| 683 | ipc_call_t call; |
738 | ipc_call_t call; |
| 684 | ipc_callid_t callid |
739 | ipc_callid_t callid = ipc_wait_cycle(&call, timeout, |
| 685 | = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE); |
740 | SYNCH_FLAGS_NONE); |
| 686 | 741 | ||
| 687 | if (!callid) { |
742 | if (!callid) { |
| 688 | handle_expired_timeouts(); |
743 | handle_expired_timeouts(); |
| 689 | continue; |
744 | continue; |
| 690 | } |
745 | } |
| Line 757... | Line 812... | ||
| 757 | * @param retval Value returned in the answer. |
812 | * @param retval Value returned in the answer. |
| 758 | * @param data Call data of the answer. |
813 | * @param data Call data of the answer. |
| 759 | */ |
814 | */ |
| 760 | static void reply_received(void *arg, int retval, ipc_call_t *data) |
815 | static void reply_received(void *arg, int retval, ipc_call_t *data) |
| 761 | { |
816 | { |
| - | 817 | futex_down(&async_futex); |
|
| - | 818 | ||
| 762 | amsg_t *msg = (amsg_t *) arg; |
819 | amsg_t *msg = (amsg_t *) arg; |
| 763 | msg->retval = retval; |
820 | msg->retval = retval; |
| 764 | 821 | ||
| 765 | futex_down(&async_futex); |
- | |
| 766 | - | ||
| 767 | /* Copy data after futex_down, just in case the call was detached */ |
822 | /* Copy data after futex_down, just in case the call was detached */ |
| 768 | if (msg->dataptr) |
823 | if ((msg->dataptr) && (data)) |
| 769 | *msg->dataptr = *data; |
824 | *msg->dataptr = *data; |
| 770 | 825 | ||
| 771 | write_barrier(); |
826 | write_barrier(); |
| 772 | 827 | ||
| 773 | /* Remove message from timeout list */ |
828 | /* Remove message from timeout list */ |
| Line 992... | Line 1047... | ||
| 992 | void async_set_interrupt_received(async_client_conn_t intr) |
1047 | void async_set_interrupt_received(async_client_conn_t intr) |
| 993 | { |
1048 | { |
| 994 | interrupt_received = intr; |
1049 | interrupt_received = intr; |
| 995 | } |
1050 | } |
| 996 | 1051 | ||
| - | 1052 | /** Setter for pending function pointer. |
|
| - | 1053 | * |
|
| - | 1054 | * @param pend Function that will implement a new pending |
|
| - | 1055 | * operations fibril. |
|
| - | 1056 | */ |
|
| - | 1057 | void async_set_pending(async_pending_t pend) |
|
| - | 1058 | { |
|
| - | 1059 | pending = pend; |
|
| - | 1060 | } |
|
| - | 1061 | ||
| 997 | /** Pseudo-synchronous message sending - fast version. |
1062 | /** Pseudo-synchronous message sending - fast version. |
| 998 | * |
1063 | * |
| 999 | * Send message asynchronously and return only after the reply arrives. |
1064 | * Send message asynchronously and return only after the reply arrives. |
| 1000 | * |
1065 | * |
| 1001 | * This function can only transfer 4 register payload arguments. For |
1066 | * This function can only transfer 4 register payload arguments. For |