Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/async/server.c

    r061274f re768aea  
    122122#include "../private/fibril.h"
    123123
    124 #define DPRINTF(...)  ((void) 0)
    125 
    126124/** Async framework global futex */
    127125futex_t async_futex = FUTEX_INITIALIZER;
     
    134132        link_t link;
    135133
     134        cap_call_handle_t chandle;
    136135        ipc_call_t call;
    137136} msg_t;
     
    165164        list_t msg_queue;
    166165
     166        /** Identification of the opening call. */
     167        cap_call_handle_t chandle;
     168
    167169        /** Call data of the opening call. */
    168170        ipc_call_t call;
     
    177179        void *data;
    178180} 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;
    185181
    186182/* Notification data */
     
    201197        void *arg;
    202198
    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;
    205212} notification_t;
    206213
     
    242249static LIST_INITIALIZE(notification_queue);
    243250static 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;
    248251
    249252static sysarg_t notification_avail = 0;
     
    409412        client_t *client = async_client_get(fibril_connection->in_task_id, true);
    410413        if (!client) {
    411                 ipc_answer_0(fibril_connection->call.cap_handle, ENOMEM);
     414                ipc_answer_0(fibril_connection->chandle, ENOMEM);
    412415                return 0;
    413416        }
     
    418421         * Call the connection handler function.
    419422         */
    420         fibril_connection->handler(fibril_connection->call.cap_handle,
     423        fibril_connection->handler(fibril_connection->chandle,
    421424            &fibril_connection->call, fibril_connection->data);
    422425
     
    445448
    446449                list_remove(&msg->link);
    447                 ipc_answer_0(msg->call.cap_handle, EHANGUP);
     450                ipc_answer_0(msg->chandle, EHANGUP);
    448451                free(msg);
    449452        }
     
    468471 * @param in_task_id     Identification of the incoming connection.
    469472 * @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.
    474478 * @param handler        Connection handler.
    475479 * @param data           Client argument to pass to the connection handler.
     
    479483 */
    480484static 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)
    482487{
    483488        connection_t *conn = malloc(sizeof(*conn));
    484489        if (!conn) {
    485                 if (call)
    486                         ipc_answer_0(call->cap_handle, ENOMEM);
     490                if (chandle != CAP_NIL)
     491                        ipc_answer_0(chandle, ENOMEM);
    487492
    488493                return (uintptr_t) NULL;
     
    492497        conn->in_phone_hash = in_phone_hash;
    493498        list_initialize(&conn->msg_queue);
     499        conn->chandle = chandle;
    494500        conn->close_chandle = CAP_NIL;
    495501        conn->handler = handler;
     
    498504        if (call)
    499505                conn->call = *call;
    500         else
    501                 conn->call.cap_handle = CAP_NIL;
    502506
    503507        /* We will activate the fibril ASAP */
     
    508512                free(conn);
    509513
    510                 if (call)
    511                         ipc_answer_0(call->cap_handle, ENOMEM);
     514                if (chandle != CAP_NIL)
     515                        ipc_answer_0(chandle, ENOMEM);
    512516
    513517                return (uintptr_t) NULL;
     
    564568        sysarg_t phone_hash = IPC_GET_ARG5(answer);
    565569        fid_t fid = async_new_connection(answer.in_task_id, phone_hash,
    566             NULL, handler, data);
     570            CAP_NIL, NULL, handler, data);
    567571        if (fid == (uintptr_t) NULL)
    568572                return ENOMEM;
     
    633637 * timeouts are unregistered.
    634638 *
    635  * @param call Data of the incoming call.
     639 * @param chandle  Handle of the incoming call.
     640 * @param call     Data of the incoming call.
    636641 *
    637642 * @return False if the call doesn't match any connection.
     
    639644 *
    640645 */
    641 static bool route_call(ipc_call_t *call)
     646static bool route_call(cap_call_handle_t chandle, ipc_call_t *call)
    642647{
    643648        assert(call);
     
    662667        }
    663668
     669        msg->chandle = chandle;
    664670        msg->call = *call;
    665671        list_append(&msg->link, &conn->msg_queue);
    666672
    667673        if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP)
    668                 conn->close_chandle = call->cap_handle;
     674                conn->close_chandle = chandle;
    669675
    670676        /* If the connection fibril is waiting for an event, activate it */
     
    703709                notification_t *notification = list_get_instance(
    704710                    list_first(&notification_queue), notification_t, qlink);
     711                list_remove(&notification->qlink);
    705712
    706713                async_notification_handler_t handler = notification->handler;
    707714                void *arg = notification->arg;
    708 
    709                 notification_msg_t *m = list_pop(&notification->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, &notification_freelist);
    723                         m = NULL;
    724                 }
    725 
    726                 if (list_empty(&notification->msg_list))
    727                         list_remove(&notification->qlink);
     715                ipc_call_t calldata = notification->calldata;
     716                long count = notification->count;
     717
     718                notification->count = 0;
    728719
    729720                futex_unlock(&notification_futex);
     721
     722                // FIXME: Pass count to the handler. It might be important.
     723                (void) count;
    730724
    731725                if (handler)
    732726                        handler(&calldata, arg);
    733 
    734                 free(m);
    735727        }
    736728
     
    768760        futex_lock(&notification_futex);
    769761
    770         notification_msg_t *m = list_pop(&notification_freelist,
    771             notification_msg_t, link);
    772 
    773         if (!m) {
    774                 futex_unlock(&notification_futex);
    775                 m = malloc(sizeof(notification_msg_t));
    776                 if (!m) {
    777                         DPRINTF("Out of memory.\n");
    778                         abort();
    779                 }
    780 
    781                 futex_lock(&notification_futex);
    782                 notification_freelist_total++;
    783         }
    784 
    785762        ht_link_t *link = hash_table_find(&notification_hash_table,
    786763            &IPC_GET_IMETHOD(*call));
     
    788765                /* Invalid notification. */
    789766                // TODO: Make sure this can't happen and turn it into assert.
    790                 notification_freelist_total--;
    791767                futex_unlock(&notification_futex);
    792                 free(m);
    793768                return;
    794769        }
     
    797772            hash_table_get_inst(link, notification_t, htlink);
    798773
    799         notification_freelist_used++;
    800         m->calldata = *call;
    801         list_append(&m->link, &notification->msg_list);
    802 
    803         if (!link_in_use(&notification->qlink))
    804                 list_append(&notification->qlink, &notification_queue);
    805 
     774        notification->count++;
     775        notification->calldata = *call;
     776
     777        if (link_in_use(&notification->qlink)) {
     778                /* Notification already queued. */
     779                futex_unlock(&notification_futex);
     780                return;
     781        }
     782
     783        list_append(&notification->qlink, &notification_queue);
    806784        futex_unlock(&notification_futex);
    807785
     
    824802        notification->handler = handler;
    825803        notification->arg = arg;
    826 
    827         list_initialize(&notification->msg_list);
    828804
    829805        fid_t fib = 0;
     
    10351011        list_remove(&msg->link);
    10361012
    1037         cap_call_handle_t chandle = msg->call.cap_handle;
     1013        cap_call_handle_t chandle = msg->chandle;
    10381014        *call = msg->call;
    10391015        free(msg);
     
    10821058 * Otherwise the call is routed to its connection fibril.
    10831059 *
    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 */
     1064static void handle_call(cap_call_handle_t chandle, ipc_call_t *call)
    10881065{
    10891066        assert(call);
     
    10921069                return;
    10931070
    1094         if (call->cap_handle == CAP_NIL) {
     1071        if (chandle == CAP_NIL) {
    10951072                if (call->flags & IPC_CALL_NOTIF) {
    10961073                        /* Kernel notification */
     
    11101087                    async_get_port_handler(iface, 0, &data);
    11111088
    1112                 async_new_connection(call->in_task_id, in_phone_hash, call,
    1113                     handler, data);
     1089                async_new_connection(call->in_task_id, in_phone_hash, chandle,
     1090                    call, handler, data);
    11141091                return;
    11151092        }
    11161093
    11171094        /* Try to route the call through the connection hash table */
    1118         if (route_call(call))
     1095        if (route_call(chandle, call))
    11191096                return;
    11201097
    11211098        /* Unknown call from unknown phone - hang it up */
    1122         ipc_answer_0(call->cap_handle, EHANGUP);
     1099        ipc_answer_0(chandle, EHANGUP);
    11231100}
    11241101
     
    12011178
    12021179                assert(rc == EOK);
    1203                 handle_call(&call);
     1180                handle_call(call.cap_handle, &call);
    12041181        }
    12051182
     
    18701847}
    18711848
    1872 __noreturn void async_manager(void)
     1849_Noreturn void async_manager(void)
    18731850{
    18741851        futex_lock(&async_futex);
Note: See TracChangeset for help on using the changeset viewer.