Changeset 1de92fb0 in mainline


Ignore:
Timestamp:
2018-08-01T18:15:53Z (6 years ago)
Author:
Jiří Zárevúcky <jiri.zarevucky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f787c8e
Parents:
6340b4d2
git-author:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-07-31 22:01:34)
git-committer:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-08-01 18:15:53)
Message:

Implement MPSC FIFO channel and use it to pass inbound IPC calls to the connection fibril.

Technically, a SPSC channel would be sufficient for this, and might be added
in the future but MPSC is more widely useful.

Location:
uspace/lib/c
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/Makefile

    r6340b4d2 r1de92fb0  
    143143        generic/thread/futex.c \
    144144        generic/thread/rcu.c \
     145        generic/thread/mpsc.c \
    145146        generic/sysinfo.c \
    146147        generic/ipc.c \
  • uspace/lib/c/generic/async/server.c

    r6340b4d2 r1de92fb0  
    124124#define DPRINTF(...)  ((void) 0)
    125125
    126 /** Call data */
    127 typedef struct {
    128         link_t link;
    129         ipc_call_t call;
    130 } msg_t;
    131 
    132126/* Client connection data */
    133127typedef struct {
     
    156150        client_t *client;
    157151
    158         /** Message event. */
    159         fibril_event_t msg_arrived;
    160 
    161         /** Messages that should be delivered to this fibril. */
    162         list_t msg_queue;
     152        /** Channel for messages that should be delivered to this fibril. */
     153        mpsc_t *msg_channel;
    163154
    164155        /** Call data of the opening call. */
    165156        ipc_call_t call;
    166 
    167         /** Identification of the closing call. */
    168         cap_call_handle_t close_chandle;
    169157
    170158        /** Fibril function that will be used to handle the connection. */
     
    423411        async_client_put(client);
    424412
     413        fibril_rmutex_lock(&conn_mutex);
     414
    425415        /*
    426416         * Remove myself from the connection hash table.
    427417         */
    428         fibril_rmutex_lock(&conn_mutex);
    429418        hash_table_remove(&conn_hash_table, &(conn_key_t){
    430419                .task_id = fibril_connection->in_task_id,
    431420                .phone_hash = fibril_connection->in_phone_hash
    432421        });
     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
    433429        fibril_rmutex_unlock(&conn_mutex);
    434430
     
    436432         * Answer all remaining messages with EHANGUP.
    437433         */
    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         }
     434        ipc_call_t call;
     435        while (mpsc_receive(c, &call, NULL) == EOK)
     436                ipc_answer_0(call.cap_handle, EHANGUP);
    447437
    448438        /*
    449          * If the connection was hung-up, answer the last call,
    450          * i.e. IPC_M_PHONE_HUNGUP.
     439         * Clean up memory.
    451440         */
    452         if (fibril_connection->close_chandle)
    453                 ipc_answer_0(fibril_connection->close_chandle, EOK);
    454 
     441        mpsc_destroy(c);
    455442        free(fibril_connection);
    456443        return EOK;
     
    488475        conn->in_task_id = in_task_id;
    489476        conn->in_phone_hash = in_phone_hash;
    490         conn->msg_arrived = FIBRIL_EVENT_INIT;
    491         list_initialize(&conn->msg_queue);
    492         conn->close_chandle = CAP_NIL;
     477        conn->msg_channel = mpsc_create(sizeof(ipc_call_t));
    493478        conn->handler = handler;
    494479        conn->data = data;
     
    503488
    504489        if (conn->fid == 0) {
     490                mpsc_destroy(conn->msg_channel);
    505491                free(conn);
    506492
     
    606592 * @param call Data of the incoming call.
    607593 *
    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  */
    612 static bool route_call(ipc_call_t *call)
     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 */
     599static errno_t route_call(ipc_call_t *call)
    613600{
    614601        assert(call);
     
    622609        if (!link) {
    623610                fibril_rmutex_unlock(&conn_mutex);
    624                 return false;
     611                return ENOENT;
    625612        }
    626613
    627614        connection_t *conn = hash_table_get_inst(link, connection_t, link);
    628615
    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;
     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        }
    641626
    642627        fibril_rmutex_unlock(&conn_mutex);
    643 
    644         /* If the connection fibril is waiting for an event, activate it */
    645         fibril_notify(&conn->msg_arrived);
    646         return true;
     628        return rc;
    647629}
    648630
     
    939921        assert(fibril_connection);
    940922
    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 
    950923        struct timeval tv;
    951924        struct timeval *expires = NULL;
     
    956929        }
    957930
    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);
     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
    994946        return true;
    995947}
     
    10711023
    10721024        /* Try to route the call through the connection hash table */
    1073         if (route_call(call))
     1025        errno_t rc = route_call(call);
     1026        if (rc == EOK)
    10741027                return;
    10751028
    1076         /* Unknown call from unknown phone - hang it up */
    1077         ipc_answer_0(call->cap_handle, EHANGUP);
     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);
    10781034}
    10791035
  • uspace/lib/c/generic/thread/atomic.c

    r6340b4d2 r1de92fb0  
    3636 */
    3737
     38void __sync_synchronize(void)
     39{
     40        // FIXME: Full memory barrier. We need a syscall for this.
     41        // Should we implement this or is empty definition ok here?
     42}
     43
    3844unsigned __sync_add_and_fetch_4(volatile void *vptr, unsigned val)
    3945{
  • uspace/lib/c/generic/thread/fibril.c

    r6340b4d2 r1de92fb0  
    723723}
    724724
     725/**
     726 * Wake up the fibril waiting for the given event.
     727 * Up to one wakeup is remembered if the fibril is not currently waiting.
     728 *
     729 * This function is safe for use under restricted mutex lock.
     730 */
    725731void fibril_notify(fibril_event_t *event)
    726732{
  • uspace/lib/c/include/fibril_synch.h

    r6340b4d2 r1de92fb0  
    5050 *         - may not use any other synchronization primitive,
    5151 *           save for another `fibril_rmutex_t`. This includes nonblocking
    52  *           operations like cvar signal and mutex unlock.
     52 *           operations like cvar signal and mutex unlock, unless otherwise
     53 *           specified.
    5354 *         - may not read IPC messages
    5455 *         - may not start a new thread/fibril
     
    245246extern void fibril_semaphore_close(fibril_semaphore_t *);
    246247
     248typedef struct mpsc mpsc_t;
     249extern mpsc_t *mpsc_create(size_t);
     250extern void mpsc_destroy(mpsc_t *);
     251extern errno_t mpsc_send(mpsc_t *, const void *);
     252extern errno_t mpsc_receive(mpsc_t *, void *, const struct timeval *);
     253extern void mpsc_close(mpsc_t *);
     254
    247255#endif
    248256
Note: See TracChangeset for help on using the changeset viewer.