Changes in uspace/lib/c/generic/async.c [927a181e:8820544] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async.c
r927a181e r8820544 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> … … 109 111 #include <sys/time.h> 110 112 #include <libarch/barrier.h> 111 #include < bool.h>113 #include <stdbool.h> 112 114 #include <malloc.h> 113 115 #include <mem.h> … … 116 118 #include "private/libc.h" 117 119 118 119 120 /** Session data */ 120 121 struct async_sess { … … 166 167 167 168 /** Async framework global futex */ 168 futex_t async_futex = FUTEX_INITIALIZER;169 atomic_t async_futex = FUTEX_INITIALIZER; 169 170 170 171 /** Number of threads waiting for IPC in the kernel. */ … … 242 243 async_client_conn_t cfibril; 243 244 } connection_t; 245 246 /* Notification data */ 247 typedef struct { 248 ht_link_t link; 249 250 /** Notification method */ 251 sysarg_t imethod; 252 253 /** Notification handler */ 254 async_notification_handler_t handler; 255 256 /** Notification data */ 257 void *data; 258 } notification_t; 244 259 245 260 /** Identifier of the incoming connection handled by the current fibril. */ … … 335 350 } 336 351 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 352 static async_client_conn_t client_connection = default_client_connection; 351 static async_interrupt_handler_t interrupt_received = default_interrupt_received;353 static size_t notification_handler_stksz = FIBRIL_DFLT_STK_SIZE; 352 354 353 355 /** Setter for client_connection function pointer. … … 362 364 } 363 365 364 /** Setter for interrupt_received function pointer. 365 * 366 * @param intr Function that will implement a new interrupt 367 * notification fibril. 368 */ 369 void async_set_interrupt_received(async_interrupt_handler_t intr) 370 { 371 interrupt_received = intr; 366 /** Set the stack size for the notification handler notification fibrils. 367 * 368 * @param size Stack size in bytes. 369 */ 370 void async_set_notification_handler_stack_size(size_t size) 371 { 372 notification_handler_stksz = size; 372 373 } 373 374 … … 389 390 static hash_table_t client_hash_table; 390 391 static hash_table_t conn_hash_table; 392 static hash_table_t notification_hash_table; 391 393 static LIST_INITIALIZE(timeout_list); 392 394 393 static size_t client_key_hash(void *k) 394 { 395 task_id_t key = *(task_id_t*)k; 396 return key; 395 static sysarg_t notification_avail = 0; 396 397 static size_t client_key_hash(void *key) 398 { 399 task_id_t in_task_id = *(task_id_t *) key; 400 return in_task_id; 397 401 } 398 402 … … 403 407 } 404 408 405 static bool client_key_equal(void *k , const ht_link_t *item)406 { 407 task_id_t key = *(task_id_t*)k;409 static bool client_key_equal(void *key, const ht_link_t *item) 410 { 411 task_id_t in_task_id = *(task_id_t *) key; 408 412 client_t *client = hash_table_get_inst(item, client_t, link); 409 return key == client->in_task_id; 410 } 411 413 return in_task_id == client->in_task_id; 414 } 412 415 413 416 /** Operations for the client hash table. */ … … 429 432 static size_t conn_key_hash(void *key) 430 433 { 431 sysarg_t in_phone_hash = *(sysarg_t*)key;432 return in_phone_hash 434 sysarg_t in_phone_hash = *(sysarg_t *) key; 435 return in_phone_hash; 433 436 } 434 437 … … 441 444 static bool conn_key_equal(void *key, const ht_link_t *item) 442 445 { 443 sysarg_t in_phone_hash = *(sysarg_t *)key;446 sysarg_t in_phone_hash = *(sysarg_t *) key; 444 447 connection_t *conn = hash_table_get_inst(item, connection_t, link); 445 448 return (in_phone_hash == conn->in_phone_hash); 446 449 } 447 448 450 449 451 /** Operations for the connection hash table. */ … … 452 454 .key_hash = conn_key_hash, 453 455 .key_equal = conn_key_equal, 456 .equal = NULL, 457 .remove_callback = NULL 458 }; 459 460 static size_t notification_key_hash(void *key) 461 { 462 sysarg_t id = *(sysarg_t *) key; 463 return id; 464 } 465 466 static size_t notification_hash(const ht_link_t *item) 467 { 468 notification_t *notification = 469 hash_table_get_inst(item, notification_t, link); 470 return notification_key_hash(¬ification->imethod); 471 } 472 473 static bool notification_key_equal(void *key, const ht_link_t *item) 474 { 475 sysarg_t id = *(sysarg_t *) key; 476 notification_t *notification = 477 hash_table_get_inst(item, notification_t, link); 478 return id == notification->imethod; 479 } 480 481 /** Operations for the notification hash table. */ 482 static hash_table_ops_t notification_hash_table_ops = { 483 .hash = notification_hash, 484 .key_hash = notification_key_hash, 485 .key_equal = notification_key_equal, 454 486 .equal = NULL, 455 487 .remove_callback = NULL … … 501 533 futex_down(&async_futex); 502 534 503 ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash); 504 505 if (!hlp) { 535 ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash); 536 if (!link) { 506 537 futex_up(&async_futex); 507 538 return false; 508 539 } 509 540 510 connection_t *conn = hash_table_get_inst( hlp, connection_t, link);541 connection_t *conn = hash_table_get_inst(link, connection_t, link); 511 542 512 543 msg_t *msg = malloc(sizeof(*msg)); … … 543 574 * 544 575 * When a notification arrives, a fibril with this implementing function is 545 * created. It calls interrupt_received() and does the final cleanup. 576 * created. It calls the corresponding notification handler and does the final 577 * cleanup. 546 578 * 547 579 * @param arg Message structure pointer. … … 555 587 556 588 msg_t *msg = (msg_t *) arg; 557 interrupt_received(msg->callid, &msg->call); 589 async_notification_handler_t handler = NULL; 590 void *data = NULL; 591 592 futex_down(&async_futex); 593 594 ht_link_t *link = hash_table_find(¬ification_hash_table, 595 &IPC_GET_IMETHOD(msg->call)); 596 if (link) { 597 notification_t *notification = 598 hash_table_get_inst(link, notification_t, link); 599 handler = notification->handler; 600 data = notification->data; 601 } 602 603 futex_up(&async_futex); 604 605 if (handler) 606 handler(msg->callid, &msg->call, data); 558 607 559 608 free(msg); … … 561 610 } 562 611 563 /** Process interruptnotification.612 /** Process notification. 564 613 * 565 614 * A new fibril is created which would process the notification. … … 587 636 msg->call = *call; 588 637 589 fid_t fid = fibril_create(notification_fibril, msg); 638 fid_t fid = fibril_create_generic(notification_fibril, msg, 639 notification_handler_stksz); 590 640 if (fid == 0) { 591 641 free(msg); … … 598 648 futex_up(&async_futex); 599 649 return true; 650 } 651 652 /** Subscribe to IRQ notification. 653 * 654 * @param inr IRQ number. 655 * @param devno Device number of the device generating inr. 656 * @param handler Notification handler. 657 * @param data Notification handler client data. 658 * @param ucode Top-half pseudocode handler. 659 * 660 * @return Zero on success or a negative error code. 661 * 662 */ 663 int async_irq_subscribe(int inr, int devno, 664 async_notification_handler_t handler, void *data, const irq_code_t *ucode) 665 { 666 notification_t *notification = 667 (notification_t *) malloc(sizeof(notification_t)); 668 if (!notification) 669 return ENOMEM; 670 671 futex_down(&async_futex); 672 673 sysarg_t imethod = notification_avail; 674 notification_avail++; 675 676 notification->imethod = imethod; 677 notification->handler = handler; 678 notification->data = data; 679 680 hash_table_insert(¬ification_hash_table, ¬ification->link); 681 682 futex_up(&async_futex); 683 684 return ipc_irq_subscribe(inr, devno, imethod, ucode); 685 } 686 687 /** Unsubscribe from IRQ notification. 688 * 689 * @param inr IRQ number. 690 * @param devno Device number of the device generating inr. 691 * 692 * @return Zero on success or a negative error code. 693 * 694 */ 695 int async_irq_unsubscribe(int inr, int devno) 696 { 697 // TODO: Remove entry from hash table 698 // to avoid memory leak 699 700 return ipc_irq_unsubscribe(inr, devno); 701 } 702 703 /** Subscribe to event notifications. 704 * 705 * @param evno Event type to subscribe. 706 * @param handler Notification handler. 707 * @param data Notification handler client data. 708 * 709 * @return Zero on success or a negative error code. 710 * 711 */ 712 int async_event_subscribe(event_type_t evno, 713 async_notification_handler_t handler, void *data) 714 { 715 notification_t *notification = 716 (notification_t *) malloc(sizeof(notification_t)); 717 if (!notification) 718 return ENOMEM; 719 720 futex_down(&async_futex); 721 722 sysarg_t imethod = notification_avail; 723 notification_avail++; 724 725 notification->imethod = imethod; 726 notification->handler = handler; 727 notification->data = data; 728 729 hash_table_insert(¬ification_hash_table, ¬ification->link); 730 731 futex_up(&async_futex); 732 733 return ipc_event_subscribe(evno, imethod); 734 } 735 736 /** Subscribe to task event notifications. 737 * 738 * @param evno Event type to subscribe. 739 * @param handler Notification handler. 740 * @param data Notification handler client data. 741 * 742 * @return Zero on success or a negative error code. 743 * 744 */ 745 int async_event_task_subscribe(event_task_type_t evno, 746 async_notification_handler_t handler, void *data) 747 { 748 notification_t *notification = 749 (notification_t *) malloc(sizeof(notification_t)); 750 if (!notification) 751 return ENOMEM; 752 753 futex_down(&async_futex); 754 755 sysarg_t imethod = notification_avail; 756 notification_avail++; 757 758 notification->imethod = imethod; 759 notification->handler = handler; 760 notification->data = data; 761 762 hash_table_insert(¬ification_hash_table, ¬ification->link); 763 764 futex_up(&async_futex); 765 766 return ipc_event_task_subscribe(evno, imethod); 767 } 768 769 /** Unmask event notifications. 770 * 771 * @param evno Event type to unmask. 772 * 773 * @return Value returned by the kernel. 774 * 775 */ 776 int async_event_unmask(event_type_t evno) 777 { 778 return ipc_event_unmask(evno); 779 } 780 781 /** Unmask task event notifications. 782 * 783 * @param evno Event type to unmask. 784 * 785 * @return Value returned by the kernel. 786 * 787 */ 788 int async_event_task_unmask(event_task_type_t evno) 789 { 790 return ipc_event_task_unmask(evno); 600 791 } 601 792 … … 691 882 692 883 futex_down(&async_futex); 693 ht_link_t *l nk = hash_table_find(&client_hash_table, &client_id);694 if (l nk) {695 client = hash_table_get_inst(l nk, client_t, link);884 ht_link_t *link = hash_table_find(&client_hash_table, &client_id); 885 if (link) { 886 client = hash_table_get_inst(link, client_t, link); 696 887 atomic_inc(&client->refcnt); 697 888 } else if (create) { … … 1095 1286 1096 1287 if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops)) 1288 abort(); 1289 1290 if (!hash_table_create(¬ification_hash_table, 0, 0, 1291 ¬ification_hash_table_ops)) 1097 1292 abort(); 1098 1293 … … 2057 2252 2058 2253 async_sess_t *sess = exch->sess; 2254 assert(sess != NULL); 2059 2255 2060 2256 atomic_dec(&sess->refcnt); … … 2078 2274 * @param arg User defined argument. 2079 2275 * @param flags Storage for the received flags. Can be NULL. 2080 * @param dst Destination address space area base. Cannot be NULL. 2276 * @param dst Address of the storage for the destination address space area 2277 * base address. Cannot be NULL. 2081 2278 * 2082 2279 * @return Zero on success or a negative error code from errno.h. … … 2206 2403 * 2207 2404 * @param callid Hash of the IPC_M_DATA_WRITE call to answer. 2208 * @param dst Destination address space area base address. 2405 * @param dst Address of the storage for the destination address space area 2406 * base address. 2209 2407 * 2210 2408 * @return Zero on success or a value from @ref errno.h on failure. … … 2267 2465 bool async_data_read_receive(ipc_callid_t *callid, size_t *size) 2268 2466 { 2467 ipc_call_t data; 2468 return async_data_read_receive_call(callid, &data, size); 2469 } 2470 2471 /** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework. 2472 * 2473 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ 2474 * calls so that the user doesn't have to remember the meaning of each IPC 2475 * argument. 2476 * 2477 * So far, this wrapper is to be used from within a connection fibril. 2478 * 2479 * @param callid Storage for the hash of the IPC_M_DATA_READ. 2480 * @param size Storage for the maximum size. Can be NULL. 2481 * 2482 * @return True on success, false on failure. 2483 * 2484 */ 2485 bool async_data_read_receive_call(ipc_callid_t *callid, ipc_call_t *data, 2486 size_t *size) 2487 { 2269 2488 assert(callid); 2270 2271 ipc_call_t data;2272 *callid = async_get_call( &data);2273 2274 if (IPC_GET_IMETHOD( data) != IPC_M_DATA_READ)2489 assert(data); 2490 2491 *callid = async_get_call(data); 2492 2493 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ) 2275 2494 return false; 2276 2495 2277 2496 if (size) 2278 *size = (size_t) IPC_GET_ARG2( data);2497 *size = (size_t) IPC_GET_ARG2(*data); 2279 2498 2280 2499 return true; … … 2371 2590 bool async_data_write_receive(ipc_callid_t *callid, size_t *size) 2372 2591 { 2592 ipc_call_t data; 2593 return async_data_write_receive_call(callid, &data, size); 2594 } 2595 2596 /** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework. 2597 * 2598 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE 2599 * calls so that the user doesn't have to remember the meaning of each IPC 2600 * argument. 2601 * 2602 * So far, this wrapper is to be used from within a connection fibril. 2603 * 2604 * @param callid Storage for the hash of the IPC_M_DATA_WRITE. 2605 * @param data Storage for the ipc call data. 2606 * @param size Storage for the suggested size. May be NULL. 2607 * 2608 * @return True on success, false on failure. 2609 * 2610 */ 2611 bool async_data_write_receive_call(ipc_callid_t *callid, ipc_call_t *data, 2612 size_t *size) 2613 { 2373 2614 assert(callid); 2374 2375 ipc_call_t data;2376 *callid = async_get_call( &data);2377 2378 if (IPC_GET_IMETHOD( data) != IPC_M_DATA_WRITE)2615 assert(data); 2616 2617 *callid = async_get_call(data); 2618 2619 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE) 2379 2620 return false; 2380 2621 2381 2622 if (size) 2382 *size = (size_t) IPC_GET_ARG2( data);2623 *size = (size_t) IPC_GET_ARG2(*data); 2383 2624 2384 2625 return true;
Note:
See TracChangeset
for help on using the changeset viewer.