Changeset f5837524 in mainline for uspace/lib/c/generic/async/server.c


Ignore:
Timestamp:
2018-10-29T17:15:02Z (6 years ago)
Author:
Jakub Jermar <jakub@…>
Children:
eec201d
Parents:
184f2f8a
git-author:
Jakub Jermar <jakub@…> (2018-10-28 12:42:35)
git-committer:
Jakub Jermar <jakub@…> (2018-10-29 17:15:02)
Message:

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

File:
1 edited

Legend:

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

    r184f2f8a rf5837524  
    144144        task_id_t in_task_id;
    145145
    146         /** Incoming phone hash. */
    147         sysarg_t in_phone_hash;
    148 
    149146        /** Link to the client tracking structure. */
    150147        client_t *client;
     
    234231static sysarg_t notification_avail = 0;
    235232
    236 static FIBRIL_RMUTEX_INITIALIZE(conn_mutex);
    237 static hash_table_t conn_hash_table;
    238 
    239233static size_t client_key_hash(void *key)
    240234{
     
    261255        .key_hash = client_key_hash,
    262256        .key_equal = client_key_equal,
    263         .equal = NULL,
    264         .remove_callback = NULL
    265 };
    266 
    267 typedef struct {
    268         task_id_t task_id;
    269         sysarg_t phone_hash;
    270 } conn_key_t;
    271 
    272 /** Compute hash into the connection hash table
    273  *
    274  * The hash is based on the source task ID and the source phone hash. The task
    275  * ID is included in the hash because a phone hash alone might not be unique
    276  * while we still track connections for killed tasks due to kernel's recycling
    277  * of phone structures.
    278  *
    279  * @param key Pointer to the connection key structure.
    280  *
    281  * @return Index into the connection hash table.
    282  *
    283  */
    284 static size_t conn_key_hash(void *key)
    285 {
    286         conn_key_t *ck = (conn_key_t *) key;
    287 
    288         size_t hash = 0;
    289         hash = hash_combine(hash, LOWER32(ck->task_id));
    290         hash = hash_combine(hash, UPPER32(ck->task_id));
    291         hash = hash_combine(hash, ck->phone_hash);
    292         return hash;
    293 }
    294 
    295 static size_t conn_hash(const ht_link_t *item)
    296 {
    297         connection_t *conn = hash_table_get_inst(item, connection_t, link);
    298         return conn_key_hash(&(conn_key_t){
    299                 .task_id = conn->in_task_id,
    300                 .phone_hash = conn->in_phone_hash
    301         });
    302 }
    303 
    304 static bool conn_key_equal(void *key, const ht_link_t *item)
    305 {
    306         conn_key_t *ck = (conn_key_t *) key;
    307         connection_t *conn = hash_table_get_inst(item, connection_t, link);
    308         return ((ck->task_id == conn->in_task_id) &&
    309             (ck->phone_hash == conn->in_phone_hash));
    310 }
    311 
    312 /** Operations for the connection hash table. */
    313 static hash_table_ops_t conn_hash_table_ops = {
    314         .hash = conn_hash,
    315         .key_hash = conn_key_hash,
    316         .key_equal = conn_key_equal,
    317257        .equal = NULL,
    318258        .remove_callback = NULL
     
    386326        fibril_connection = (connection_t *) arg;
    387327
     328        mpsc_t *c = fibril_connection->msg_channel;
     329
    388330        /*
    389331         * Add our reference for the current connection in the client task
     
    395337        if (!client) {
    396338                ipc_answer_0(fibril_connection->call.cap_handle, ENOMEM);
    397                 return 0;
     339                goto out;
    398340        }
    399341
     
    411353        async_client_put(client);
    412354
    413         fibril_rmutex_lock(&conn_mutex);
    414 
    415         /*
    416          * Remove myself from the connection hash table.
    417          */
    418         hash_table_remove(&conn_hash_table, &(conn_key_t){
    419                 .task_id = fibril_connection->in_task_id,
    420                 .phone_hash = fibril_connection->in_phone_hash
    421         });
    422 
    423355        /*
    424356         * Close the channel, if it isn't closed already.
    425357         */
    426         mpsc_t *c = fibril_connection->msg_channel;
    427358        mpsc_close(c);
    428 
    429         fibril_rmutex_unlock(&conn_mutex);
    430359
    431360        /*
     
    439368         * Clean up memory.
    440369         */
     370out:
    441371        mpsc_destroy(c);
    442372        free(fibril_connection);
     
    444374}
    445375
     376/** Return label usable during replies to IPC_M_CONNECT_ME_TO. */
     377sysarg_t async_get_label(void)
     378{
     379   return (sysarg_t) fibril_connection;
     380}
     381
    446382/** Create a new fibril for a new connection.
    447383 *
     
    450386 * particular fibrils.
    451387 *
    452  * @param in_task_id     Identification of the incoming connection.
    453  * @param in_phone_hash  Identification of the incoming connection.
    454  * @param call           Call data of the opening call. If call is NULL,
    455  *                       the connection was opened by accepting the
    456  *                       IPC_M_CONNECT_TO_ME call and this function is
    457  *                       called directly by the server.
    458  * @param handler        Connection handler.
    459  * @param data           Client argument to pass to the connection handler.
     388 * @param conn        Pointer to the connection structure. Will be used as the
     389 *                    label of the connected phone and request_label of incoming
     390 *                    calls routed through that phone.
     391 * @param in_task_id  Identification of the incoming connection.
     392 * @param call        Call data of the opening call. If call is NULL, the
     393 *                    connection was opened by accepting the
     394 *                    IPC_M_CONNECT_TO_ME call and this function is called
     395 *                    directly by the server.
     396 * @param handler     Connection handler.
     397 * @param data        Client argument to pass to the connection handler.
    460398 *
    461399 * @return  New fibril id or NULL on failure.
    462400 *
    463401 */
    464 static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
     402static fid_t async_new_connection(connection_t *conn, task_id_t in_task_id,
    465403    ipc_call_t *call, async_port_handler_t handler, void *data)
    466404{
    467         connection_t *conn = malloc(sizeof(*conn));
    468         if (!conn) {
    469                 if (call)
    470                         ipc_answer_0(call->cap_handle, ENOMEM);
    471 
    472                 return (fid_t) NULL;
    473         }
    474 
    475405        conn->in_task_id = in_task_id;
    476         conn->in_phone_hash = in_phone_hash;
    477406        conn->msg_channel = mpsc_create(sizeof(ipc_call_t));
    478407        conn->handler = handler;
    479408        conn->data = data;
     409
     410        if (!conn->msg_channel)
     411                goto error;
    480412
    481413        if (call)
     
    487419        conn->fid = fibril_create(connection_fibril, conn);
    488420
    489         if (conn->fid == 0) {
     421        if (conn->fid == 0)
     422                goto error;
     423
     424        fibril_start(conn->fid);
     425
     426        return conn->fid;
     427
     428error:
     429        if (conn->msg_channel)
    490430                mpsc_destroy(conn->msg_channel);
    491                 free(conn);
    492 
    493                 if (call)
    494                         ipc_answer_0(call->cap_handle, ENOMEM);
    495 
    496                 return (fid_t) NULL;
    497         }
    498 
    499         /* Add connection to the connection hash table */
    500 
    501         fibril_rmutex_lock(&conn_mutex);
    502         hash_table_insert(&conn_hash_table, &conn->link);
    503         fibril_rmutex_unlock(&conn_mutex);
    504 
    505         fibril_start(conn->fid);
    506 
    507         return conn->fid;
     431        free(conn);
     432
     433        if (call)
     434                ipc_answer_0(call->cap_handle, ENOMEM);
     435
     436        return (fid_t) NULL;
    508437}
    509438
     
    532461                return ENOENT;
    533462
     463        connection_t *conn = calloc(1, sizeof(*conn));
     464        if (!conn)
     465                return ENOMEM;
     466
    534467        ipc_call_t answer;
    535         aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, iface, arg1, arg2,
    536             &answer);
     468        aid_t req = async_send_5(exch, IPC_M_CONNECT_TO_ME, iface, arg1, arg2,
     469            0, (sysarg_t) conn, &answer);
    537470
    538471        errno_t rc;
    539472        async_wait_for(req, &rc);
    540         if (rc != EOK)
     473        if (rc != EOK) {
     474                free(conn);
    541475                return rc;
     476        }
    542477
    543478        rc = async_create_port_internal(iface, handler, data, port_id);
    544         if (rc != EOK)
     479        if (rc != EOK) {
     480                free(conn);
    545481                return rc;
    546 
    547         sysarg_t phone_hash = IPC_GET_ARG5(answer);
    548         fid_t fid = async_new_connection(answer.in_task_id, phone_hash,
    549             NULL, handler, data);
     482        }
     483
     484        fid_t fid = async_new_connection(conn, answer.task_id, NULL, handler,
     485            data);
    550486        if (fid == (fid_t) NULL)
    551487                return ENOMEM;
     
    601537        assert(call);
    602538
    603         fibril_rmutex_lock(&conn_mutex);
    604 
    605         ht_link_t *link = hash_table_find(&conn_hash_table, &(conn_key_t){
    606                 .task_id = call->in_task_id,
    607                 .phone_hash = call->in_phone_hash
    608         });
    609         if (!link) {
    610                 fibril_rmutex_unlock(&conn_mutex);
     539        connection_t *conn = (connection_t *) call->request_label;
     540
     541        if (!conn)
    611542                return ENOENT;
    612         }
    613 
    614         connection_t *conn = hash_table_get_inst(link, connection_t, link);
     543
     544        assert(conn->msg_channel);
    615545
    616546        errno_t rc = mpsc_send(conn->msg_channel, call);
     
    625555        }
    626556
    627         fibril_rmutex_unlock(&conn_mutex);
    628557        return rc;
    629558}
     
    1009938        /* New connection */
    1010939        if (IPC_GET_IMETHOD(*call) == IPC_M_CONNECT_ME_TO) {
     940                connection_t *conn = calloc(1, sizeof(*conn));
     941                if (!conn) {
     942                        ipc_answer_0(call->cap_handle, ENOMEM);
     943                        return;
     944                }
     945
    1011946                iface_t iface = (iface_t) IPC_GET_ARG1(*call);
    1012                 sysarg_t in_phone_hash = IPC_GET_ARG5(*call);
    1013947
    1014948                // TODO: Currently ignores all ports but the first one.
     
    1017951                    async_get_port_handler(iface, 0, &data);
    1018952
    1019                 async_new_connection(call->in_task_id, in_phone_hash, call,
    1020                     handler, data);
     953                async_new_connection(conn, call->task_id, call, handler, data);
    1021954                return;
    1022955        }
    1023956
    1024         /* Try to route the call through the connection hash table */
     957        /* Route the call according to its request label */
    1025958        errno_t rc = route_call(call);
    1026959        if (rc == EOK)
     
    10831016                abort();
    10841017
    1085         if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops))
    1086                 abort();
    1087 
    10881018        if (!hash_table_create(&notification_hash_table, 0, 0,
    10891019            &notification_hash_table_ops))
     
    11711101                return ENOENT;
    11721102
    1173         ipc_call_t answer;
    1174         aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, iface, arg2, arg3,
    1175             &answer);
    1176 
    1177         errno_t rc;
    1178         async_wait_for(req, &rc);
    1179         if (rc != EOK)
    1180                 return (errno_t) rc;
    1181 
    1182         return EOK;
     1103        sysarg_t label = 0;
     1104        errno_t rc = async_req_5_0(exch, IPC_M_CONNECT_TO_ME, iface, arg2, arg3,
     1105            0, label);
     1106
     1107        return rc;
    11831108}
    11841109
Note: See TracChangeset for help on using the changeset viewer.