Changes in uspace/lib/c/generic/async.c [8820544:927a181e] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async.c
r8820544 r927a181e 101 101 #undef LIBC_ASYNC_C_ 102 102 103 #include <ipc/irq.h>104 #include <ipc/event.h>105 103 #include <futex.h> 106 104 #include <fibril.h> … … 111 109 #include <sys/time.h> 112 110 #include <libarch/barrier.h> 113 #include < stdbool.h>111 #include <bool.h> 114 112 #include <malloc.h> 115 113 #include <mem.h> … … 118 116 #include "private/libc.h" 119 117 118 120 119 /** Session data */ 121 120 struct async_sess { … … 167 166 168 167 /** Async framework global futex */ 169 atomic_t async_futex = FUTEX_INITIALIZER;168 futex_t async_futex = FUTEX_INITIALIZER; 170 169 171 170 /** Number of threads waiting for IPC in the kernel. */ … … 243 242 async_client_conn_t cfibril; 244 243 } 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;259 244 260 245 /** Identifier of the incoming connection handled by the current fibril. */ … … 350 335 } 351 336 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 352 350 static async_client_conn_t client_connection = default_client_connection; 353 static size_t notification_handler_stksz = FIBRIL_DFLT_STK_SIZE;351 static async_interrupt_handler_t interrupt_received = default_interrupt_received; 354 352 355 353 /** Setter for client_connection function pointer. … … 364 362 } 365 363 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; 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; 373 372 } 374 373 … … 390 389 static hash_table_t client_hash_table; 391 390 static hash_table_t conn_hash_table; 392 static hash_table_t notification_hash_table;393 391 static LIST_INITIALIZE(timeout_list); 394 392 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; 393 static size_t client_key_hash(void *k) 394 { 395 task_id_t key = *(task_id_t*)k; 396 return key; 401 397 } 402 398 … … 407 403 } 408 404 409 static bool client_key_equal(void *k ey, const ht_link_t *item)410 { 411 task_id_t in_task_id = *(task_id_t *) key;405 static bool client_key_equal(void *k, const ht_link_t *item) 406 { 407 task_id_t key = *(task_id_t*)k; 412 408 client_t *client = hash_table_get_inst(item, client_t, link); 413 return in_task_id == client->in_task_id; 414 } 409 return key == client->in_task_id; 410 } 411 415 412 416 413 /** Operations for the client hash table. */ … … 432 429 static size_t conn_key_hash(void *key) 433 430 { 434 sysarg_t in_phone_hash = *(sysarg_t *)key;435 return in_phone_hash ;431 sysarg_t in_phone_hash = *(sysarg_t*)key; 432 return in_phone_hash ; 436 433 } 437 434 … … 444 441 static bool conn_key_equal(void *key, const ht_link_t *item) 445 442 { 446 sysarg_t in_phone_hash = *(sysarg_t *)key;443 sysarg_t in_phone_hash = *(sysarg_t*)key; 447 444 connection_t *conn = hash_table_get_inst(item, connection_t, link); 448 445 return (in_phone_hash == conn->in_phone_hash); 449 446 } 447 450 448 451 449 /** Operations for the connection hash table. */ … … 458 456 }; 459 457 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,486 .equal = NULL,487 .remove_callback = NULL488 };489 490 458 /** Sort in current fibril's timeout request. 491 459 * … … 533 501 futex_down(&async_futex); 534 502 535 ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash); 536 if (!link) { 503 ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash); 504 505 if (!hlp) { 537 506 futex_up(&async_futex); 538 507 return false; 539 508 } 540 509 541 connection_t *conn = hash_table_get_inst( link, connection_t, link);510 connection_t *conn = hash_table_get_inst(hlp, connection_t, link); 542 511 543 512 msg_t *msg = malloc(sizeof(*msg)); … … 574 543 * 575 544 * When a notification arrives, a fibril with this implementing function is 576 * created. It calls the corresponding notification handler and does the final 577 * cleanup. 545 * created. It calls interrupt_received() and does the final cleanup. 578 546 * 579 547 * @param arg Message structure pointer. … … 587 555 588 556 msg_t *msg = (msg_t *) arg; 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); 557 interrupt_received(msg->callid, &msg->call); 607 558 608 559 free(msg); … … 610 561 } 611 562 612 /** Process notification.563 /** Process interrupt notification. 613 564 * 614 565 * A new fibril is created which would process the notification. … … 636 587 msg->call = *call; 637 588 638 fid_t fid = fibril_create_generic(notification_fibril, msg, 639 notification_handler_stksz); 589 fid_t fid = fibril_create(notification_fibril, msg); 640 590 if (fid == 0) { 641 591 free(msg); … … 648 598 futex_up(&async_futex); 649 599 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 table698 // to avoid memory leak699 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);791 600 } 792 601 … … 882 691 883 692 futex_down(&async_futex); 884 ht_link_t *l ink = hash_table_find(&client_hash_table, &client_id);885 if (l ink) {886 client = hash_table_get_inst(l ink, client_t, link);693 ht_link_t *lnk = hash_table_find(&client_hash_table, &client_id); 694 if (lnk) { 695 client = hash_table_get_inst(lnk, client_t, link); 887 696 atomic_inc(&client->refcnt); 888 697 } else if (create) { … … 1286 1095 1287 1096 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))1292 1097 abort(); 1293 1098 … … 2252 2057 2253 2058 async_sess_t *sess = exch->sess; 2254 assert(sess != NULL);2255 2059 2256 2060 atomic_dec(&sess->refcnt); … … 2274 2078 * @param arg User defined argument. 2275 2079 * @param flags Storage for the received flags. Can be NULL. 2276 * @param dst Address of the storage for the destination address space area 2277 * base address. Cannot be NULL. 2080 * @param dst Destination address space area base. Cannot be NULL. 2278 2081 * 2279 2082 * @return Zero on success or a negative error code from errno.h. … … 2403 2206 * 2404 2207 * @param callid Hash of the IPC_M_DATA_WRITE call to answer. 2405 * @param dst Address of the storage for the destination address space area 2406 * base address. 2208 * @param dst Destination address space area base address. 2407 2209 * 2408 2210 * @return Zero on success or a value from @ref errno.h on failure. … … 2465 2267 bool async_data_read_receive(ipc_callid_t *callid, size_t *size) 2466 2268 { 2269 assert(callid); 2270 2467 2271 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 { 2488 assert(callid); 2489 assert(data); 2490 2491 *callid = async_get_call(data); 2492 2493 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ) 2272 *callid = async_get_call(&data); 2273 2274 if (IPC_GET_IMETHOD(data) != IPC_M_DATA_READ) 2494 2275 return false; 2495 2276 2496 2277 if (size) 2497 *size = (size_t) IPC_GET_ARG2( *data);2278 *size = (size_t) IPC_GET_ARG2(data); 2498 2279 2499 2280 return true; … … 2590 2371 bool async_data_write_receive(ipc_callid_t *callid, size_t *size) 2591 2372 { 2373 assert(callid); 2374 2592 2375 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 { 2614 assert(callid); 2615 assert(data); 2616 2617 *callid = async_get_call(data); 2618 2619 if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE) 2376 *callid = async_get_call(&data); 2377 2378 if (IPC_GET_IMETHOD(data) != IPC_M_DATA_WRITE) 2620 2379 return false; 2621 2380 2622 2381 if (size) 2623 *size = (size_t) IPC_GET_ARG2( *data);2382 *size = (size_t) IPC_GET_ARG2(data); 2624 2383 2625 2384 return true;
Note:
See TracChangeset
for help on using the changeset viewer.