Changeset 36c9234 in mainline for uspace/lib/libc/generic/async.c
- Timestamp:
- 2007-07-04T17:03:42Z (17 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- b76f2f8
- Parents:
- f5b4fb9
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libc/generic/async.c
rf5b4fb9 r36c9234 73 73 * 74 74 * 75 * client_connection(icallid, *icall)75 * my_client_connection(icallid, *icall) 76 76 * { 77 77 * if (want_refuse) { … … 116 116 link_t link; 117 117 118 /** Fibril waiting for this message. */118 /** Identification of and link to the waiting fibril. */ 119 119 fid_t fid; 120 120 /** If true, this fibril is currently active. */ … … 135 135 } amsg_t; 136 136 137 /** 138 * Structures of this type are used to group information about a call and a 139 * message queue link. 140 */ 137 141 typedef struct { 138 142 link_t link; … … 168 172 __thread connection_t *FIBRIL_connection; 169 173 170 /** If true, it is forbidden to use async_req functions and all preemption is 171 * disabled. */ 174 /** 175 * If true, it is forbidden to use async_req functions and all preemption is 176 * disabled. 177 */ 172 178 __thread int in_interrupt_handler; 173 179 174 180 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call); 175 181 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call); 182 183 /** 184 * Pointer to a fibril function that will be used to handle connections. 185 */ 176 186 static async_client_conn_t client_connection = default_client_connection; 187 /** 188 * Pointer to a fibril function that will be used to handle interrupt 189 * notifications. 190 */ 177 191 static async_client_conn_t interrupt_received = default_interrupt_received; 178 192 … … 252 266 /** Try to route a call to an appropriate connection fibril. 253 267 * 268 * If the proper connection fibril is found, a message with the call is added to 269 * its message queue. If the fibril was not active, it is activated and all 270 * timeouts are unregistered. 271 * 272 * @param callid Hash of the incoming call. 273 * @param call Data of the incoming call. 274 * 275 * @return Zero if the call doesn't match any connection. 276 * One if the call was passed to the respective connection 277 * fibril. 254 278 */ 255 279 static int route_call(ipc_callid_t callid, ipc_call_t *call) … … 278 302 conn->close_callid = callid; 279 303 280 /* If the c all is waiting for event, runit */304 /* If the connection fibril is waiting for an event, activate it */ 281 305 if (!conn->wdata.active) { 282 306 /* If in timeout list, remove it */ … … 315 339 * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot. 316 340 * I would never expect to find so many errors in 317 * compiler *($&$(*&$341 * a compiler *($&$(*&$ 318 342 */ 319 343 conn = FIBRIL_connection; … … 357 381 } 358 382 359 /** Fibril function that gets created on new connection383 /** Default fibril function that gets called to handle new connection. 360 384 * 361 385 * This function is defined as a weak symbol - to be redefined in user code. 386 * 387 * @param callid Hash of the incoming call. 388 * @param call Data of the incoming call. 362 389 */ 363 390 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call) … … 365 392 ipc_answer_fast(callid, ENOENT, 0, 0); 366 393 } 394 395 /** Default fibril function that gets called to handle interrupt notifications. 396 * 397 * @param callid Hash of the incoming call. 398 * @param call Data of the incoming call. 399 */ 367 400 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call) 368 401 { … … 371 404 /** Wrapper for client connection fibril. 372 405 * 373 * When new connection arrives, a fibril with this implementing function is406 * When a new connection arrives, a fibril with this implementing function is 374 407 * created. It calls client_connection() and does the final cleanup. 375 408 * 376 * @param arg Connection structure pointer 409 * @param arg Connection structure pointer. 377 410 * 378 411 * @return Always zero. … … 389 422 &FIBRIL_connection->call); 390 423 391 /* Remove myself from connection hash table */424 /* Remove myself from the connection hash table */ 392 425 futex_down(&async_futex); 393 426 key = FIBRIL_connection->in_phone_hash; … … 395 428 futex_up(&async_futex); 396 429 397 /* Answer all remaining messages with ehangup*/430 /* Answer all remaining messages with EHANGUP */ 398 431 while (!list_empty(&FIBRIL_connection->msg_queue)) { 399 432 msg = list_get_instance(FIBRIL_connection->msg_queue.next, … … 417 450 * particular fibrils. 418 451 * 419 * @param in_phone_hash Identification of the incoming connection 420 * @param callid Callid of the IPC_M_CONNECT_ME_TO packet 421 * @param call Call data of the opening packet 422 * @param cfibril Fibril function that should be called upon 423 * opening the connection 424 * @return New fibril id. 452 * @param in_phone_hash Identification of the incoming connection. 453 * @param callid Hash of the opening IPC_M_CONNECT_ME_TO call. 454 * @param call Call data of the opening call. 455 * @param cfibril Fibril function that should be called upon opening the 456 * connection. 457 * 458 * @return New fibril id or NULL on failure. 425 459 */ 426 460 fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid, … … 441 475 if (call) 442 476 conn->call = *call; 443 conn->wdata.active = 1; /* We will activate it asap*/477 conn->wdata.active = 1; /* We will activate the fibril ASAP */ 444 478 conn->cfibril = cfibril; 445 479 … … 450 484 return NULL; 451 485 } 452 /* Add connection to hash table */486 /* Add connection to the connection hash table */ 453 487 key = conn->in_phone_hash; 454 488 futex_down(&async_futex); … … 461 495 } 462 496 463 /** Handle a call that was received. */ 497 /** Handle a call that was received. 498 * 499 * If the call has the IPC_M_CONNECT_ME_TO method, a new connection is created. 500 * Otherwise the call is routed to its connection fibril. 501 * 502 * @param callid Hash of the incoming call. 503 * @param call Data of the incoming call. 504 */ 464 505 static void handle_call(ipc_callid_t callid, ipc_call_t *call) 465 506 { … … 480 521 } 481 522 482 /* Try to route call through connection tables*/523 /* Try to route the call through the connection hash table */ 483 524 if (route_call(callid, call)) 484 525 return; … … 495 536 link_t *cur; 496 537 497 gettimeofday(&tv, NULL);538 gettimeofday(&tv, NULL); 498 539 futex_down(&async_futex); 499 540 … … 507 548 waiter->inlist = 0; 508 549 waiter->timedout = 1; 509 /* Redundant condition? The fibril should not 510 * be active when it gets here. 550 /* 551 * Redundant condition? 552 * The fibril should not be active when it gets here. 511 553 */ 512 554 if (!waiter->active) { … … 519 561 } 520 562 521 /** Endless loop dispatching incoming calls and answers */ 563 /** Endless loop dispatching incoming calls and answers. 564 * 565 * @return Never returns. 566 */ 522 567 static int async_manager_worker(void) 523 568 { … … 531 576 if (fibril_schedule_next_adv(FIBRIL_FROM_MANAGER)) { 532 577 futex_up(&async_futex); 533 /* async_futex is always held 534 * when entering manager fibril 578 /* 579 * async_futex is always held when entering a manager 580 * fibril. 535 581 */ 536 582 continue; … … 568 614 } 569 615 570 /** Function to start async_manager as a standalone fibril. 616 /** Function to start async_manager as a standalone fibril. 571 617 * 572 * When more kernel threads are used, one async manager should 573 * exist per thread. 618 * When more kernel threads are used, one async manager should exist per thread. 619 * 620 * @param arg Unused. 621 * 622 * @return Never returns. 574 623 */ 575 624 static int async_manager_fibril(void *arg) 576 625 { 577 626 futex_up(&async_futex); 578 /* async_futex is always locked when entering 579 * manager */ 627 /* 628 * async_futex is always locked when entering manager 629 */ 580 630 async_manager_worker(); 581 631 … … 583 633 } 584 634 585 /** Add one manager to manager list */635 /** Add one manager to manager list. */ 586 636 void async_create_manager(void) 587 637 { … … 598 648 } 599 649 600 /** Initialize internal structures needed for async manager */ 650 /** Initialize the async framework. 651 * 652 * @return Zero on success or an error code. 653 */ 601 654 int _async_init(void) 602 655 { … … 610 663 } 611 664 612 /** IPC handler for messages in async framework 613 * 614 * Notify the fibril which is waiting for this message, that it arrived 665 /** Reply received callback. 666 * 667 * This function is called whenever a reply for an asynchronous message sent out 668 * by the asynchronous framework is received. 669 * 670 * Notify the fibril which is waiting for this message that it has arrived. 671 * 672 * @param private Pointer to the asynchronous message record. 673 * @param retval Value returned in the answer. 674 * @param data Call data of the answer. 615 675 */ 616 676 static void reply_received(void *private, int retval, ipc_call_t *data) … … 621 681 622 682 futex_down(&async_futex); 623 /* Copy data after futex_down, just in case the 624 * call was detached 625 */ 683 /* Copy data after futex_down, just in case the call was detached */ 626 684 if (msg->dataptr) 627 685 *msg->dataptr = *data; … … 632 690 list_remove(&msg->wdata.link); 633 691 msg->done = 1; 634 if (! 692 if (!msg->wdata.active) { 635 693 msg->wdata.active = 1; 636 694 fibril_add_ready(msg->wdata.fid); … … 639 697 } 640 698 641 /** Send message and return id of the sent message 642 * 643 * The return value can be used as input for async_wait() to wait 644 * for completion. 699 /** Send message and return id of the sent message. 700 * 701 * The return value can be used as input for async_wait() to wait for 702 * completion. 703 * 704 * @param phoneid Handle of the phone that will be used for the send. 705 * @param method Service-defined method. 706 * @param arg1 Service-defined payload argument. 707 * @param arg2 Service-defined payload argument. 708 * @param dataptr If non-NULL, storage where the reply data will be 709 * stored. 710 * 711 * @return Hash of the sent message. 645 712 */ 646 713 aid_t async_send_2(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2, … … 659 726 msg->dataptr = dataptr; 660 727 661 msg->wdata.active = 1; /* We may sleep in next method, but it 662 * will use it's own mechanism */ 728 /* We may sleep in the next method, but it will use its own mechanism */ 729 msg->wdata.active = 1; 730 663 731 ipc_call_async_2(phoneid, method, arg1, arg2, msg, reply_received, 1); 664 732 … … 668 736 /** Send message and return id of the sent message 669 737 * 670 * The return value can be used as input for async_wait() to wait 671 * for completion. 738 * The return value can be used as input for async_wait() to wait for 739 * completion. 740 * 741 * @param phoneid Handle of the phone that will be used for the send. 742 * @param method Service-defined method. 743 * @param arg1 Service-defined payload argument. 744 * @param arg2 Service-defined payload argument. 745 * @param arg3 Service-defined payload argument. 746 * @param dataptr If non-NULL, storage where the reply data will be 747 * stored. 748 * 749 * @return Hash of the sent message. 672 750 */ 673 751 aid_t async_send_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2, … … 677 755 678 756 if (in_interrupt_handler) { 679 printf("Cannot send asynchronous request in interrupt handler.\n"); 757 printf("Cannot send asynchronous request in interrupt " 758 "handler.\n"); 680 759 _exit(1); 681 760 } … … 685 764 msg->dataptr = dataptr; 686 765 687 msg->wdata.active = 1; /* We may sleep in next method, but it 688 * will use it's own mechanism */ 766 /* We may sleep in next method, but it will use its own mechanism */ 767 msg->wdata.active = 1; 768 689 769 ipc_call_async_3(phoneid, method, arg1, arg2, arg3, msg, reply_received, 690 770 1); … … 693 773 } 694 774 695 /** Wait for a message sent by async framework696 * 697 * @param amsgid Message ID to wait for698 * @param retval Pointer to variable where will be stored retval of the699 * answered message. If NULL, it is ignored.775 /** Wait for a message sent by the async framework. 776 * 777 * @param amsgid Hash of the message to wait for. 778 * @param retval Pointer to storage where the retval of the answer will 779 * be stored. 700 780 */ 701 781 void async_wait_for(aid_t amsgid, ipcarg_t *retval) … … 712 792 msg->wdata.active = 0; 713 793 msg->wdata.inlist = 0; 714 /* Leave locked async_futexwhen entering this function */794 /* Leave the async_futex locked when entering this function */ 715 795 fibril_schedule_next_adv(FIBRIL_TO_MANAGER); 716 796 /* futex is up automatically after fibril_schedule_next...*/ … … 721 801 } 722 802 723 /** Wait for a message sent by async framework with timeout724 * 725 * @param amsgid Message ID to wait for726 * @param retval Pointer to variable where will be stored retval727 * of the answered message. If NULL, it is ignored.728 * @param timeout Timeout in usecs729 * @return 0 on success, ETIMEOUT if timeout expired730 * 803 /** Wait for a message sent by the async framework, timeout variant. 804 * 805 * @param amsgid Hash of the message to wait for. 806 * @param retval Pointer to storage where the retval of the answer will 807 * be stored. 808 * @param timeout Timeout in microseconds. 809 * 810 * @return Zero on success, ETIMEOUT if the timeout has expired. 731 811 */ 732 812 int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout) … … 751 831 insert_timeout(&msg->wdata); 752 832 753 /* Leave locked async_futexwhen entering this function */833 /* Leave the async_futex locked when entering this function */ 754 834 fibril_schedule_next_adv(FIBRIL_TO_MANAGER); 755 835 /* futex is up automatically after fibril_schedule_next...*/ … … 766 846 } 767 847 768 /** Wait specified time, but in the meantime handle incoming events 769 * 770 * @param timeout Time in microseconds to wait 848 /** Wait for specified time. 849 * 850 * The current fibril is suspended but the thread continues to execute. 851 * 852 * @param timeout Duration of the wait in microseconds. 771 853 */ 772 854 void async_usleep(suseconds_t timeout) … … 791 873 futex_down(&async_futex); 792 874 insert_timeout(&msg->wdata); 793 /* Leave locked the async_futexwhen entering this function */875 /* Leave the async_futex locked when entering this function */ 794 876 fibril_schedule_next_adv(FIBRIL_TO_MANAGER); 795 877 /* futex is up automatically after fibril_schedule_next_adv()...*/ … … 797 879 } 798 880 799 /** Set function that is called when IPC_M_CONNECT_ME_TO is received.800 * 801 * @param conn Function that will form a newfibril.881 /** Setter for client_connection function pointer. 882 * 883 * @param conn Function that will implement a new connection fibril. 802 884 */ 803 885 void async_set_client_connection(async_client_conn_t conn) … … 805 887 client_connection = conn; 806 888 } 889 890 /** Setter for interrupt_received function pointer. 891 * 892 * @param conn Function that will implement a new interrupt 893 * notification fibril. 894 */ 807 895 void async_set_interrupt_received(async_client_conn_t conn) 808 896 { … … 826 914 /** @} 827 915 */ 916
Note:
See TracChangeset
for help on using the changeset viewer.