Changes in uspace/lib/c/generic/async.c [df956b9b:ae6021d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async.c
rdf956b9b rae6021d 77 77 * } 78 78 * 79 * my_client_connection(icallid, *icall)79 * port_handler(icallid, *icall) 80 80 * { 81 81 * if (want_refuse) { … … 101 101 #undef LIBC_ASYNC_C_ 102 102 103 #include <ipc/irq.h> 104 #include <ipc/event.h> 103 105 #include <futex.h> 104 106 #include <fibril.h> … … 114 116 #include <stdlib.h> 115 117 #include <macros.h> 118 #include <as.h> 119 #include <abi/mm/as.h> 116 120 #include "private/libc.h" 117 118 121 119 122 /** Session data */ … … 122 125 list_t exch_list; 123 126 127 /** Session interface */ 128 iface_t iface; 129 124 130 /** Exchange management style */ 125 131 exch_mgmt_t mgmt; … … 166 172 167 173 /** Async framework global futex */ 168 atomic_t async_futex = FUTEX_INITIALIZER;174 futex_t async_futex = FUTEX_INITIALIZER; 169 175 170 176 /** Number of threads waiting for IPC in the kernel. */ … … 188 194 /** If reply was received. */ 189 195 bool done; 190 196 191 197 /** If the message / reply should be discarded on arrival. */ 192 198 bool forget; 193 199 194 200 /** If already destroyed. */ 195 201 bool destroyed; … … 231 237 /** Identification of the opening call. */ 232 238 ipc_callid_t callid; 239 233 240 /** Call data of the opening call. */ 234 241 ipc_call_t call; 235 /** Local argument or NULL if none. */236 void *carg;237 242 238 243 /** Identification of the closing call. */ … … 240 245 241 246 /** Fibril function that will be used to handle the connection. */ 242 async_client_conn_t cfibril; 247 async_port_handler_t handler; 248 249 /** Client data */ 250 void *data; 243 251 } connection_t; 252 253 /** Interface data */ 254 typedef struct { 255 ht_link_t link; 256 257 /** Interface ID */ 258 iface_t iface; 259 260 /** Futex protecting the hash table */ 261 futex_t futex; 262 263 /** Interface ports */ 264 hash_table_t port_hash_table; 265 266 /** Next available port ID */ 267 port_id_t port_id_avail; 268 } interface_t; 269 270 /* Port data */ 271 typedef struct { 272 ht_link_t link; 273 274 /** Port ID */ 275 port_id_t id; 276 277 /** Port connection handler */ 278 async_port_handler_t handler; 279 280 /** Client data */ 281 void *data; 282 } port_t; 283 284 /* Notification data */ 285 typedef struct { 286 ht_link_t link; 287 288 /** Notification method */ 289 sysarg_t imethod; 290 291 /** Notification handler */ 292 async_notification_handler_t handler; 293 294 /** Notification data */ 295 void *data; 296 } notification_t; 244 297 245 298 /** Identifier of the incoming connection handled by the current fibril. */ … … 249 302 { 250 303 struct timeval tv = { 0, 0 }; 251 304 252 305 to->inlist = false; 253 306 to->occurred = false; … … 272 325 static amsg_t *amsg_create(void) 273 326 { 274 amsg_t *msg; 275 276 msg = malloc(sizeof(amsg_t)); 327 amsg_t *msg = malloc(sizeof(amsg_t)); 277 328 if (msg) { 278 329 msg->done = false; … … 283 334 awaiter_initialize(&msg->wdata); 284 335 } 285 336 286 337 return msg; 287 338 } … … 320 371 } 321 372 322 /** Default fibril function that gets called to handle new connection. 323 * 324 * This function is defined as a weak symbol - to be redefined in user code. 373 /** Default fallback fibril function. 374 * 375 * This fallback fibril function gets called on incomming 376 * connections that do not have a specific handler defined. 325 377 * 326 378 * @param callid Hash of the incoming call. … … 329 381 * 330 382 */ 331 static void default_ client_connection(ipc_callid_t callid, ipc_call_t *call,383 static void default_fallback_port_handler(ipc_callid_t callid, ipc_call_t *call, 332 384 void *arg) 333 385 { … … 335 387 } 336 388 337 /** Default fibril function that gets called to handle interrupt notifications. 338 * 339 * This function is defined as a weak symbol - to be redefined in user code. 340 * 341 * @param callid Hash of the incoming call. 342 * @param call Data of the incoming call. 343 * @param arg Local argument. 344 * 345 */ 346 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call) 347 { 348 } 349 350 static async_client_conn_t client_connection = default_client_connection; 351 static async_interrupt_handler_t interrupt_received = default_interrupt_received; 352 static size_t interrupt_handler_stksz = FIBRIL_DFLT_STK_SIZE; 353 354 /** Setter for client_connection function pointer. 355 * 356 * @param conn Function that will implement a new connection fibril. 357 * 358 */ 359 void async_set_client_connection(async_client_conn_t conn) 360 { 361 assert(client_connection == default_client_connection); 362 client_connection = conn; 363 } 364 365 /** Setter for interrupt_received function pointer. 366 * 367 * @param intr Function that will implement a new interrupt 368 * notification fibril. 369 */ 370 void async_set_interrupt_received(async_interrupt_handler_t intr) 371 { 372 interrupt_received = intr; 373 } 374 375 /** Set the stack size for the interrupt handler notification fibrils. 376 * 377 * @param size Stack size in bytes. 378 */ 379 void async_set_interrupt_handler_stack_size(size_t size) 380 { 381 interrupt_handler_stksz = size; 389 static async_port_handler_t fallback_port_handler = 390 default_fallback_port_handler; 391 static void *fallback_port_data = NULL; 392 393 static hash_table_t interface_hash_table; 394 395 static size_t interface_key_hash(void *key) 396 { 397 iface_t iface = *(iface_t *) key; 398 return iface; 399 } 400 401 static size_t interface_hash(const ht_link_t *item) 402 { 403 interface_t *interface = hash_table_get_inst(item, interface_t, link); 404 return interface_key_hash(&interface->iface); 405 } 406 407 static bool interface_key_equal(void *key, const ht_link_t *item) 408 { 409 iface_t iface = *(iface_t *) key; 410 interface_t *interface = hash_table_get_inst(item, interface_t, link); 411 return iface == interface->iface; 412 } 413 414 /** Operations for the port hash table. */ 415 static hash_table_ops_t interface_hash_table_ops = { 416 .hash = interface_hash, 417 .key_hash = interface_key_hash, 418 .key_equal = interface_key_equal, 419 .equal = NULL, 420 .remove_callback = NULL 421 }; 422 423 static size_t port_key_hash(void *key) 424 { 425 port_id_t port_id = *(port_id_t *) key; 426 return port_id; 427 } 428 429 static size_t port_hash(const ht_link_t *item) 430 { 431 port_t *port = hash_table_get_inst(item, port_t, link); 432 return port_key_hash(&port->id); 433 } 434 435 static bool port_key_equal(void *key, const ht_link_t *item) 436 { 437 port_id_t port_id = *(port_id_t *) key; 438 port_t *port = hash_table_get_inst(item, port_t, link); 439 return port_id == port->id; 440 } 441 442 /** Operations for the port hash table. */ 443 static hash_table_ops_t port_hash_table_ops = { 444 .hash = port_hash, 445 .key_hash = port_key_hash, 446 .key_equal = port_key_equal, 447 .equal = NULL, 448 .remove_callback = NULL 449 }; 450 451 static interface_t *async_new_interface(iface_t iface) 452 { 453 interface_t *interface = 454 (interface_t *) malloc(sizeof(interface_t)); 455 if (!interface) 456 return NULL; 457 458 bool ret = hash_table_create(&interface->port_hash_table, 0, 0, 459 &port_hash_table_ops); 460 if (!ret) { 461 free(interface); 462 return NULL; 463 } 464 465 interface->iface = iface; 466 futex_initialize(&interface->futex, 1); 467 interface->port_id_avail = 0; 468 469 hash_table_insert(&interface_hash_table, &interface->link); 470 471 return interface; 472 } 473 474 static port_t *async_new_port(interface_t *interface, 475 async_port_handler_t handler, void *data) 476 { 477 port_t *port = (port_t *) malloc(sizeof(port_t)); 478 if (!port) 479 return NULL; 480 481 futex_down(&interface->futex); 482 483 port_id_t id = interface->port_id_avail; 484 interface->port_id_avail++; 485 486 port->id = id; 487 port->handler = handler; 488 port->data = data; 489 490 hash_table_insert(&interface->port_hash_table, &port->link); 491 492 futex_up(&interface->futex); 493 494 return port; 382 495 } 383 496 … … 396 509 */ 397 510 static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv); 511 512 int async_create_port(iface_t iface, async_port_handler_t handler, 513 void *data, port_id_t *port_id) 514 { 515 if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK) 516 return EINVAL; 517 518 interface_t *interface; 519 520 futex_down(&async_futex); 521 522 ht_link_t *link = hash_table_find(&interface_hash_table, &iface); 523 if (link) 524 interface = hash_table_get_inst(link, interface_t, link); 525 else 526 interface = async_new_interface(iface); 527 528 if (!interface) { 529 futex_up(&async_futex); 530 return ENOMEM; 531 } 532 533 port_t *port = async_new_port(interface, handler, data); 534 if (!port) { 535 futex_up(&async_futex); 536 return ENOMEM; 537 } 538 539 *port_id = port->id; 540 541 futex_up(&async_futex); 542 543 return EOK; 544 } 545 546 void async_set_fallback_port_handler(async_port_handler_t handler, void *data) 547 { 548 assert(handler != NULL); 549 550 fallback_port_handler = handler; 551 fallback_port_data = data; 552 } 398 553 399 554 static hash_table_t client_hash_table; 400 555 static hash_table_t conn_hash_table; 556 static hash_table_t notification_hash_table; 401 557 static LIST_INITIALIZE(timeout_list); 402 558 403 static size_t client_key_hash(void *k) 404 { 405 task_id_t key = *(task_id_t*)k; 406 return key; 559 static sysarg_t notification_avail = 0; 560 561 static size_t client_key_hash(void *key) 562 { 563 task_id_t in_task_id = *(task_id_t *) key; 564 return in_task_id; 407 565 } 408 566 … … 413 571 } 414 572 415 static bool client_key_equal(void *k , const ht_link_t *item)416 { 417 task_id_t key = *(task_id_t*)k;573 static bool client_key_equal(void *key, const ht_link_t *item) 574 { 575 task_id_t in_task_id = *(task_id_t *) key; 418 576 client_t *client = hash_table_get_inst(item, client_t, link); 419 return key == client->in_task_id; 420 } 421 577 return in_task_id == client->in_task_id; 578 } 422 579 423 580 /** Operations for the client hash table. */ … … 439 596 static size_t conn_key_hash(void *key) 440 597 { 441 sysarg_t in_phone_hash = *(sysarg_t*)key;442 return in_phone_hash 598 sysarg_t in_phone_hash = *(sysarg_t *) key; 599 return in_phone_hash; 443 600 } 444 601 … … 451 608 static bool conn_key_equal(void *key, const ht_link_t *item) 452 609 { 453 sysarg_t in_phone_hash = *(sysarg_t *)key;610 sysarg_t in_phone_hash = *(sysarg_t *) key; 454 611 connection_t *conn = hash_table_get_inst(item, connection_t, link); 455 612 return (in_phone_hash == conn->in_phone_hash); 456 613 } 457 458 614 459 615 /** Operations for the connection hash table. */ … … 466 622 }; 467 623 624 static client_t *async_client_get(task_id_t client_id, bool create) 625 { 626 client_t *client = NULL; 627 628 futex_down(&async_futex); 629 ht_link_t *link = hash_table_find(&client_hash_table, &client_id); 630 if (link) { 631 client = hash_table_get_inst(link, client_t, link); 632 atomic_inc(&client->refcnt); 633 } else if (create) { 634 client = malloc(sizeof(client_t)); 635 if (client) { 636 client->in_task_id = client_id; 637 client->data = async_client_data_create(); 638 639 atomic_set(&client->refcnt, 1); 640 hash_table_insert(&client_hash_table, &client->link); 641 } 642 } 643 644 futex_up(&async_futex); 645 return client; 646 } 647 648 static void async_client_put(client_t *client) 649 { 650 bool destroy; 651 652 futex_down(&async_futex); 653 654 if (atomic_predec(&client->refcnt) == 0) { 655 hash_table_remove(&client_hash_table, &client->in_task_id); 656 destroy = true; 657 } else 658 destroy = false; 659 660 futex_up(&async_futex); 661 662 if (destroy) { 663 if (client->data) 664 async_client_data_destroy(client->data); 665 666 free(client); 667 } 668 } 669 670 /** Wrapper for client connection fibril. 671 * 672 * When a new connection arrives, a fibril with this implementing 673 * function is created. 674 * 675 * @param arg Connection structure pointer. 676 * 677 * @return Always zero. 678 * 679 */ 680 static int connection_fibril(void *arg) 681 { 682 assert(arg); 683 684 /* 685 * Setup fibril-local connection pointer. 686 */ 687 fibril_connection = (connection_t *) arg; 688 689 /* 690 * Add our reference for the current connection in the client task 691 * tracking structure. If this is the first reference, create and 692 * hash in a new tracking structure. 693 */ 694 695 client_t *client = async_client_get(fibril_connection->in_task_id, true); 696 if (!client) { 697 ipc_answer_0(fibril_connection->callid, ENOMEM); 698 return 0; 699 } 700 701 fibril_connection->client = client; 702 703 /* 704 * Call the connection handler function. 705 */ 706 fibril_connection->handler(fibril_connection->callid, 707 &fibril_connection->call, fibril_connection->data); 708 709 /* 710 * Remove the reference for this client task connection. 711 */ 712 async_client_put(client); 713 714 /* 715 * Remove myself from the connection hash table. 716 */ 717 futex_down(&async_futex); 718 hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash); 719 futex_up(&async_futex); 720 721 /* 722 * Answer all remaining messages with EHANGUP. 723 */ 724 while (!list_empty(&fibril_connection->msg_queue)) { 725 msg_t *msg = 726 list_get_instance(list_first(&fibril_connection->msg_queue), 727 msg_t, link); 728 729 list_remove(&msg->link); 730 ipc_answer_0(msg->callid, EHANGUP); 731 free(msg); 732 } 733 734 /* 735 * If the connection was hung-up, answer the last call, 736 * i.e. IPC_M_PHONE_HUNGUP. 737 */ 738 if (fibril_connection->close_callid) 739 ipc_answer_0(fibril_connection->close_callid, EOK); 740 741 free(fibril_connection); 742 return 0; 743 } 744 745 /** Create a new fibril for a new connection. 746 * 747 * Create new fibril for connection, fill in connection structures 748 * and insert it into the hash table, so that later we can easily 749 * do routing of messages to particular fibrils. 750 * 751 * @param in_task_id Identification of the incoming connection. 752 * @param in_phone_hash Identification of the incoming connection. 753 * @param callid Hash of the opening IPC_M_CONNECT_ME_TO call. 754 * If callid is zero, the connection was opened by 755 * accepting the IPC_M_CONNECT_TO_ME call and this 756 * function is called directly by the server. 757 * @param call Call data of the opening call. 758 * @param handler Connection handler. 759 * @param data Client argument to pass to the connection handler. 760 * 761 * @return New fibril id or NULL on failure. 762 * 763 */ 764 static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash, 765 ipc_callid_t callid, ipc_call_t *call, async_port_handler_t handler, 766 void *data) 767 { 768 connection_t *conn = malloc(sizeof(*conn)); 769 if (!conn) { 770 if (callid) 771 ipc_answer_0(callid, ENOMEM); 772 773 return (uintptr_t) NULL; 774 } 775 776 conn->in_task_id = in_task_id; 777 conn->in_phone_hash = in_phone_hash; 778 list_initialize(&conn->msg_queue); 779 conn->callid = callid; 780 conn->close_callid = 0; 781 conn->handler = handler; 782 conn->data = data; 783 784 if (call) 785 conn->call = *call; 786 787 /* We will activate the fibril ASAP */ 788 conn->wdata.active = true; 789 conn->wdata.fid = fibril_create(connection_fibril, conn); 790 791 if (conn->wdata.fid == 0) { 792 free(conn); 793 794 if (callid) 795 ipc_answer_0(callid, ENOMEM); 796 797 return (uintptr_t) NULL; 798 } 799 800 /* Add connection to the connection hash table */ 801 802 futex_down(&async_futex); 803 hash_table_insert(&conn_hash_table, &conn->link); 804 futex_up(&async_futex); 805 806 fibril_add_ready(conn->wdata.fid); 807 808 return conn->wdata.fid; 809 } 810 811 /** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework. 812 * 813 * Ask through phone for a new connection to some service. 814 * 815 * @param exch Exchange for sending the message. 816 * @param iface Callback interface. 817 * @param arg1 User defined argument. 818 * @param arg2 User defined argument. 819 * @param handler Callback handler. 820 * @param data Handler data. 821 * @param port_id ID of the newly created port. 822 * 823 * @return Zero on success or a negative error code. 824 * 825 */ 826 int async_create_callback_port(async_exch_t *exch, iface_t iface, sysarg_t arg1, 827 sysarg_t arg2, async_port_handler_t handler, void *data, port_id_t *port_id) 828 { 829 if ((iface & IFACE_MOD_CALLBACK) != IFACE_MOD_CALLBACK) 830 return EINVAL; 831 832 if (exch == NULL) 833 return ENOENT; 834 835 ipc_call_t answer; 836 aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, iface, arg1, arg2, 837 &answer); 838 839 sysarg_t ret; 840 async_wait_for(req, &ret); 841 if (ret != EOK) 842 return (int) ret; 843 844 sysarg_t phone_hash = IPC_GET_ARG5(answer); 845 interface_t *interface; 846 847 futex_down(&async_futex); 848 849 ht_link_t *link = hash_table_find(&interface_hash_table, &iface); 850 if (link) 851 interface = hash_table_get_inst(link, interface_t, link); 852 else 853 interface = async_new_interface(iface); 854 855 if (!interface) { 856 futex_up(&async_futex); 857 return ENOMEM; 858 } 859 860 port_t *port = async_new_port(interface, handler, data); 861 if (!port) { 862 futex_up(&async_futex); 863 return ENOMEM; 864 } 865 866 *port_id = port->id; 867 868 futex_up(&async_futex); 869 870 fid_t fid = async_new_connection(answer.in_task_id, phone_hash, 871 0, NULL, handler, data); 872 if (fid == (uintptr_t) NULL) 873 return ENOMEM; 874 875 return EOK; 876 } 877 878 static size_t notification_key_hash(void *key) 879 { 880 sysarg_t id = *(sysarg_t *) key; 881 return id; 882 } 883 884 static size_t notification_hash(const ht_link_t *item) 885 { 886 notification_t *notification = 887 hash_table_get_inst(item, notification_t, link); 888 return notification_key_hash(¬ification->imethod); 889 } 890 891 static bool notification_key_equal(void *key, const ht_link_t *item) 892 { 893 sysarg_t id = *(sysarg_t *) key; 894 notification_t *notification = 895 hash_table_get_inst(item, notification_t, link); 896 return id == notification->imethod; 897 } 898 899 /** Operations for the notification hash table. */ 900 static hash_table_ops_t notification_hash_table_ops = { 901 .hash = notification_hash, 902 .key_hash = notification_key_hash, 903 .key_equal = notification_key_equal, 904 .equal = NULL, 905 .remove_callback = NULL 906 }; 907 468 908 /** Sort in current fibril's timeout request. 469 909 * … … 511 951 futex_down(&async_futex); 512 952 513 ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash); 514 515 if (!hlp) { 953 ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash); 954 if (!link) { 516 955 futex_up(&async_futex); 517 956 return false; 518 957 } 519 958 520 connection_t *conn = hash_table_get_inst( hlp, connection_t, link);959 connection_t *conn = hash_table_get_inst(link, connection_t, link); 521 960 522 961 msg_t *msg = malloc(sizeof(*msg)); … … 550 989 } 551 990 552 /** Notification fibril. 553 * 554 * When a notification arrives, a fibril with this implementing function is 555 * created. It calls interrupt_received() and does the final cleanup. 556 * 557 * @param arg Message structure pointer. 558 * 559 * @return Always zero. 560 * 561 */ 562 static int notification_fibril(void *arg) 563 { 564 assert(arg); 565 566 msg_t *msg = (msg_t *) arg; 567 interrupt_received(msg->callid, &msg->call); 568 569 free(msg); 570 return 0; 571 } 572 573 /** Process interrupt notification. 574 * 575 * A new fibril is created which would process the notification. 991 /** Process notification. 576 992 * 577 993 * @param callid Hash of the incoming call. 578 994 * @param call Data of the incoming call. 579 995 * 580 * @return False if an error occured.581 * True if the call was passed to the notification fibril. 582 * 583 */ 584 static bool process_notification(ipc_callid_t callid, ipc_call_t *call) 585 { 996 */ 997 static void process_notification(ipc_callid_t callid, ipc_call_t *call) 998 { 999 async_notification_handler_t handler = NULL; 1000 void *data = NULL; 1001 586 1002 assert(call); 587 1003 588 1004 futex_down(&async_futex); 589 1005 590 msg_t *msg = malloc(sizeof(*msg)); 591 if (!msg) { 592 futex_up(&async_futex); 593 return false; 594 } 595 596 msg->callid = callid; 597 msg->call = *call; 598 599 fid_t fid = fibril_create_generic(notification_fibril, msg, 600 interrupt_handler_stksz); 601 if (fid == 0) { 602 free(msg); 603 futex_up(&async_futex); 604 return false; 605 } 606 607 fibril_add_ready(fid); 1006 ht_link_t *link = hash_table_find(¬ification_hash_table, 1007 &IPC_GET_IMETHOD(*call)); 1008 if (link) { 1009 notification_t *notification = 1010 hash_table_get_inst(link, notification_t, link); 1011 handler = notification->handler; 1012 data = notification->data; 1013 } 608 1014 609 1015 futex_up(&async_futex); 610 return true; 1016 1017 if (handler) 1018 handler(callid, call, data); 1019 } 1020 1021 /** Subscribe to IRQ notification. 1022 * 1023 * @param inr IRQ number. 1024 * @param devno Device number of the device generating inr. 1025 * @param handler Notification handler. 1026 * @param data Notification handler client data. 1027 * @param ucode Top-half pseudocode handler. 1028 * 1029 * @return Zero on success or a negative error code. 1030 * 1031 */ 1032 int async_irq_subscribe(int inr, int devno, 1033 async_notification_handler_t handler, void *data, const irq_code_t *ucode) 1034 { 1035 notification_t *notification = 1036 (notification_t *) malloc(sizeof(notification_t)); 1037 if (!notification) 1038 return ENOMEM; 1039 1040 futex_down(&async_futex); 1041 1042 sysarg_t imethod = notification_avail; 1043 notification_avail++; 1044 1045 notification->imethod = imethod; 1046 notification->handler = handler; 1047 notification->data = data; 1048 1049 hash_table_insert(¬ification_hash_table, ¬ification->link); 1050 1051 futex_up(&async_futex); 1052 1053 return ipc_irq_subscribe(inr, devno, imethod, ucode); 1054 } 1055 1056 /** Unsubscribe from IRQ notification. 1057 * 1058 * @param inr IRQ number. 1059 * @param devno Device number of the device generating inr. 1060 * 1061 * @return Zero on success or a negative error code. 1062 * 1063 */ 1064 int async_irq_unsubscribe(int inr, int devno) 1065 { 1066 // TODO: Remove entry from hash table 1067 // to avoid memory leak 1068 1069 return ipc_irq_unsubscribe(inr, devno); 1070 } 1071 1072 /** Subscribe to event notifications. 1073 * 1074 * @param evno Event type to subscribe. 1075 * @param handler Notification handler. 1076 * @param data Notification handler client data. 1077 * 1078 * @return Zero on success or a negative error code. 1079 * 1080 */ 1081 int async_event_subscribe(event_type_t evno, 1082 async_notification_handler_t handler, void *data) 1083 { 1084 notification_t *notification = 1085 (notification_t *) malloc(sizeof(notification_t)); 1086 if (!notification) 1087 return ENOMEM; 1088 1089 futex_down(&async_futex); 1090 1091 sysarg_t imethod = notification_avail; 1092 notification_avail++; 1093 1094 notification->imethod = imethod; 1095 notification->handler = handler; 1096 notification->data = data; 1097 1098 hash_table_insert(¬ification_hash_table, ¬ification->link); 1099 1100 futex_up(&async_futex); 1101 1102 return ipc_event_subscribe(evno, imethod); 1103 } 1104 1105 /** Subscribe to task event notifications. 1106 * 1107 * @param evno Event type to subscribe. 1108 * @param handler Notification handler. 1109 * @param data Notification handler client data. 1110 * 1111 * @return Zero on success or a negative error code. 1112 * 1113 */ 1114 int async_event_task_subscribe(event_task_type_t evno, 1115 async_notification_handler_t handler, void *data) 1116 { 1117 notification_t *notification = 1118 (notification_t *) malloc(sizeof(notification_t)); 1119 if (!notification) 1120 return ENOMEM; 1121 1122 futex_down(&async_futex); 1123 1124 sysarg_t imethod = notification_avail; 1125 notification_avail++; 1126 1127 notification->imethod = imethod; 1128 notification->handler = handler; 1129 notification->data = data; 1130 1131 hash_table_insert(¬ification_hash_table, ¬ification->link); 1132 1133 futex_up(&async_futex); 1134 1135 return ipc_event_task_subscribe(evno, imethod); 1136 } 1137 1138 /** Unmask event notifications. 1139 * 1140 * @param evno Event type to unmask. 1141 * 1142 * @return Value returned by the kernel. 1143 * 1144 */ 1145 int async_event_unmask(event_type_t evno) 1146 { 1147 return ipc_event_unmask(evno); 1148 } 1149 1150 /** Unmask task event notifications. 1151 * 1152 * @param evno Event type to unmask. 1153 * 1154 * @return Value returned by the kernel. 1155 * 1156 */ 1157 int async_event_task_unmask(event_task_type_t evno) 1158 { 1159 return ipc_event_task_unmask(evno); 611 1160 } 612 1161 … … 640 1189 if (usecs) { 641 1190 getuptime(&conn->wdata.to_event.expires); 642 tv_add (&conn->wdata.to_event.expires, usecs);1191 tv_add_diff(&conn->wdata.to_event.expires, usecs); 643 1192 } else 644 1193 conn->wdata.to_event.inlist = false; … … 686 1235 } 687 1236 688 msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link); 1237 msg_t *msg = list_get_instance(list_first(&conn->msg_queue), 1238 msg_t, link); 689 1239 list_remove(&msg->link); 690 1240 … … 697 1247 } 698 1248 699 static client_t *async_client_get(task_id_t client_id, bool create)700 {701 client_t *client = NULL;702 703 futex_down(&async_futex);704 ht_link_t *lnk = hash_table_find(&client_hash_table, &client_id);705 if (lnk) {706 client = hash_table_get_inst(lnk, client_t, link);707 atomic_inc(&client->refcnt);708 } else if (create) {709 client = malloc(sizeof(client_t));710 if (client) {711 client->in_task_id = client_id;712 client->data = async_client_data_create();713 714 atomic_set(&client->refcnt, 1);715 hash_table_insert(&client_hash_table, &client->link);716 }717 }718 719 futex_up(&async_futex);720 return client;721 }722 723 static void async_client_put(client_t *client)724 {725 bool destroy;726 727 futex_down(&async_futex);728 729 if (atomic_predec(&client->refcnt) == 0) {730 hash_table_remove(&client_hash_table, &client->in_task_id);731 destroy = true;732 } else733 destroy = false;734 735 futex_up(&async_futex);736 737 if (destroy) {738 if (client->data)739 async_client_data_destroy(client->data);740 741 free(client);742 }743 }744 745 1249 void *async_get_client_data(void) 746 1250 { … … 754 1258 if (!client) 755 1259 return NULL; 1260 756 1261 if (!client->data) { 757 1262 async_client_put(client); 758 1263 return NULL; 759 1264 } 760 1265 761 1266 return client->data; 762 1267 } … … 765 1270 { 766 1271 client_t *client = async_client_get(client_id, false); 767 1272 768 1273 assert(client); 769 1274 assert(client->data); 770 1275 771 1276 /* Drop the reference we got in async_get_client_data_by_hash(). */ 772 1277 async_client_put(client); 773 1278 774 1279 /* Drop our own reference we got at the beginning of this function. */ 775 1280 async_client_put(client); 776 1281 } 777 1282 778 /** Wrapper for client connection fibril. 779 * 780 * When a new connection arrives, a fibril with this implementing function is 781 * created. It calls client_connection() and does the final cleanup. 782 * 783 * @param arg Connection structure pointer. 784 * 785 * @return Always zero. 786 * 787 */ 788 static int connection_fibril(void *arg) 789 { 790 assert(arg); 791 792 /* 793 * Setup fibril-local connection pointer. 794 */ 795 fibril_connection = (connection_t *) arg; 796 797 /* 798 * Add our reference for the current connection in the client task 799 * tracking structure. If this is the first reference, create and 800 * hash in a new tracking structure. 801 */ 802 803 client_t *client = async_client_get(fibril_connection->in_task_id, true); 804 if (!client) { 805 ipc_answer_0(fibril_connection->callid, ENOMEM); 806 return 0; 807 } 808 809 fibril_connection->client = client; 810 811 /* 812 * Call the connection handler function. 813 */ 814 fibril_connection->cfibril(fibril_connection->callid, 815 &fibril_connection->call, fibril_connection->carg); 816 817 /* 818 * Remove the reference for this client task connection. 819 */ 820 async_client_put(client); 821 822 /* 823 * Remove myself from the connection hash table. 824 */ 1283 static port_t *async_find_port(iface_t iface, port_id_t port_id) 1284 { 1285 port_t *port = NULL; 1286 825 1287 futex_down(&async_futex); 826 hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash); 1288 1289 ht_link_t *link = hash_table_find(&interface_hash_table, &iface); 1290 if (link) { 1291 interface_t *interface = 1292 hash_table_get_inst(link, interface_t, link); 1293 1294 link = hash_table_find(&interface->port_hash_table, &port_id); 1295 if (link) 1296 port = hash_table_get_inst(link, port_t, link); 1297 } 1298 827 1299 futex_up(&async_futex); 828 1300 829 /* 830 * Answer all remaining messages with EHANGUP. 831 */ 832 while (!list_empty(&fibril_connection->msg_queue)) { 833 msg_t *msg = 834 list_get_instance(list_first(&fibril_connection->msg_queue), 835 msg_t, link); 836 837 list_remove(&msg->link); 838 ipc_answer_0(msg->callid, EHANGUP); 839 free(msg); 840 } 841 842 /* 843 * If the connection was hung-up, answer the last call, 844 * i.e. IPC_M_PHONE_HUNGUP. 845 */ 846 if (fibril_connection->close_callid) 847 ipc_answer_0(fibril_connection->close_callid, EOK); 848 849 free(fibril_connection); 850 return 0; 851 } 852 853 /** Create a new fibril for a new connection. 854 * 855 * Create new fibril for connection, fill in connection structures and insert 856 * it into the hash table, so that later we can easily do routing of messages to 857 * particular fibrils. 858 * 859 * @param in_task_id Identification of the incoming connection. 860 * @param in_phone_hash Identification of the incoming connection. 861 * @param callid Hash of the opening IPC_M_CONNECT_ME_TO call. 862 * If callid is zero, the connection was opened by 863 * accepting the IPC_M_CONNECT_TO_ME call and this function 864 * is called directly by the server. 865 * @param call Call data of the opening call. 866 * @param cfibril Fibril function that should be called upon opening the 867 * connection. 868 * @param carg Extra argument to pass to the connection fibril 869 * 870 * @return New fibril id or NULL on failure. 871 * 872 */ 873 fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash, 874 ipc_callid_t callid, ipc_call_t *call, 875 async_client_conn_t cfibril, void *carg) 876 { 877 connection_t *conn = malloc(sizeof(*conn)); 878 if (!conn) { 879 if (callid) 880 ipc_answer_0(callid, ENOMEM); 881 882 return (uintptr_t) NULL; 883 } 884 885 conn->in_task_id = in_task_id; 886 conn->in_phone_hash = in_phone_hash; 887 list_initialize(&conn->msg_queue); 888 conn->callid = callid; 889 conn->close_callid = 0; 890 conn->carg = carg; 891 892 if (call) 893 conn->call = *call; 894 895 /* We will activate the fibril ASAP */ 896 conn->wdata.active = true; 897 conn->cfibril = cfibril; 898 conn->wdata.fid = fibril_create(connection_fibril, conn); 899 900 if (conn->wdata.fid == 0) { 901 free(conn); 902 903 if (callid) 904 ipc_answer_0(callid, ENOMEM); 905 906 return (uintptr_t) NULL; 907 } 908 909 /* Add connection to the connection hash table */ 910 911 futex_down(&async_futex); 912 hash_table_insert(&conn_hash_table, &conn->link); 913 futex_up(&async_futex); 914 915 fibril_add_ready(conn->wdata.fid); 916 917 return conn->wdata.fid; 1301 return port; 918 1302 } 919 1303 … … 931 1315 assert(call); 932 1316 933 /* Unrouted call - take some default action */1317 /* Kernel notification */ 934 1318 if ((callid & IPC_CALLID_NOTIFICATION)) { 1319 fibril_t *fibril = (fibril_t *) __tcb_get()->fibril_data; 1320 unsigned oldsw = fibril->switches; 1321 935 1322 process_notification(callid, call); 1323 1324 if (oldsw != fibril->switches) { 1325 /* 1326 * The notification handler did not execute atomically 1327 * and so the current manager fibril assumed the role of 1328 * a notification fibril. While waiting for its 1329 * resources, it switched to another manager fibril that 1330 * had already existed or it created a new one. We 1331 * therefore know there is at least yet another 1332 * manager fibril that can take over. We now kill the 1333 * current 'notification' fibril to prevent fibril 1334 * population explosion. 1335 */ 1336 futex_down(&async_futex); 1337 fibril_switch(FIBRIL_FROM_DEAD); 1338 } 1339 936 1340 return; 937 1341 } 938 1342 939 switch (IPC_GET_IMETHOD(*call)) { 940 case IPC_M_CLONE_ESTABLISH: 941 case IPC_M_CONNECT_ME_TO: 1343 /* New connection */ 1344 if (IPC_GET_IMETHOD(*call) == IPC_M_CONNECT_ME_TO) { 1345 iface_t iface = (iface_t) IPC_GET_ARG1(*call); 1346 sysarg_t in_phone_hash = IPC_GET_ARG5(*call); 1347 1348 async_notification_handler_t handler = fallback_port_handler; 1349 void *data = fallback_port_data; 1350 1351 // TODO: Currently ignores all ports but the first one 1352 port_t *port = async_find_port(iface, 0); 1353 if (port) { 1354 handler = port->handler; 1355 data = port->data; 1356 } 1357 1358 async_new_connection(call->in_task_id, in_phone_hash, callid, 1359 call, handler, data); 1360 return; 1361 } 1362 1363 /* Cloned connection */ 1364 if (IPC_GET_IMETHOD(*call) == IPC_M_CLONE_ESTABLISH) { 1365 // TODO: Currently ignores ports altogether 1366 942 1367 /* Open new connection with fibril, etc. */ 943 1368 async_new_connection(call->in_task_id, IPC_GET_ARG5(*call), 944 callid, call, client_connection, NULL);1369 callid, call, fallback_port_handler, fallback_port_data); 945 1370 return; 946 1371 } … … 1034 1459 1035 1460 } else { 1036 timeout = tv_sub(&waiter->to_event.expires, &tv); 1461 timeout = tv_sub_diff(&waiter->to_event.expires, 1462 &tv); 1037 1463 futex_up(&async_futex); 1038 1464 } … … 1086 1512 void async_create_manager(void) 1087 1513 { 1088 fid_t fid = fibril_create (async_manager_fibril, NULL);1514 fid_t fid = fibril_create_generic(async_manager_fibril, NULL, PAGE_SIZE); 1089 1515 if (fid != 0) 1090 1516 fibril_add_manager(fid); … … 1102 1528 void __async_init(void) 1103 1529 { 1530 if (!hash_table_create(&interface_hash_table, 0, 0, 1531 &interface_hash_table_ops)) 1532 abort(); 1533 1104 1534 if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops)) 1105 1535 abort(); 1106 1536 1107 1537 if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops)) 1538 abort(); 1539 1540 if (!hash_table_create(¬ification_hash_table, 0, 0, 1541 ¬ification_hash_table_ops)) 1108 1542 abort(); 1109 1543 … … 1112 1546 abort(); 1113 1547 1548 session_ns->iface = 0; 1114 1549 session_ns->mgmt = EXCHANGE_ATOMIC; 1115 1550 session_ns->phone = PHONE_NS; … … 1158 1593 1159 1594 msg->done = true; 1160 1595 1161 1596 if (msg->forget) { 1162 1597 assert(msg->wdata.active); … … 1166 1601 fibril_add_ready(msg->wdata.fid); 1167 1602 } 1168 1603 1169 1604 futex_up(&async_futex); 1170 1605 } … … 1201 1636 1202 1637 ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg, 1203 reply_received , true);1638 reply_received); 1204 1639 1205 1640 return (aid_t) msg; … … 1239 1674 1240 1675 ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5, 1241 msg, reply_received , true);1676 msg, reply_received); 1242 1677 1243 1678 return (aid_t) msg; … … 1258 1693 1259 1694 futex_down(&async_futex); 1260 1695 1261 1696 assert(!msg->forget); 1262 1697 assert(!msg->destroyed); 1263 1698 1264 1699 if (msg->done) { 1265 1700 futex_up(&async_futex); … … 1302 1737 1303 1738 amsg_t *msg = (amsg_t *) amsgid; 1304 1739 1305 1740 futex_down(&async_futex); 1306 1741 1307 1742 assert(!msg->forget); 1308 1743 assert(!msg->destroyed); 1309 1744 1310 1745 if (msg->done) { 1311 1746 futex_up(&async_futex); … … 1319 1754 if (timeout < 0) 1320 1755 timeout = 0; 1321 1756 1322 1757 getuptime(&msg->wdata.to_event.expires); 1323 tv_add (&msg->wdata.to_event.expires, timeout);1758 tv_add_diff(&msg->wdata.to_event.expires, timeout); 1324 1759 1325 1760 /* … … 1372 1807 { 1373 1808 amsg_t *msg = (amsg_t *) amsgid; 1374 1809 1375 1810 assert(msg); 1376 1811 assert(!msg->forget); 1377 1812 assert(!msg->destroyed); 1378 1813 1379 1814 futex_down(&async_futex); 1815 1380 1816 if (msg->done) { 1381 1817 amsg_destroy(msg); … … 1384 1820 msg->forget = true; 1385 1821 } 1822 1386 1823 futex_up(&async_futex); 1387 1824 } … … 1403 1840 1404 1841 getuptime(&msg->wdata.to_event.expires); 1405 tv_add (&msg->wdata.to_event.expires, timeout);1842 tv_add_diff(&msg->wdata.to_event.expires, timeout); 1406 1843 1407 1844 futex_down(&async_futex); … … 1526 1963 { 1527 1964 if (exch != NULL) 1528 ipc_call_async_0(exch->phone, imethod, NULL, NULL , true);1965 ipc_call_async_0(exch->phone, imethod, NULL, NULL); 1529 1966 } 1530 1967 … … 1532 1969 { 1533 1970 if (exch != NULL) 1534 ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL , true);1971 ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL); 1535 1972 } 1536 1973 … … 1539 1976 { 1540 1977 if (exch != NULL) 1541 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL, 1542 true); 1978 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL); 1543 1979 } 1544 1980 … … 1548 1984 if (exch != NULL) 1549 1985 ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL, 1550 NULL , true);1986 NULL); 1551 1987 } 1552 1988 … … 1556 1992 if (exch != NULL) 1557 1993 ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, 1558 NULL, NULL , true);1994 NULL, NULL); 1559 1995 } 1560 1996 … … 1564 2000 if (exch != NULL) 1565 2001 ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, 1566 arg5, NULL, NULL , true);2002 arg5, NULL, NULL); 1567 2003 } 1568 2004 … … 1629 2065 * @param arg2 User defined argument. 1630 2066 * @param arg3 User defined argument. 1631 * @param client_receiver Connection handing routine.1632 2067 * 1633 2068 * @return Zero on success or a negative error code. … … 1635 2070 */ 1636 2071 int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2, 1637 sysarg_t arg3 , async_client_conn_t client_receiver, void *carg)2072 sysarg_t arg3) 1638 2073 { 1639 2074 if (exch == NULL) 1640 2075 return ENOENT; 1641 2076 1642 sysarg_t phone_hash; 2077 ipc_call_t answer; 2078 aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3, 2079 &answer); 2080 1643 2081 sysarg_t rc; 1644 1645 aid_t req;1646 ipc_call_t answer;1647 req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,1648 &answer);1649 2082 async_wait_for(req, &rc); 1650 2083 if (rc != EOK) 1651 2084 return (int) rc; 1652 1653 phone_hash = IPC_GET_ARG5(answer);1654 1655 if (client_receiver != NULL)1656 async_new_connection(answer.in_task_id, phone_hash, 0, NULL,1657 client_receiver, carg);1658 2085 1659 2086 return EOK; … … 1696 2123 1697 2124 ipc_call_async_0(exch->phone, IPC_M_CLONE_ESTABLISH, msg, 1698 reply_received , true);2125 reply_received); 1699 2126 1700 2127 sysarg_t rc; … … 1715 2142 } 1716 2143 2144 sess->iface = 0; 1717 2145 sess->mgmt = mgmt; 1718 2146 sess->phone = phone; … … 1744 2172 1745 2173 ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4, 1746 msg, reply_received , true);2174 msg, reply_received); 1747 2175 1748 2176 sysarg_t rc; … … 1784 2212 int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3, 1785 2213 0); 1786 1787 2214 if (phone < 0) { 1788 2215 errno = phone; … … 1791 2218 } 1792 2219 2220 sess->iface = 0; 1793 2221 sess->mgmt = mgmt; 1794 2222 sess->phone = phone; … … 1807 2235 } 1808 2236 2237 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework. 2238 * 2239 * Ask through phone for a new connection to some service and block until 2240 * success. 2241 * 2242 * @param exch Exchange for sending the message. 2243 * @param iface Connection interface. 2244 * @param arg2 User defined argument. 2245 * @param arg3 User defined argument. 2246 * 2247 * @return New session on success or NULL on error. 2248 * 2249 */ 2250 async_sess_t *async_connect_me_to_iface(async_exch_t *exch, iface_t iface, 2251 sysarg_t arg2, sysarg_t arg3) 2252 { 2253 if (exch == NULL) { 2254 errno = ENOENT; 2255 return NULL; 2256 } 2257 2258 async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t)); 2259 if (sess == NULL) { 2260 errno = ENOMEM; 2261 return NULL; 2262 } 2263 2264 int phone = async_connect_me_to_internal(exch->phone, iface, arg2, 2265 arg3, 0); 2266 if (phone < 0) { 2267 errno = phone; 2268 free(sess); 2269 return NULL; 2270 } 2271 2272 sess->iface = iface; 2273 sess->phone = phone; 2274 sess->arg1 = iface; 2275 sess->arg2 = arg2; 2276 sess->arg3 = arg3; 2277 2278 fibril_mutex_initialize(&sess->remote_state_mtx); 2279 sess->remote_state_data = NULL; 2280 2281 list_initialize(&sess->exch_list); 2282 fibril_mutex_initialize(&sess->mutex); 2283 atomic_set(&sess->refcnt, 0); 2284 2285 return sess; 2286 } 2287 1809 2288 /** Set arguments for new connections. 1810 2289 * … … 1862 2341 } 1863 2342 2343 sess->iface = 0; 1864 2344 sess->mgmt = mgmt; 1865 2345 sess->phone = phone; … … 1878 2358 } 1879 2359 2360 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework. 2361 * 2362 * Ask through phone for a new connection to some service and block until 2363 * success. 2364 * 2365 * @param exch Exchange for sending the message. 2366 * @param iface Connection interface. 2367 * @param arg2 User defined argument. 2368 * @param arg3 User defined argument. 2369 * 2370 * @return New session on success or NULL on error. 2371 * 2372 */ 2373 async_sess_t *async_connect_me_to_blocking_iface(async_exch_t *exch, iface_t iface, 2374 sysarg_t arg2, sysarg_t arg3) 2375 { 2376 if (exch == NULL) { 2377 errno = ENOENT; 2378 return NULL; 2379 } 2380 2381 async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t)); 2382 if (sess == NULL) { 2383 errno = ENOMEM; 2384 return NULL; 2385 } 2386 2387 int phone = async_connect_me_to_internal(exch->phone, iface, arg2, 2388 arg3, IPC_FLAG_BLOCKING); 2389 if (phone < 0) { 2390 errno = phone; 2391 free(sess); 2392 return NULL; 2393 } 2394 2395 sess->iface = iface; 2396 sess->phone = phone; 2397 sess->arg1 = iface; 2398 sess->arg2 = arg2; 2399 sess->arg3 = arg3; 2400 2401 fibril_mutex_initialize(&sess->remote_state_mtx); 2402 sess->remote_state_data = NULL; 2403 2404 list_initialize(&sess->exch_list); 2405 fibril_mutex_initialize(&sess->mutex); 2406 atomic_set(&sess->refcnt, 0); 2407 2408 return sess; 2409 } 2410 1880 2411 /** Connect to a task specified by id. 1881 2412 * … … 1896 2427 } 1897 2428 2429 sess->iface = 0; 1898 2430 sess->mgmt = EXCHANGE_ATOMIC; 1899 2431 sess->phone = phone; … … 1973 2505 return NULL; 1974 2506 1975 async_exch_t *exch; 2507 exch_mgmt_t mgmt = sess->mgmt; 2508 if (sess->iface != 0) 2509 mgmt = sess->iface & IFACE_EXCHANGE_MASK; 2510 2511 async_exch_t *exch = NULL; 1976 2512 1977 2513 fibril_mutex_lock(&async_sess_mutex); … … 1992 2528 */ 1993 2529 1994 if (( sess->mgmt == EXCHANGE_ATOMIC) ||1995 ( sess->mgmt == EXCHANGE_SERIALIZE)) {2530 if ((mgmt == EXCHANGE_ATOMIC) || 2531 (mgmt == EXCHANGE_SERIALIZE)) { 1996 2532 exch = (async_exch_t *) malloc(sizeof(async_exch_t)); 1997 2533 if (exch != NULL) { … … 2001 2537 exch->phone = sess->phone; 2002 2538 } 2003 } else { /* EXCHANGE_PARALLEL */ 2539 } else if (mgmt == EXCHANGE_PARALLEL) { 2540 int phone; 2541 2542 retry: 2004 2543 /* 2005 2544 * Make a one-time attempt to connect a new data phone. 2006 2545 */ 2007 2008 int phone;2009 2010 retry:2011 2546 phone = async_connect_me_to_internal(sess->phone, sess->arg1, 2012 2547 sess->arg2, sess->arg3, 0); … … 2050 2585 atomic_inc(&sess->refcnt); 2051 2586 2052 if ( sess->mgmt == EXCHANGE_SERIALIZE)2587 if (mgmt == EXCHANGE_SERIALIZE) 2053 2588 fibril_mutex_lock(&sess->mutex); 2054 2589 } … … 2070 2605 assert(sess != NULL); 2071 2606 2607 exch_mgmt_t mgmt = sess->mgmt; 2608 if (sess->iface != 0) 2609 mgmt = sess->iface & IFACE_EXCHANGE_MASK; 2610 2072 2611 atomic_dec(&sess->refcnt); 2073 2612 2074 if ( sess->mgmt == EXCHANGE_SERIALIZE)2613 if (mgmt == EXCHANGE_SERIALIZE) 2075 2614 fibril_mutex_unlock(&sess->mutex); 2076 2615 … … 2281 2820 bool async_data_read_receive(ipc_callid_t *callid, size_t *size) 2282 2821 { 2822 ipc_call_t data; 2823 return async_data_read_receive_call(callid, &data, size); 2824 } 2825 2826 /** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework. 2827 * 2828 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ 2829 * calls so that the user doesn't have to remember the meaning of each IPC 2830 * argument. 2831 * 2832 * So far, this wrapper is to be used from within a connection fibril. 2833 * 2834 * @param callid Storage for the hash of the IPC_M_DATA_READ. 2835 * @param size Storage for the maximum size. Can be NULL. 2836 * 2837 * @return True on success, false on failure. 2838 * 2839 */ 2840 bool async_data_read_receive_call(ipc_callid_t *callid, ipc_call_t *data, 2841 size_t *size) 2842 { 2283 2843 assert(callid); 2284 2285 ipc_call_t data;2286 *callid = async_get_call( &data);2287 2288 if (IPC_GET_IMETHOD( data) != IPC_M_DATA_READ)2844 assert(data); 2845 2846 *callid = async_get_call(data); 2847 2848 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ) 2289 2849 return false; 2290 2850 2291 2851 if (size) 2292 *size = (size_t) IPC_GET_ARG2( data);2852 *size = (size_t) IPC_GET_ARG2(*data); 2293 2853 2294 2854 return true; … … 2385 2945 bool async_data_write_receive(ipc_callid_t *callid, size_t *size) 2386 2946 { 2947 ipc_call_t data; 2948 return async_data_write_receive_call(callid, &data, size); 2949 } 2950 2951 /** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework. 2952 * 2953 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE 2954 * calls so that the user doesn't have to remember the meaning of each IPC 2955 * argument. 2956 * 2957 * So far, this wrapper is to be used from within a connection fibril. 2958 * 2959 * @param callid Storage for the hash of the IPC_M_DATA_WRITE. 2960 * @param data Storage for the ipc call data. 2961 * @param size Storage for the suggested size. May be NULL. 2962 * 2963 * @return True on success, false on failure. 2964 * 2965 */ 2966 bool async_data_write_receive_call(ipc_callid_t *callid, ipc_call_t *data, 2967 size_t *size) 2968 { 2387 2969 assert(callid); 2388 2389 ipc_call_t data;2390 *callid = async_get_call( &data);2391 2392 if (IPC_GET_IMETHOD( data) != IPC_M_DATA_WRITE)2970 assert(data); 2971 2972 *callid = async_get_call(data); 2973 2974 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE) 2393 2975 return false; 2394 2976 2395 2977 if (size) 2396 *size = (size_t) IPC_GET_ARG2( data);2978 *size = (size_t) IPC_GET_ARG2(*data); 2397 2979 2398 2980 return true; … … 2466 3048 } 2467 3049 2468 void * _data;3050 void *arg_data; 2469 3051 2470 3052 if (nullterm) 2471 _data = malloc(size + 1);3053 arg_data = malloc(size + 1); 2472 3054 else 2473 _data = malloc(size);2474 2475 if ( _data == NULL) {3055 arg_data = malloc(size); 3056 3057 if (arg_data == NULL) { 2476 3058 ipc_answer_0(callid, ENOMEM); 2477 3059 return ENOMEM; 2478 3060 } 2479 3061 2480 int rc = async_data_write_finalize(callid, _data, size);3062 int rc = async_data_write_finalize(callid, arg_data, size); 2481 3063 if (rc != EOK) { 2482 free( _data);3064 free(arg_data); 2483 3065 return rc; 2484 3066 } 2485 3067 2486 3068 if (nullterm) 2487 ((char *) _data)[size] = 0;2488 2489 *data = _data;3069 ((char *) arg_data)[size] = 0; 3070 3071 *data = arg_data; 2490 3072 if (received != NULL) 2491 3073 *received = size; … … 2585 3167 } 2586 3168 3169 sess->iface = 0; 2587 3170 sess->mgmt = mgmt; 2588 3171 sess->phone = phone; … … 2634 3217 } 2635 3218 3219 sess->iface = 0; 2636 3220 sess->mgmt = mgmt; 2637 3221 sess->phone = phone; … … 2679 3263 return NULL; 2680 3264 3265 sess->iface = 0; 2681 3266 sess->mgmt = mgmt; 2682 3267 sess->phone = phone; … … 2706 3291 { 2707 3292 assert(callid); 2708 3293 2709 3294 ipc_call_t call; 2710 3295 *callid = async_get_call(&call); 2711 3296 2712 3297 if (IPC_GET_IMETHOD(call) != IPC_M_STATE_CHANGE_AUTHORIZE) 2713 3298 return false; … … 2719 3304 if (arg3) 2720 3305 *arg3 = IPC_GET_ARG3(call); 2721 3306 2722 3307 return true; 2723 3308 } … … 2798 3383 } 2799 3384 3385 void *async_as_area_create(void *base, size_t size, unsigned int flags, 3386 async_sess_t *pager, sysarg_t id1, sysarg_t id2, sysarg_t id3) 3387 { 3388 as_area_pager_info_t pager_info = { 3389 .pager = pager->phone, 3390 .id1 = id1, 3391 .id2 = id2, 3392 .id3 = id3 3393 }; 3394 return as_area_create(base, size, flags, &pager_info); 3395 } 3396 2800 3397 /** @} 2801 3398 */
Note:
See TracChangeset
for help on using the changeset viewer.