Changes in uspace/lib/c/generic/async/server.c [e768aea:061274f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async/server.c
re768aea r061274f 122 122 #include "../private/fibril.h" 123 123 124 #define DPRINTF(...) ((void) 0) 125 124 126 /** Async framework global futex */ 125 127 futex_t async_futex = FUTEX_INITIALIZER; … … 132 134 link_t link; 133 135 134 cap_call_handle_t chandle;135 136 ipc_call_t call; 136 137 } msg_t; … … 164 165 list_t msg_queue; 165 166 166 /** Identification of the opening call. */167 cap_call_handle_t chandle;168 169 167 /** Call data of the opening call. */ 170 168 ipc_call_t call; … … 179 177 void *data; 180 178 } connection_t; 179 180 /* Member of notification_t::msg_list. */ 181 typedef struct { 182 link_t link; 183 ipc_call_t calldata; 184 } notification_msg_t; 181 185 182 186 /* Notification data */ … … 197 201 void *arg; 198 202 199 /** Data of the most recent notification. */ 200 ipc_call_t calldata; 201 202 /** 203 * How many notifications with this `imethod` arrived since it was last 204 * handled. If `count` > 1, `calldata` only holds the data for the most 205 * recent such notification, all the older data being lost. 206 * 207 * `async_spawn_notification_handler()` can be used to increase the 208 * number of notifications that can be processed simultaneously, 209 * reducing the likelihood of losing them when the handler blocks. 210 */ 211 long count; 203 /** List of arrived notifications. */ 204 list_t msg_list; 212 205 } notification_t; 213 206 … … 249 242 static LIST_INITIALIZE(notification_queue); 250 243 static FIBRIL_SEMAPHORE_INITIALIZE(notification_semaphore, 0); 244 245 static LIST_INITIALIZE(notification_freelist); 246 static long notification_freelist_total = 0; 247 static long notification_freelist_used = 0; 251 248 252 249 static sysarg_t notification_avail = 0; … … 412 409 client_t *client = async_client_get(fibril_connection->in_task_id, true); 413 410 if (!client) { 414 ipc_answer_0(fibril_connection->c handle, ENOMEM);411 ipc_answer_0(fibril_connection->call.cap_handle, ENOMEM); 415 412 return 0; 416 413 } … … 421 418 * Call the connection handler function. 422 419 */ 423 fibril_connection->handler(fibril_connection->c handle,420 fibril_connection->handler(fibril_connection->call.cap_handle, 424 421 &fibril_connection->call, fibril_connection->data); 425 422 … … 448 445 449 446 list_remove(&msg->link); 450 ipc_answer_0(msg->c handle, EHANGUP);447 ipc_answer_0(msg->call.cap_handle, EHANGUP); 451 448 free(msg); 452 449 } … … 471 468 * @param in_task_id Identification of the incoming connection. 472 469 * @param in_phone_hash Identification of the incoming connection. 473 * @param chandle Handle of the opening IPC_M_CONNECT_ME_TO call. 474 * If chandle is CAP_NIL, the connection was opened by 475 * accepting the IPC_M_CONNECT_TO_ME call and this 476 * function is called directly by the server. 477 * @param call Call data of the opening call. 470 * @param call Call data of the opening call. If call is NULL, 471 * the connection was opened by accepting the 472 * IPC_M_CONNECT_TO_ME call and this function is 473 * called directly by the server. 478 474 * @param handler Connection handler. 479 475 * @param data Client argument to pass to the connection handler. … … 483 479 */ 484 480 static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash, 485 cap_call_handle_t chandle, ipc_call_t *call, async_port_handler_t handler, 486 void *data) 481 ipc_call_t *call, async_port_handler_t handler, void *data) 487 482 { 488 483 connection_t *conn = malloc(sizeof(*conn)); 489 484 if (!conn) { 490 if (c handle != CAP_NIL)491 ipc_answer_0(c handle, ENOMEM);485 if (call) 486 ipc_answer_0(call->cap_handle, ENOMEM); 492 487 493 488 return (uintptr_t) NULL; … … 497 492 conn->in_phone_hash = in_phone_hash; 498 493 list_initialize(&conn->msg_queue); 499 conn->chandle = chandle;500 494 conn->close_chandle = CAP_NIL; 501 495 conn->handler = handler; … … 504 498 if (call) 505 499 conn->call = *call; 500 else 501 conn->call.cap_handle = CAP_NIL; 506 502 507 503 /* We will activate the fibril ASAP */ … … 512 508 free(conn); 513 509 514 if (c handle != CAP_NIL)515 ipc_answer_0(c handle, ENOMEM);510 if (call) 511 ipc_answer_0(call->cap_handle, ENOMEM); 516 512 517 513 return (uintptr_t) NULL; … … 568 564 sysarg_t phone_hash = IPC_GET_ARG5(answer); 569 565 fid_t fid = async_new_connection(answer.in_task_id, phone_hash, 570 CAP_NIL,NULL, handler, data);566 NULL, handler, data); 571 567 if (fid == (uintptr_t) NULL) 572 568 return ENOMEM; … … 637 633 * timeouts are unregistered. 638 634 * 639 * @param chandle Handle of the incoming call. 640 * @param call Data of the incoming call. 635 * @param call Data of the incoming call. 641 636 * 642 637 * @return False if the call doesn't match any connection. … … 644 639 * 645 640 */ 646 static bool route_call( cap_call_handle_t chandle,ipc_call_t *call)641 static bool route_call(ipc_call_t *call) 647 642 { 648 643 assert(call); … … 667 662 } 668 663 669 msg->chandle = chandle;670 664 msg->call = *call; 671 665 list_append(&msg->link, &conn->msg_queue); 672 666 673 667 if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP) 674 conn->close_chandle = c handle;668 conn->close_chandle = call->cap_handle; 675 669 676 670 /* If the connection fibril is waiting for an event, activate it */ … … 709 703 notification_t *notification = list_get_instance( 710 704 list_first(¬ification_queue), notification_t, qlink); 711 list_remove(¬ification->qlink);712 705 713 706 async_notification_handler_t handler = notification->handler; 714 707 void *arg = notification->arg; 715 ipc_call_t calldata = notification->calldata; 716 long count = notification->count; 717 718 notification->count = 0; 708 709 notification_msg_t *m = list_pop(¬ification->msg_list, 710 notification_msg_t, link); 711 assert(m); 712 ipc_call_t calldata = m->calldata; 713 714 notification_freelist_used--; 715 716 if (notification_freelist_total > 64 && 717 notification_freelist_total > 2 * notification_freelist_used) { 718 /* Going to free the structure if we have too much. */ 719 notification_freelist_total--; 720 } else { 721 /* Otherwise add to freelist. */ 722 list_append(&m->link, ¬ification_freelist); 723 m = NULL; 724 } 725 726 if (list_empty(¬ification->msg_list)) 727 list_remove(¬ification->qlink); 719 728 720 729 futex_unlock(¬ification_futex); 721 722 // FIXME: Pass count to the handler. It might be important.723 (void) count;724 730 725 731 if (handler) 726 732 handler(&calldata, arg); 733 734 free(m); 727 735 } 728 736 … … 760 768 futex_lock(¬ification_futex); 761 769 770 notification_msg_t *m = list_pop(¬ification_freelist, 771 notification_msg_t, link); 772 773 if (!m) { 774 futex_unlock(¬ification_futex); 775 m = malloc(sizeof(notification_msg_t)); 776 if (!m) { 777 DPRINTF("Out of memory.\n"); 778 abort(); 779 } 780 781 futex_lock(¬ification_futex); 782 notification_freelist_total++; 783 } 784 762 785 ht_link_t *link = hash_table_find(¬ification_hash_table, 763 786 &IPC_GET_IMETHOD(*call)); … … 765 788 /* Invalid notification. */ 766 789 // TODO: Make sure this can't happen and turn it into assert. 790 notification_freelist_total--; 767 791 futex_unlock(¬ification_futex); 792 free(m); 768 793 return; 769 794 } … … 772 797 hash_table_get_inst(link, notification_t, htlink); 773 798 774 notification->count++; 775 notification->calldata = *call; 776 777 if (link_in_use(¬ification->qlink)) { 778 /* Notification already queued. */ 779 futex_unlock(¬ification_futex); 780 return; 781 } 782 783 list_append(¬ification->qlink, ¬ification_queue); 799 notification_freelist_used++; 800 m->calldata = *call; 801 list_append(&m->link, ¬ification->msg_list); 802 803 if (!link_in_use(¬ification->qlink)) 804 list_append(¬ification->qlink, ¬ification_queue); 805 784 806 futex_unlock(¬ification_futex); 785 807 … … 802 824 notification->handler = handler; 803 825 notification->arg = arg; 826 827 list_initialize(¬ification->msg_list); 804 828 805 829 fid_t fib = 0; … … 1011 1035 list_remove(&msg->link); 1012 1036 1013 cap_call_handle_t chandle = msg->c handle;1037 cap_call_handle_t chandle = msg->call.cap_handle; 1014 1038 *call = msg->call; 1015 1039 free(msg); … … 1058 1082 * Otherwise the call is routed to its connection fibril. 1059 1083 * 1060 * @param chandle Handle of the incoming call. 1061 * @param call Data of the incoming call. 1062 * 1063 */ 1064 static void handle_call(cap_call_handle_t chandle, ipc_call_t *call) 1084 * @param call Data of the incoming call. 1085 * 1086 */ 1087 static void handle_call(ipc_call_t *call) 1065 1088 { 1066 1089 assert(call); … … 1069 1092 return; 1070 1093 1071 if (c handle == CAP_NIL) {1094 if (call->cap_handle == CAP_NIL) { 1072 1095 if (call->flags & IPC_CALL_NOTIF) { 1073 1096 /* Kernel notification */ … … 1087 1110 async_get_port_handler(iface, 0, &data); 1088 1111 1089 async_new_connection(call->in_task_id, in_phone_hash, c handle,1090 call,handler, data);1112 async_new_connection(call->in_task_id, in_phone_hash, call, 1113 handler, data); 1091 1114 return; 1092 1115 } 1093 1116 1094 1117 /* Try to route the call through the connection hash table */ 1095 if (route_call(c handle, call))1118 if (route_call(call)) 1096 1119 return; 1097 1120 1098 1121 /* Unknown call from unknown phone - hang it up */ 1099 ipc_answer_0(c handle, EHANGUP);1122 ipc_answer_0(call->cap_handle, EHANGUP); 1100 1123 } 1101 1124 … … 1178 1201 1179 1202 assert(rc == EOK); 1180 handle_call( call.cap_handle,&call);1203 handle_call(&call); 1181 1204 } 1182 1205 … … 1847 1870 } 1848 1871 1849 _ Noreturn void async_manager(void)1872 __noreturn void async_manager(void) 1850 1873 { 1851 1874 futex_lock(&async_futex);
Note:
See TracChangeset
for help on using the changeset viewer.