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