Ignore:
File:
1 edited

Legend:

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

    re768aea r061274f  
    122122#include "../private/fibril.h"
    123123
     124#define DPRINTF(...)  ((void) 0)
     125
    124126/** Async framework global futex */
    125127futex_t async_futex = FUTEX_INITIALIZER;
     
    132134        link_t link;
    133135
    134         cap_call_handle_t chandle;
    135136        ipc_call_t call;
    136137} msg_t;
     
    164165        list_t msg_queue;
    165166
    166         /** Identification of the opening call. */
    167         cap_call_handle_t chandle;
    168 
    169167        /** Call data of the opening call. */
    170168        ipc_call_t call;
     
    179177        void *data;
    180178} connection_t;
     179
     180/* Member of notification_t::msg_list. */
     181typedef struct {
     182        link_t link;
     183        ipc_call_t calldata;
     184} notification_msg_t;
    181185
    182186/* Notification data */
     
    197201        void *arg;
    198202
    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;
    212205} notification_t;
    213206
     
    249242static LIST_INITIALIZE(notification_queue);
    250243static FIBRIL_SEMAPHORE_INITIALIZE(notification_semaphore, 0);
     244
     245static LIST_INITIALIZE(notification_freelist);
     246static long notification_freelist_total = 0;
     247static long notification_freelist_used = 0;
    251248
    252249static sysarg_t notification_avail = 0;
     
    412409        client_t *client = async_client_get(fibril_connection->in_task_id, true);
    413410        if (!client) {
    414                 ipc_answer_0(fibril_connection->chandle, ENOMEM);
     411                ipc_answer_0(fibril_connection->call.cap_handle, ENOMEM);
    415412                return 0;
    416413        }
     
    421418         * Call the connection handler function.
    422419         */
    423         fibril_connection->handler(fibril_connection->chandle,
     420        fibril_connection->handler(fibril_connection->call.cap_handle,
    424421            &fibril_connection->call, fibril_connection->data);
    425422
     
    448445
    449446                list_remove(&msg->link);
    450                 ipc_answer_0(msg->chandle, EHANGUP);
     447                ipc_answer_0(msg->call.cap_handle, EHANGUP);
    451448                free(msg);
    452449        }
     
    471468 * @param in_task_id     Identification of the incoming connection.
    472469 * @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.
    478474 * @param handler        Connection handler.
    479475 * @param data           Client argument to pass to the connection handler.
     
    483479 */
    484480static 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)
    487482{
    488483        connection_t *conn = malloc(sizeof(*conn));
    489484        if (!conn) {
    490                 if (chandle != CAP_NIL)
    491                         ipc_answer_0(chandle, ENOMEM);
     485                if (call)
     486                        ipc_answer_0(call->cap_handle, ENOMEM);
    492487
    493488                return (uintptr_t) NULL;
     
    497492        conn->in_phone_hash = in_phone_hash;
    498493        list_initialize(&conn->msg_queue);
    499         conn->chandle = chandle;
    500494        conn->close_chandle = CAP_NIL;
    501495        conn->handler = handler;
     
    504498        if (call)
    505499                conn->call = *call;
     500        else
     501                conn->call.cap_handle = CAP_NIL;
    506502
    507503        /* We will activate the fibril ASAP */
     
    512508                free(conn);
    513509
    514                 if (chandle != CAP_NIL)
    515                         ipc_answer_0(chandle, ENOMEM);
     510                if (call)
     511                        ipc_answer_0(call->cap_handle, ENOMEM);
    516512
    517513                return (uintptr_t) NULL;
     
    568564        sysarg_t phone_hash = IPC_GET_ARG5(answer);
    569565        fid_t fid = async_new_connection(answer.in_task_id, phone_hash,
    570             CAP_NIL, NULL, handler, data);
     566            NULL, handler, data);
    571567        if (fid == (uintptr_t) NULL)
    572568                return ENOMEM;
     
    637633 * timeouts are unregistered.
    638634 *
    639  * @param chandle  Handle of the incoming call.
    640  * @param call     Data of the incoming call.
     635 * @param call Data of the incoming call.
    641636 *
    642637 * @return False if the call doesn't match any connection.
     
    644639 *
    645640 */
    646 static bool route_call(cap_call_handle_t chandle, ipc_call_t *call)
     641static bool route_call(ipc_call_t *call)
    647642{
    648643        assert(call);
     
    667662        }
    668663
    669         msg->chandle = chandle;
    670664        msg->call = *call;
    671665        list_append(&msg->link, &conn->msg_queue);
    672666
    673667        if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP)
    674                 conn->close_chandle = chandle;
     668                conn->close_chandle = call->cap_handle;
    675669
    676670        /* If the connection fibril is waiting for an event, activate it */
     
    709703                notification_t *notification = list_get_instance(
    710704                    list_first(&notification_queue), notification_t, qlink);
    711                 list_remove(&notification->qlink);
    712705
    713706                async_notification_handler_t handler = notification->handler;
    714707                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(&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);
    719728
    720729                futex_unlock(&notification_futex);
    721 
    722                 // FIXME: Pass count to the handler. It might be important.
    723                 (void) count;
    724730
    725731                if (handler)
    726732                        handler(&calldata, arg);
     733
     734                free(m);
    727735        }
    728736
     
    760768        futex_lock(&notification_futex);
    761769
     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
    762785        ht_link_t *link = hash_table_find(&notification_hash_table,
    763786            &IPC_GET_IMETHOD(*call));
     
    765788                /* Invalid notification. */
    766789                // TODO: Make sure this can't happen and turn it into assert.
     790                notification_freelist_total--;
    767791                futex_unlock(&notification_futex);
     792                free(m);
    768793                return;
    769794        }
     
    772797            hash_table_get_inst(link, notification_t, htlink);
    773798
    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);
     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
    784806        futex_unlock(&notification_futex);
    785807
     
    802824        notification->handler = handler;
    803825        notification->arg = arg;
     826
     827        list_initialize(&notification->msg_list);
    804828
    805829        fid_t fib = 0;
     
    10111035        list_remove(&msg->link);
    10121036
    1013         cap_call_handle_t chandle = msg->chandle;
     1037        cap_call_handle_t chandle = msg->call.cap_handle;
    10141038        *call = msg->call;
    10151039        free(msg);
     
    10581082 * Otherwise the call is routed to its connection fibril.
    10591083 *
    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 */
     1087static void handle_call(ipc_call_t *call)
    10651088{
    10661089        assert(call);
     
    10691092                return;
    10701093
    1071         if (chandle == CAP_NIL) {
     1094        if (call->cap_handle == CAP_NIL) {
    10721095                if (call->flags & IPC_CALL_NOTIF) {
    10731096                        /* Kernel notification */
     
    10871110                    async_get_port_handler(iface, 0, &data);
    10881111
    1089                 async_new_connection(call->in_task_id, in_phone_hash, chandle,
    1090                     call, handler, data);
     1112                async_new_connection(call->in_task_id, in_phone_hash, call,
     1113                    handler, data);
    10911114                return;
    10921115        }
    10931116
    10941117        /* Try to route the call through the connection hash table */
    1095         if (route_call(chandle, call))
     1118        if (route_call(call))
    10961119                return;
    10971120
    10981121        /* Unknown call from unknown phone - hang it up */
    1099         ipc_answer_0(chandle, EHANGUP);
     1122        ipc_answer_0(call->cap_handle, EHANGUP);
    11001123}
    11011124
     
    11781201
    11791202                assert(rc == EOK);
    1180                 handle_call(call.cap_handle, &call);
     1203                handle_call(&call);
    11811204        }
    11821205
     
    18471870}
    18481871
    1849 _Noreturn void async_manager(void)
     1872__noreturn void async_manager(void)
    18501873{
    18511874        futex_lock(&async_futex);
Note: See TracChangeset for help on using the changeset viewer.