Ignore:
File:
1 edited

Legend:

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

    r1de92fb0 r8080262  
    124124#define DPRINTF(...)  ((void) 0)
    125125
     126/** Call data */
     127typedef struct {
     128        link_t link;
     129        ipc_call_t call;
     130} msg_t;
     131
    126132/* Client connection data */
    127133typedef struct {
     
    150156        client_t *client;
    151157
    152         /** Channel for messages that should be delivered to this fibril. */
    153         mpsc_t *msg_channel;
     158        /** Message event. */
     159        fibril_event_t msg_arrived;
     160
     161        /** Messages that should be delivered to this fibril. */
     162        list_t msg_queue;
    154163
    155164        /** Call data of the opening call. */
    156165        ipc_call_t call;
     166
     167        /** Identification of the closing call. */
     168        cap_call_handle_t close_chandle;
    157169
    158170        /** Fibril function that will be used to handle the connection. */
     
    411423        async_client_put(client);
    412424
    413         fibril_rmutex_lock(&conn_mutex);
    414 
    415425        /*
    416426         * Remove myself from the connection hash table.
    417427         */
     428        fibril_rmutex_lock(&conn_mutex);
    418429        hash_table_remove(&conn_hash_table, &(conn_key_t){
    419430                .task_id = fibril_connection->in_task_id,
    420431                .phone_hash = fibril_connection->in_phone_hash
    421432        });
    422 
    423         /*
    424          * Close the channel, if it isn't closed already.
    425          */
    426         mpsc_t *c = fibril_connection->msg_channel;
    427         mpsc_close(c);
    428 
    429433        fibril_rmutex_unlock(&conn_mutex);
    430434
     
    432436         * Answer all remaining messages with EHANGUP.
    433437         */
    434         ipc_call_t call;
    435         while (mpsc_receive(c, &call, NULL) == EOK)
    436                 ipc_answer_0(call.cap_handle, EHANGUP);
     438        while (!list_empty(&fibril_connection->msg_queue)) {
     439                msg_t *msg =
     440                    list_get_instance(list_first(&fibril_connection->msg_queue),
     441                    msg_t, link);
     442
     443                list_remove(&msg->link);
     444                ipc_answer_0(msg->call.cap_handle, EHANGUP);
     445                free(msg);
     446        }
    437447
    438448        /*
    439          * Clean up memory.
     449         * If the connection was hung-up, answer the last call,
     450         * i.e. IPC_M_PHONE_HUNGUP.
    440451         */
    441         mpsc_destroy(c);
     452        if (fibril_connection->close_chandle)
     453                ipc_answer_0(fibril_connection->close_chandle, EOK);
     454
    442455        free(fibril_connection);
    443456        return EOK;
     
    475488        conn->in_task_id = in_task_id;
    476489        conn->in_phone_hash = in_phone_hash;
    477         conn->msg_channel = mpsc_create(sizeof(ipc_call_t));
     490        conn->msg_arrived = FIBRIL_EVENT_INIT;
     491        list_initialize(&conn->msg_queue);
     492        conn->close_chandle = CAP_NIL;
    478493        conn->handler = handler;
    479494        conn->data = data;
     
    488503
    489504        if (conn->fid == 0) {
    490                 mpsc_destroy(conn->msg_channel);
    491505                free(conn);
    492506
     
    592606 * @param call Data of the incoming call.
    593607 *
    594  * @return EOK if the call was successfully passed to the respective fibril.
    595  * @return ENOENT if the call doesn't match any connection.
    596  * @return Other error code if routing failed for other reasons.
    597  *
    598  */
    599 static errno_t route_call(ipc_call_t *call)
     608 * @return False if the call doesn't match any connection.
     609 * @return True if the call was passed to the respective connection fibril.
     610 *
     611 */
     612static bool route_call(ipc_call_t *call)
    600613{
    601614        assert(call);
     
    609622        if (!link) {
    610623                fibril_rmutex_unlock(&conn_mutex);
    611                 return ENOENT;
     624                return false;
    612625        }
    613626
    614627        connection_t *conn = hash_table_get_inst(link, connection_t, link);
    615628
    616         errno_t rc = mpsc_send(conn->msg_channel, call);
    617 
    618         if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP) {
    619                 /* Close the channel, but let the connection fibril answer. */
    620                 mpsc_close(conn->msg_channel);
    621                 // FIXME: Ideally, we should be able to discard/answer the
    622                 //        hungup message here and just close the channel without
    623                 //        passing it out. Unfortunatelly, somehow that breaks
    624                 //        handling of CPU exceptions.
    625         }
     629        // FIXME: malloc in critical section
     630        msg_t *msg = malloc(sizeof(*msg));
     631        if (!msg) {
     632                fibril_rmutex_unlock(&conn_mutex);
     633                return false;
     634        }
     635
     636        msg->call = *call;
     637        list_append(&msg->link, &conn->msg_queue);
     638
     639        if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP)
     640                conn->close_chandle = call->cap_handle;
    626641
    627642        fibril_rmutex_unlock(&conn_mutex);
    628         return rc;
     643
     644        /* If the connection fibril is waiting for an event, activate it */
     645        fibril_notify(&conn->msg_arrived);
     646        return true;
    629647}
    630648
     
    921939        assert(fibril_connection);
    922940
     941        /*
     942         * Why doing this?
     943         * GCC 4.1.0 coughs on fibril_connection-> dereference.
     944         * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
     945         *           I would never expect to find so many errors in
     946         *           a compiler.
     947         */
     948        connection_t *conn = fibril_connection;
     949
    923950        struct timeval tv;
    924951        struct timeval *expires = NULL;
     
    929956        }
    930957
    931         errno_t rc = mpsc_receive(fibril_connection->msg_channel,
    932             call, expires);
    933 
    934         if (rc == ETIMEOUT)
    935                 return false;
    936 
    937         if (rc != EOK) {
    938                 /*
    939                  * The async_get_call_timeout() interface doesn't support
    940                  * propagating errors. Return a null call instead.
    941                  */
    942 
    943                 memset(call, 0, sizeof(ipc_call_t));
    944         }
    945 
     958        fibril_rmutex_lock(&conn_mutex);
     959
     960        /* If nothing in queue, wait until something arrives */
     961        while (list_empty(&conn->msg_queue)) {
     962                if (conn->close_chandle) {
     963                        /*
     964                         * Handle the case when the connection was already
     965                         * closed by the client but the server did not notice
     966                         * the first IPC_M_PHONE_HUNGUP call and continues to
     967                         * call async_get_call_timeout(). Repeat
     968                         * IPC_M_PHONE_HUNGUP until the caller notices.
     969                         */
     970                        memset(call, 0, sizeof(ipc_call_t));
     971                        IPC_SET_IMETHOD(*call, IPC_M_PHONE_HUNGUP);
     972                        fibril_rmutex_unlock(&conn_mutex);
     973                        return true;
     974                }
     975
     976                // TODO: replace with cvar
     977                fibril_rmutex_unlock(&conn_mutex);
     978
     979                errno_t rc = fibril_wait_timeout(&conn->msg_arrived, expires);
     980                if (rc == ETIMEOUT)
     981                        return false;
     982
     983                fibril_rmutex_lock(&conn_mutex);
     984        }
     985
     986        msg_t *msg = list_get_instance(list_first(&conn->msg_queue),
     987            msg_t, link);
     988        list_remove(&msg->link);
     989
     990        *call = msg->call;
     991        free(msg);
     992
     993        fibril_rmutex_unlock(&conn_mutex);
    946994        return true;
    947995}
     
    10231071
    10241072        /* Try to route the call through the connection hash table */
    1025         errno_t rc = route_call(call);
    1026         if (rc == EOK)
     1073        if (route_call(call))
    10271074                return;
    10281075
    1029         // TODO: Log the error.
    1030 
    1031         if (call->cap_handle != CAP_NIL)
    1032                 /* Unknown call from unknown phone - hang it up */
    1033                 ipc_answer_0(call->cap_handle, EHANGUP);
     1076        /* Unknown call from unknown phone - hang it up */
     1077        ipc_answer_0(call->cap_handle, EHANGUP);
    10341078}
    10351079
Note: See TracChangeset for help on using the changeset viewer.