Changeset 9ef495f in mainline for uspace/lib/c/generic/async.c
- Timestamp:
- 2015-08-23T13:31:31Z (9 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 616f5dd3
- Parents:
- f9b2cb4c
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async.c
rf9b2cb4c r9ef495f 630 630 .remove_callback = NULL 631 631 }; 632 633 static 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 657 static 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 */ 689 static 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 */ 773 static 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 } 632 819 633 820 /** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework. … … 1118 1305 } 1119 1306 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 } else1154 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 1166 1307 void *async_get_client_data(void) 1167 1308 { … … 1217 1358 1218 1359 return port; 1219 }1220 1221 /** Wrapper for client connection fibril.1222 *1223 * When a new connection arrives, a fibril with this implementing function is1224 * 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 task1242 * tracking structure. If this is the first reference, create and1243 * 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 insert1299 * it into the hash table, so that later we can easily do routing of messages to1300 * 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 by1306 * accepting the IPC_M_CONNECT_TO_ME call and this function1307 * 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 the1310 * connection.1311 * @param data Extra argument to pass to the connection fibril1312 *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;1361 1360 } 1362 1361
Note:
See TracChangeset
for help on using the changeset viewer.