Changeset 9ef495f in mainline for uspace/lib/c/generic/async.c


Ignore:
Timestamp:
2015-08-23T13:31:31Z (9 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
616f5dd3
Parents:
f9b2cb4c
Message:

make async_new_connection() static

File:
1 edited

Legend:

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

    rf9b2cb4c r9ef495f  
    630630        .remove_callback = NULL
    631631};
     632
     633static client_t *async_client_get(task_id_t client_id, bool create)
     634{
     635        client_t *client = NULL;
     636       
     637        futex_down(&async_futex);
     638        ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
     639        if (link) {
     640                client = hash_table_get_inst(link, client_t, link);
     641                atomic_inc(&client->refcnt);
     642        } else if (create) {
     643                client = malloc(sizeof(client_t));
     644                if (client) {
     645                        client->in_task_id = client_id;
     646                        client->data = async_client_data_create();
     647                       
     648                        atomic_set(&client->refcnt, 1);
     649                        hash_table_insert(&client_hash_table, &client->link);
     650                }
     651        }
     652       
     653        futex_up(&async_futex);
     654        return client;
     655}
     656
     657static void async_client_put(client_t *client)
     658{
     659        bool destroy;
     660       
     661        futex_down(&async_futex);
     662       
     663        if (atomic_predec(&client->refcnt) == 0) {
     664                hash_table_remove(&client_hash_table, &client->in_task_id);
     665                destroy = true;
     666        } else
     667                destroy = false;
     668       
     669        futex_up(&async_futex);
     670       
     671        if (destroy) {
     672                if (client->data)
     673                        async_client_data_destroy(client->data);
     674               
     675                free(client);
     676        }
     677}
     678
     679/** Wrapper for client connection fibril.
     680 *
     681 * When a new connection arrives, a fibril with this implementing
     682 * function is created.
     683 *
     684 * @param arg Connection structure pointer.
     685 *
     686 * @return Always zero.
     687 *
     688 */
     689static int connection_fibril(void *arg)
     690{
     691        assert(arg);
     692       
     693        /*
     694         * Setup fibril-local connection pointer.
     695         */
     696        fibril_connection = (connection_t *) arg;
     697       
     698        /*
     699         * Add our reference for the current connection in the client task
     700         * tracking structure. If this is the first reference, create and
     701         * hash in a new tracking structure.
     702         */
     703       
     704        client_t *client = async_client_get(fibril_connection->in_task_id, true);
     705        if (!client) {
     706                ipc_answer_0(fibril_connection->callid, ENOMEM);
     707                return 0;
     708        }
     709       
     710        fibril_connection->client = client;
     711       
     712        /*
     713         * Call the connection handler function.
     714         */
     715        fibril_connection->handler(fibril_connection->callid,
     716            &fibril_connection->call, fibril_connection->data);
     717       
     718        /*
     719         * Remove the reference for this client task connection.
     720         */
     721        async_client_put(client);
     722       
     723        /*
     724         * Remove myself from the connection hash table.
     725         */
     726        futex_down(&async_futex);
     727        hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
     728        futex_up(&async_futex);
     729       
     730        /*
     731         * Answer all remaining messages with EHANGUP.
     732         */
     733        while (!list_empty(&fibril_connection->msg_queue)) {
     734                msg_t *msg =
     735                    list_get_instance(list_first(&fibril_connection->msg_queue),
     736                    msg_t, link);
     737               
     738                list_remove(&msg->link);
     739                ipc_answer_0(msg->callid, EHANGUP);
     740                free(msg);
     741        }
     742       
     743        /*
     744         * If the connection was hung-up, answer the last call,
     745         * i.e. IPC_M_PHONE_HUNGUP.
     746         */
     747        if (fibril_connection->close_callid)
     748                ipc_answer_0(fibril_connection->close_callid, EOK);
     749       
     750        free(fibril_connection);
     751        return 0;
     752}
     753
     754/** Create a new fibril for a new connection.
     755 *
     756 * Create new fibril for connection, fill in connection structures
     757 * and insert it into the hash table, so that later we can easily
     758 * do routing of messages to particular fibrils.
     759 *
     760 * @param in_task_id    Identification of the incoming connection.
     761 * @param in_phone_hash Identification of the incoming connection.
     762 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
     763 *                      If callid is zero, the connection was opened by
     764 *                      accepting the IPC_M_CONNECT_TO_ME call and this
     765 *                      function is called directly by the server.
     766 * @param call          Call data of the opening call.
     767 * @param handler       Connection handler.
     768 * @param data          Client argument to pass to the connection handler.
     769 *
     770 * @return New fibril id or NULL on failure.
     771 *
     772 */
     773static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
     774    ipc_callid_t callid, ipc_call_t *call, async_port_handler_t handler,
     775    void *data)
     776{
     777        connection_t *conn = malloc(sizeof(*conn));
     778        if (!conn) {
     779                if (callid)
     780                        ipc_answer_0(callid, ENOMEM);
     781               
     782                return (uintptr_t) NULL;
     783        }
     784       
     785        conn->in_task_id = in_task_id;
     786        conn->in_phone_hash = in_phone_hash;
     787        list_initialize(&conn->msg_queue);
     788        conn->callid = callid;
     789        conn->close_callid = 0;
     790        conn->handler = handler;
     791        conn->data = data;
     792       
     793        if (call)
     794                conn->call = *call;
     795       
     796        /* We will activate the fibril ASAP */
     797        conn->wdata.active = true;
     798        conn->wdata.fid = fibril_create(connection_fibril, conn);
     799       
     800        if (conn->wdata.fid == 0) {
     801                free(conn);
     802               
     803                if (callid)
     804                        ipc_answer_0(callid, ENOMEM);
     805               
     806                return (uintptr_t) NULL;
     807        }
     808       
     809        /* Add connection to the connection hash table */
     810       
     811        futex_down(&async_futex);
     812        hash_table_insert(&conn_hash_table, &conn->link);
     813        futex_up(&async_futex);
     814       
     815        fibril_add_ready(conn->wdata.fid);
     816       
     817        return conn->wdata.fid;
     818}
    632819
    633820/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
     
    11181305}
    11191306
    1120 static client_t *async_client_get(task_id_t client_id, bool create)
    1121 {
    1122         client_t *client = NULL;
    1123 
    1124         futex_down(&async_futex);
    1125         ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
    1126         if (link) {
    1127                 client = hash_table_get_inst(link, client_t, link);
    1128                 atomic_inc(&client->refcnt);
    1129         } else if (create) {
    1130                 client = malloc(sizeof(client_t));
    1131                 if (client) {
    1132                         client->in_task_id = client_id;
    1133                         client->data = async_client_data_create();
    1134                
    1135                         atomic_set(&client->refcnt, 1);
    1136                         hash_table_insert(&client_hash_table, &client->link);
    1137                 }
    1138         }
    1139 
    1140         futex_up(&async_futex);
    1141         return client;
    1142 }
    1143 
    1144 static void async_client_put(client_t *client)
    1145 {
    1146         bool destroy;
    1147 
    1148         futex_down(&async_futex);
    1149        
    1150         if (atomic_predec(&client->refcnt) == 0) {
    1151                 hash_table_remove(&client_hash_table, &client->in_task_id);
    1152                 destroy = true;
    1153         } else
    1154                 destroy = false;
    1155        
    1156         futex_up(&async_futex);
    1157        
    1158         if (destroy) {
    1159                 if (client->data)
    1160                         async_client_data_destroy(client->data);
    1161                
    1162                 free(client);
    1163         }
    1164 }
    1165 
    11661307void *async_get_client_data(void)
    11671308{
     
    12171358       
    12181359        return port;
    1219 }
    1220 
    1221 /** Wrapper for client connection fibril.
    1222  *
    1223  * When a new connection arrives, a fibril with this implementing function is
    1224  * created. It calls handler() and does the final cleanup.
    1225  *
    1226  * @param arg Connection structure pointer.
    1227  *
    1228  * @return Always zero.
    1229  *
    1230  */
    1231 static int connection_fibril(void *arg)
    1232 {
    1233         assert(arg);
    1234        
    1235         /*
    1236          * Setup fibril-local connection pointer.
    1237          */
    1238         fibril_connection = (connection_t *) arg;
    1239        
    1240         /*
    1241          * Add our reference for the current connection in the client task
    1242          * tracking structure. If this is the first reference, create and
    1243          * hash in a new tracking structure.
    1244          */
    1245 
    1246         client_t *client = async_client_get(fibril_connection->in_task_id, true);
    1247         if (!client) {
    1248                 ipc_answer_0(fibril_connection->callid, ENOMEM);
    1249                 return 0;
    1250         }
    1251 
    1252         fibril_connection->client = client;
    1253        
    1254         /*
    1255          * Call the connection handler function.
    1256          */
    1257         fibril_connection->handler(fibril_connection->callid,
    1258             &fibril_connection->call, fibril_connection->data);
    1259        
    1260         /*
    1261          * Remove the reference for this client task connection.
    1262          */
    1263         async_client_put(client);
    1264        
    1265         /*
    1266          * Remove myself from the connection hash table.
    1267          */
    1268         futex_down(&async_futex);
    1269         hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
    1270         futex_up(&async_futex);
    1271        
    1272         /*
    1273          * Answer all remaining messages with EHANGUP.
    1274          */
    1275         while (!list_empty(&fibril_connection->msg_queue)) {
    1276                 msg_t *msg =
    1277                     list_get_instance(list_first(&fibril_connection->msg_queue),
    1278                     msg_t, link);
    1279                
    1280                 list_remove(&msg->link);
    1281                 ipc_answer_0(msg->callid, EHANGUP);
    1282                 free(msg);
    1283         }
    1284        
    1285         /*
    1286          * If the connection was hung-up, answer the last call,
    1287          * i.e. IPC_M_PHONE_HUNGUP.
    1288          */
    1289         if (fibril_connection->close_callid)
    1290                 ipc_answer_0(fibril_connection->close_callid, EOK);
    1291        
    1292         free(fibril_connection);
    1293         return 0;
    1294 }
    1295 
    1296 /** Create a new fibril for a new connection.
    1297  *
    1298  * Create new fibril for connection, fill in connection structures and insert
    1299  * it into the hash table, so that later we can easily do routing of messages to
    1300  * particular fibrils.
    1301  *
    1302  * @param in_task_id    Identification of the incoming connection.
    1303  * @param in_phone_hash Identification of the incoming connection.
    1304  * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
    1305  *                      If callid is zero, the connection was opened by
    1306  *                      accepting the IPC_M_CONNECT_TO_ME call and this function
    1307  *                      is called directly by the server.
    1308  * @param call          Call data of the opening call.
    1309  * @param handler       Fibril function that should be called upon opening the
    1310  *                      connection.
    1311  * @param data          Extra argument to pass to the connection fibril
    1312  *
    1313  * @return New fibril id or NULL on failure.
    1314  *
    1315  */
    1316 fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
    1317     ipc_callid_t callid, ipc_call_t *call,
    1318     async_port_handler_t handler, void *data)
    1319 {
    1320         connection_t *conn = malloc(sizeof(*conn));
    1321         if (!conn) {
    1322                 if (callid)
    1323                         ipc_answer_0(callid, ENOMEM);
    1324                
    1325                 return (uintptr_t) NULL;
    1326         }
    1327        
    1328         conn->in_task_id = in_task_id;
    1329         conn->in_phone_hash = in_phone_hash;
    1330         list_initialize(&conn->msg_queue);
    1331         conn->callid = callid;
    1332         conn->close_callid = 0;
    1333         conn->data = data;
    1334        
    1335         if (call)
    1336                 conn->call = *call;
    1337        
    1338         /* We will activate the fibril ASAP */
    1339         conn->wdata.active = true;
    1340         conn->handler = handler;
    1341         conn->wdata.fid = fibril_create(connection_fibril, conn);
    1342        
    1343         if (conn->wdata.fid == 0) {
    1344                 free(conn);
    1345                
    1346                 if (callid)
    1347                         ipc_answer_0(callid, ENOMEM);
    1348                
    1349                 return (uintptr_t) NULL;
    1350         }
    1351        
    1352         /* Add connection to the connection hash table */
    1353        
    1354         futex_down(&async_futex);
    1355         hash_table_insert(&conn_hash_table, &conn->link);
    1356         futex_up(&async_futex);
    1357        
    1358         fibril_add_ready(conn->wdata.fid);
    1359        
    1360         return conn->wdata.fid;
    13611360}
    13621361
Note: See TracChangeset for help on using the changeset viewer.