Ignore:
File:
1 edited

Legend:

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

    r23882034 rc1c0184  
    134134
    135135typedef struct {
    136         sysarg_t in_task_hash;
    137         link_t link;
    138         int refcnt;
    139         void *data;
    140 } client_t;
    141 
    142 typedef struct {
    143136        awaiter_t wdata;
    144137       
     
    146139        link_t link;
    147140       
    148         /** Incoming client task hash. */
    149         sysarg_t in_task_hash;
    150141        /** Incoming phone hash. */
    151142        sysarg_t in_phone_hash;
    152143       
    153         /** Link to the client tracking structure. */
    154         client_t *client;
    155 
    156144        /** Messages that should be delivered to this fibril. */
    157145        link_t msg_queue;
     
    172160fibril_local connection_t *FIBRIL_connection;
    173161
    174 static void *default_client_data_constructor(void)
    175 {
    176         return NULL;
    177 }
    178 
    179 static void default_client_data_destructor(void *data)
    180 {
    181 }
    182 
    183 static async_client_data_ctor_t async_client_data_create =
    184     default_client_data_constructor;
    185 static async_client_data_dtor_t async_client_data_destroy =
    186     default_client_data_destructor;
    187 
    188 void async_set_client_data_constructor(async_client_data_ctor_t ctor)
    189 {
    190         async_client_data_create = ctor;
    191 }
    192 
    193 void async_set_client_data_destructor(async_client_data_dtor_t dtor)
    194 {
    195         async_client_data_destroy = dtor;
    196 }
    197 
    198 void *async_client_data_get(void)
    199 {
    200         assert(FIBRIL_connection);
    201 
    202         return FIBRIL_connection->client->data;
    203 }
    204 
    205162static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
    206163static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
     
    217174static async_client_conn_t interrupt_received = default_interrupt_received;
    218175
    219 static hash_table_t client_hash_table;
    220176static hash_table_t conn_hash_table;
    221177static LIST_INITIALIZE(timeout_list);
    222178
    223 #define CLIENT_HASH_TABLE_BUCKETS       32
    224 #define CONN_HASH_TABLE_BUCKETS         32
    225 
    226 static hash_index_t client_hash(unsigned long *key)
     179#define CONN_HASH_TABLE_CHAINS  32
     180
     181/** Compute hash into the connection hash table based on the source phone hash.
     182 *
     183 * @param key Pointer to source phone hash.
     184 *
     185 * @return Index into the connection hash table.
     186 *
     187 */
     188static hash_index_t conn_hash(unsigned long *key)
    227189{
    228190        assert(key);
    229         return (((*key) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
    230 }
    231 
    232 static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
    233 {
    234         client_t *cl = hash_table_get_instance(item, client_t, link);
    235         return (key[0] == cl->in_task_hash);
    236 }
    237 
    238 static void client_remove(link_t *item)
    239 {
    240 }
    241 
    242 /** Operations for the client hash table. */
    243 static hash_table_operations_t client_hash_table_ops = {
    244         .hash = client_hash,
    245         .compare = client_compare,
    246         .remove_callback = client_remove
    247 };
    248 
    249 /** Compute hash into the connection hash table based on the source phone hash.
    250  *
    251  * @param key Pointer to source phone hash.
    252  *
    253  * @return Index into the connection hash table.
    254  *
    255  */
    256 static hash_index_t conn_hash(unsigned long *key)
    257 {
    258         assert(key);
    259         return (((*key) >> 4) % CONN_HASH_TABLE_BUCKETS);
     191        return (((*key) >> 4) % CONN_HASH_TABLE_CHAINS);
    260192}
    261193
     
    548480static int connection_fibril(void *arg)
    549481{
    550         unsigned long key;
    551         client_t *cl;
    552         link_t *lnk;
    553         bool destroy = false;
    554 
    555482        /*
    556          * Setup fibril-local connection pointer.
     483         * Setup fibril-local connection pointer and call client_connection().
     484         *
    557485         */
    558486        FIBRIL_connection = (connection_t *) arg;
    559 
    560         /*
    561          * Add our reference for the current connection in the client task
    562          * tracking structure. If this is the first reference, create and
    563          * hash in a new tracking structure.
    564          */
    565         futex_down(&async_futex);
    566         key = FIBRIL_connection->in_task_hash;
    567         lnk = hash_table_find(&client_hash_table, &key);
    568         if (lnk) {
    569                 cl = hash_table_get_instance(lnk, client_t, link);
    570                 cl->refcnt++;
    571         } else {
    572                 cl = malloc(sizeof(client_t));
    573                 if (!cl) {
    574                         ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
    575                         futex_up(&async_futex);
    576                         return 0;
    577                 }
    578                 cl->in_task_hash = FIBRIL_connection->in_task_hash;
    579                 async_serialize_start();
    580                 cl->data = async_client_data_create();
    581                 async_serialize_end();
    582                 cl->refcnt = 1;
    583                 hash_table_insert(&client_hash_table, &key, &cl->link);
    584         }
    585         futex_up(&async_futex);
    586 
    587         FIBRIL_connection->client = cl;
    588 
    589         /*
    590          * Call the connection handler function.
    591          */
    592487        FIBRIL_connection->cfibril(FIBRIL_connection->callid,
    593488            &FIBRIL_connection->call);
    594489       
    595         /*
    596          * Remove the reference for this client task connection.
    597          */
     490        /* Remove myself from the connection hash table */
    598491        futex_down(&async_futex);
    599         if (--cl->refcnt == 0) {
    600                 hash_table_remove(&client_hash_table, &key, 1);
    601                 destroy = true;
    602         }
    603         futex_up(&async_futex);
    604 
    605         if (destroy) {
    606                 if (cl->data)
    607                         async_client_data_destroy(cl->data);
    608                 free(cl);
    609         }
    610 
    611         /*
    612          * Remove myself from the connection hash table.
    613          */
    614         futex_down(&async_futex);
    615         key = FIBRIL_connection->in_phone_hash;
     492        unsigned long key = FIBRIL_connection->in_phone_hash;
    616493        hash_table_remove(&conn_hash_table, &key, 1);
    617494        futex_up(&async_futex);
    618495       
    619         /*
    620          * Answer all remaining messages with EHANGUP.
    621          */
     496        /* Answer all remaining messages with EHANGUP */
    622497        while (!list_empty(&FIBRIL_connection->msg_queue)) {
    623498                msg_t *msg;
     
    630505        }
    631506       
    632         /*
    633          * If the connection was hung-up, answer the last call,
    634          * i.e. IPC_M_PHONE_HUNGUP.
    635          */
    636507        if (FIBRIL_connection->close_callid)
    637508                ipc_answer_0(FIBRIL_connection->close_callid, EOK);
     
    646517 * particular fibrils.
    647518 *
    648  * @param in_task_hash  Identification of the incoming connection.
    649519 * @param in_phone_hash Identification of the incoming connection.
    650520 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
     
    659529 *
    660530 */
    661 fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
    662     ipc_callid_t callid, ipc_call_t *call,
    663     void (*cfibril)(ipc_callid_t, ipc_call_t *))
     531fid_t async_new_connection(sysarg_t in_phone_hash, ipc_callid_t callid,
     532    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
    664533{
    665534        connection_t *conn = malloc(sizeof(*conn));
     
    670539        }
    671540       
    672         conn->in_task_hash = in_task_hash;
    673541        conn->in_phone_hash = in_phone_hash;
    674542        list_initialize(&conn->msg_queue);
     
    724592        case IPC_M_CONNECT_ME_TO:
    725593                /* Open new connection with fibril etc. */
    726                 async_new_connection(call->in_task_hash, IPC_GET_ARG5(*call),
    727                     callid, call, client_connection);
     594                async_new_connection(IPC_GET_ARG5(*call), callid, call,
     595                    client_connection);
    728596                goto out;
    729597        }
     
    876744int __async_init(void)
    877745{
    878         if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
    879             &client_hash_table_ops) || !hash_table_create(&conn_hash_table,
    880             CONN_HASH_TABLE_BUCKETS, 1, &conn_hash_table_ops)) {
     746        if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_CHAINS, 1,
     747            &conn_hash_table_ops)) {
     748                printf("%s: Cannot create async hash table\n", "libc");
    881749                return ENOMEM;
    882750        }
Note: See TracChangeset for help on using the changeset viewer.