Changes in uspace/lib/libc/generic/async.c [8aa42e3:8619f25] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libc/generic/async.c
r8aa42e3 r8619f25 83 83 * 84 84 * callid = async_get_call(&call); 85 * somehow_handle_the_call(callid, call);85 * handle_call(callid, call); 86 86 * ipc_answer_2(callid, 1, 2, 3); 87 87 * … … 94 94 #include <futex.h> 95 95 #include <async.h> 96 #include <async_priv.h>97 96 #include <fibril.h> 98 97 #include <stdio.h> … … 111 110 atomic_t threads_in_ipc_wait = { 0 }; 112 111 112 /** Structures of this type represent a waiting fibril. */ 113 typedef struct { 114 /** Expiration time. */ 115 struct timeval expires; 116 117 /** If true, this struct is in the timeout list. */ 118 bool inlist; 119 120 /** Timeout list link. */ 121 link_t link; 122 123 /** Identification of and link to the waiting fibril. */ 124 fid_t fid; 125 126 /** If true, this fibril is currently active. */ 127 bool active; 128 129 /** If true, we have timed out. */ 130 bool timedout; 131 } awaiter_t; 132 113 133 typedef struct { 114 134 awaiter_t wdata; … … 233 253 * 234 254 */ 235 void async_insert_timeout(awaiter_t *wd)236 { 237 wd->t o_event.occurred= false;238 wd-> to_event.inlist = true;255 static void insert_timeout(awaiter_t *wd) 256 { 257 wd->timedout = false; 258 wd->inlist = true; 239 259 240 260 link_t *tmp = timeout_list.next; 241 261 while (tmp != &timeout_list) { 242 awaiter_t *cur; 243 244 cur = list_get_instance(tmp, awaiter_t, to_event.link); 245 if (tv_gteq(&cur->to_event.expires, &wd->to_event.expires)) 262 awaiter_t *cur = list_get_instance(tmp, awaiter_t, link); 263 264 if (tv_gteq(&cur->expires, &wd->expires)) 246 265 break; 266 247 267 tmp = tmp->next; 248 268 } 249 269 250 list_append(&wd-> to_event.link, tmp);270 list_append(&wd->link, tmp); 251 271 } 252 272 … … 295 315 296 316 /* If in timeout list, remove it */ 297 if (conn->wdata. to_event.inlist) {298 conn->wdata. to_event.inlist = false;299 list_remove(&conn->wdata. to_event.link);317 if (conn->wdata.inlist) { 318 conn->wdata.inlist = false; 319 list_remove(&conn->wdata.link); 300 320 } 301 321 … … 385 405 386 406 if (usecs) { 387 gettimeofday(&conn->wdata. to_event.expires, NULL);388 tv_add(&conn->wdata. to_event.expires, usecs);407 gettimeofday(&conn->wdata.expires, NULL); 408 tv_add(&conn->wdata.expires, usecs); 389 409 } else 390 conn->wdata. to_event.inlist = false;410 conn->wdata.inlist = false; 391 411 392 412 /* If nothing in queue, wait until something arrives */ 393 413 while (list_empty(&conn->msg_queue)) { 394 if (conn->close_callid) {395 /*396 * Handle the case when the connection was already397 * closed by the client but the server did not notice398 * the first IPC_M_PHONE_HUNGUP call and continues to399 * call async_get_call_timeout(). Repeat400 * IPC_M_PHONE_HUNGUP until the caller notices.401 */402 memset(call, 0, sizeof(ipc_call_t));403 IPC_SET_METHOD(*call, IPC_M_PHONE_HUNGUP);404 futex_up(&async_futex);405 return conn->close_callid;406 }407 408 414 if (usecs) 409 async_insert_timeout(&conn->wdata);415 insert_timeout(&conn->wdata); 410 416 411 417 conn->wdata.active = false; … … 424 430 */ 425 431 futex_down(&async_futex); 426 if ((usecs) && (conn->wdata.t o_event.occurred)432 if ((usecs) && (conn->wdata.timedout) 427 433 && (list_empty(&conn->msg_queue))) { 428 434 /* If we timed out -> exit */ … … 542 548 list_initialize(&conn->msg_queue); 543 549 conn->callid = callid; 544 conn->close_callid = 0;550 conn->close_callid = false; 545 551 546 552 if (call) … … 619 625 link_t *cur = timeout_list.next; 620 626 while (cur != &timeout_list) { 621 awaiter_t *waiter; 622 623 waiter = list_get_instance(cur, awaiter_t, to_event.link); 624 if (tv_gt(&waiter->to_event.expires, &tv)) 627 awaiter_t *waiter = list_get_instance(cur, awaiter_t, link); 628 629 if (tv_gt(&waiter->expires, &tv)) 625 630 break; 626 631 627 632 cur = cur->next; 628 629 list_remove(&waiter-> to_event.link);630 waiter-> to_event.inlist = false;631 waiter->t o_event.occurred= true;633 634 list_remove(&waiter->link); 635 waiter->inlist = false; 636 waiter->timedout = true; 632 637 633 638 /* … … 666 671 if (!list_empty(&timeout_list)) { 667 672 awaiter_t *waiter = list_get_instance(timeout_list.next, 668 awaiter_t, to_event.link);673 awaiter_t, link); 669 674 670 675 struct timeval tv; 671 676 gettimeofday(&tv, NULL); 672 677 673 if (tv_gteq(&tv, &waiter-> to_event.expires)) {678 if (tv_gteq(&tv, &waiter->expires)) { 674 679 futex_up(&async_futex); 675 680 handle_expired_timeouts(); 676 681 continue; 677 682 } else 678 timeout = tv_sub(&waiter->to_event.expires, 679 &tv); 683 timeout = tv_sub(&waiter->expires, &tv); 680 684 } else 681 685 timeout = SYNCH_NO_TIMEOUT; … … 778 782 779 783 /* Remove message from timeout list */ 780 if (msg->wdata. to_event.inlist)781 list_remove(&msg->wdata. to_event.link);784 if (msg->wdata.inlist) 785 list_remove(&msg->wdata.link); 782 786 783 787 msg->done = true; … … 818 822 msg->dataptr = dataptr; 819 823 820 msg->wdata. to_event.inlist = false;824 msg->wdata.inlist = false; 821 825 /* We may sleep in the next method, but it will use its own mechanism */ 822 826 msg->wdata.active = true; … … 858 862 msg->dataptr = dataptr; 859 863 860 msg->wdata. to_event.inlist = false;864 msg->wdata.inlist = false; 861 865 /* We may sleep in next method, but it will use its own mechanism */ 862 866 msg->wdata.active = true; … … 887 891 msg->wdata.fid = fibril_get_id(); 888 892 msg->wdata.active = false; 889 msg->wdata. to_event.inlist = false;893 msg->wdata.inlist = false; 890 894 891 895 /* Leave the async_futex locked when entering this function */ … … 925 929 } 926 930 927 gettimeofday(&msg->wdata. to_event.expires, NULL);928 tv_add(&msg->wdata. to_event.expires, timeout);931 gettimeofday(&msg->wdata.expires, NULL); 932 tv_add(&msg->wdata.expires, timeout); 929 933 930 934 msg->wdata.fid = fibril_get_id(); 931 935 msg->wdata.active = false; 932 async_insert_timeout(&msg->wdata);936 insert_timeout(&msg->wdata); 933 937 934 938 /* Leave the async_futex locked when entering this function */ … … 966 970 msg->wdata.active = false; 967 971 968 gettimeofday(&msg->wdata. to_event.expires, NULL);969 tv_add(&msg->wdata. to_event.expires, timeout);972 gettimeofday(&msg->wdata.expires, NULL); 973 tv_add(&msg->wdata.expires, timeout); 970 974 971 975 futex_down(&async_futex); 972 976 973 async_insert_timeout(&msg->wdata);977 insert_timeout(&msg->wdata); 974 978 975 979 /* Leave the async_futex locked when entering this function */ … … 1101 1105 } 1102 1106 1103 /** Wrapper for making IPC_M_SHARE_IN calls using the async framework.1104 *1105 * @param phoneid Phone that will be used to contact the receiving side.1106 * @param dst Destination address space area base.1107 * @param size Size of the destination address space area.1108 * @param arg User defined argument.1109 * @param flags Storage where the received flags will be stored. Can be1110 * NULL.1111 *1112 * @return Zero on success or a negative error code from errno.h.1113 */1114 int async_share_in_start(int phoneid, void *dst, size_t size, ipcarg_t arg,1115 int *flags)1116 {1117 int res;1118 sysarg_t tmp_flags;1119 res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst,1120 (ipcarg_t) size, arg, NULL, &tmp_flags);1121 if (flags)1122 *flags = tmp_flags;1123 return res;1124 }1125 1126 /** Wrapper for receiving the IPC_M_SHARE_IN calls using the async framework.1127 *1128 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN calls1129 * so that the user doesn't have to remember the meaning of each IPC argument.1130 *1131 * So far, this wrapper is to be used from within a connection fibril.1132 *1133 * @param callid Storage where the hash of the IPC_M_SHARE_IN call will1134 * be stored.1135 * @param size Destination address space area size.1136 *1137 * @return Non-zero on success, zero on failure.1138 */1139 int async_share_in_receive(ipc_callid_t *callid, size_t *size)1140 {1141 ipc_call_t data;1142 1143 assert(callid);1144 assert(size);1145 1146 *callid = async_get_call(&data);1147 if (IPC_GET_METHOD(data) != IPC_M_SHARE_IN)1148 return 0;1149 *size = (size_t) IPC_GET_ARG2(data);1150 return 1;1151 }1152 1153 /** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework.1154 *1155 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls1156 * so that the user doesn't have to remember the meaning of each IPC argument.1157 *1158 * @param callid Hash of the IPC_M_DATA_READ call to answer.1159 * @param src Source address space base.1160 * @param flags Flags to be used for sharing. Bits can be only cleared.1161 *1162 * @return Zero on success or a value from @ref errno.h on failure.1163 */1164 int async_share_in_finalize(ipc_callid_t callid, void *src, int flags)1165 {1166 return ipc_share_in_finalize(callid, src, flags);1167 }1168 1169 /** Wrapper for making IPC_M_SHARE_OUT calls using the async framework.1170 *1171 * @param phoneid Phone that will be used to contact the receiving side.1172 * @param src Source address space area base address.1173 * @param flags Flags to be used for sharing. Bits can be only cleared.1174 *1175 * @return Zero on success or a negative error code from errno.h.1176 */1177 int async_share_out_start(int phoneid, void *src, int flags)1178 {1179 return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0,1180 (ipcarg_t) flags);1181 }1182 1183 /** Wrapper for receiving the IPC_M_SHARE_OUT calls using the async framework.1184 *1185 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT calls1186 * so that the user doesn't have to remember the meaning of each IPC argument.1187 *1188 * So far, this wrapper is to be used from within a connection fibril.1189 *1190 * @param callid Storage where the hash of the IPC_M_SHARE_OUT call will1191 * be stored.1192 * @param size Storage where the source address space area size will be1193 * stored.1194 * @param flags Storage where the sharing flags will be stored.1195 *1196 * @return Non-zero on success, zero on failure.1197 */1198 int async_share_out_receive(ipc_callid_t *callid, size_t *size, int *flags)1199 {1200 ipc_call_t data;1201 1202 assert(callid);1203 assert(size);1204 assert(flags);1205 1206 *callid = async_get_call(&data);1207 if (IPC_GET_METHOD(data) != IPC_M_SHARE_OUT)1208 return 0;1209 *size = (size_t) IPC_GET_ARG2(data);1210 *flags = (int) IPC_GET_ARG3(data);1211 return 1;1212 }1213 1214 /** Wrapper for answering the IPC_M_SHARE_OUT calls using the async framework.1215 *1216 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT calls1217 * so that the user doesn't have to remember the meaning of each IPC argument.1218 *1219 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.1220 * @param dst Destination address space area base address.1221 *1222 * @return Zero on success or a value from @ref errno.h on failure.1223 */1224 int async_share_out_finalize(ipc_callid_t callid, void *dst)1225 {1226 return ipc_share_out_finalize(callid, dst);1227 }1228 1229 1230 /** Wrapper for making IPC_M_DATA_READ calls using the async framework.1231 *1232 * @param phoneid Phone that will be used to contact the receiving side.1233 * @param dst Address of the beginning of the destination buffer.1234 * @param size Size of the destination buffer.1235 *1236 * @return Zero on success or a negative error code from errno.h.1237 */1238 int async_data_read_start(int phoneid, void *dst, size_t size)1239 {1240 return async_req_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst,1241 (ipcarg_t) size);1242 }1243 1244 /** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework.1245 *1246 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls1247 * so that the user doesn't have to remember the meaning of each IPC argument.1248 *1249 * So far, this wrapper is to be used from within a connection fibril.1250 *1251 * @param callid Storage where the hash of the IPC_M_DATA_READ call will1252 * be stored.1253 * @param size Storage where the maximum size will be stored. Can be1254 * NULL.1255 *1256 * @return Non-zero on success, zero on failure.1257 */1258 int async_data_read_receive(ipc_callid_t *callid, size_t *size)1259 {1260 ipc_call_t data;1261 1262 assert(callid);1263 1264 *callid = async_get_call(&data);1265 if (IPC_GET_METHOD(data) != IPC_M_DATA_READ)1266 return 0;1267 if (size)1268 *size = (size_t) IPC_GET_ARG2(data);1269 return 1;1270 }1271 1272 /** Wrapper for answering the IPC_M_DATA_READ calls using the async framework.1273 *1274 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls1275 * so that the user doesn't have to remember the meaning of each IPC argument.1276 *1277 * @param callid Hash of the IPC_M_DATA_READ call to answer.1278 * @param src Source address for the IPC_M_DATA_READ call.1279 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than1280 * the maximum size announced by the sender.1281 *1282 * @return Zero on success or a value from @ref errno.h on failure.1283 */1284 int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)1285 {1286 return ipc_data_read_finalize(callid, src, size);1287 }1288 1289 /** Wrapper for making IPC_M_DATA_WRITE calls using the async framework.1290 *1291 * @param phoneid Phone that will be used to contact the receiving side.1292 * @param src Address of the beginning of the source buffer.1293 * @param size Size of the source buffer.1294 *1295 * @return Zero on success or a negative error code from errno.h.1296 */1297 int async_data_write_start(int phoneid, const void *src, size_t size)1298 {1299 return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src,1300 (ipcarg_t) size);1301 }1302 1303 /** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework.1304 *1305 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE calls1306 * so that the user doesn't have to remember the meaning of each IPC argument.1307 *1308 * So far, this wrapper is to be used from within a connection fibril.1309 *1310 * @param callid Storage where the hash of the IPC_M_DATA_WRITE call will1311 * be stored.1312 * @param size Storage where the suggested size will be stored. May be1313 * NULL1314 *1315 * @return Non-zero on success, zero on failure.1316 */1317 int async_data_write_receive(ipc_callid_t *callid, size_t *size)1318 {1319 ipc_call_t data;1320 1321 assert(callid);1322 1323 *callid = async_get_call(&data);1324 if (IPC_GET_METHOD(data) != IPC_M_DATA_WRITE)1325 return 0;1326 if (size)1327 *size = (size_t) IPC_GET_ARG2(data);1328 return 1;1329 }1330 1331 /** Wrapper for answering the IPC_M_DATA_WRITE calls using the async framework.1332 *1333 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE calls1334 * so that the user doesn't have to remember the meaning of each IPC argument.1335 *1336 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.1337 * @param dst Final destination address for the IPC_M_DATA_WRITE call.1338 * @param size Final size for the IPC_M_DATA_WRITE call.1339 *1340 * @return Zero on success or a value from @ref errno.h on failure.1341 */1342 int async_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)1343 {1344 return ipc_data_write_finalize(callid, dst, size);1345 }1346 1347 /** Wrapper for receiving blobs via the async_data_write_*1348 *1349 * This wrapper only makes it more comfortable to use async_data_write_*1350 * functions to receive blobs.1351 *1352 * @param blob Pointer to data pointer (which should be later disposed1353 * by free()). If the operation fails, the pointer is not1354 * touched.1355 * @param max_size Maximum size (in bytes) of the blob to receive. 0 means1356 * no limit.1357 * @param received If not NULL, the size of the received data is stored here.1358 *1359 * @return Zero on success or a value from @ref errno.h on failure.1360 *1361 */1362 int async_data_blob_receive(char **blob, const size_t max_size, size_t *received)1363 {1364 ipc_callid_t callid;1365 size_t size;1366 if (!async_data_write_receive(&callid, &size)) {1367 ipc_answer_0(callid, EINVAL);1368 return EINVAL;1369 }1370 1371 if ((max_size > 0) && (size > max_size)) {1372 ipc_answer_0(callid, EINVAL);1373 return EINVAL;1374 }1375 1376 char *data = (char *) malloc(size);1377 if (data == NULL) {1378 ipc_answer_0(callid, ENOMEM);1379 return ENOMEM;1380 }1381 1382 int rc = async_data_write_finalize(callid, data, size);1383 if (rc != EOK) {1384 free(data);1385 return rc;1386 }1387 1388 *blob = data;1389 if (received != NULL)1390 *received = size;1391 1392 return EOK;1393 }1394 1395 /** Wrapper for receiving strings via the async_data_write_*1396 *1397 * This wrapper only makes it more comfortable to use async_data_write_*1398 * functions to receive strings.1399 *1400 * @param str Pointer to string pointer (which should be later disposed1401 * by free()). If the operation fails, the pointer is not1402 * touched.1403 * @param max_size Maximum size (in bytes) of the string to receive. 0 means1404 * no limit.1405 *1406 * @return Zero on success or a value from @ref errno.h on failure.1407 *1408 */1409 int async_data_string_receive(char **str, const size_t max_size)1410 {1411 ipc_callid_t callid;1412 size_t size;1413 if (!async_data_write_receive(&callid, &size)) {1414 ipc_answer_0(callid, EINVAL);1415 return EINVAL;1416 }1417 1418 if ((max_size > 0) && (size > max_size)) {1419 ipc_answer_0(callid, EINVAL);1420 return EINVAL;1421 }1422 1423 char *data = (char *) malloc(size + 1);1424 if (data == NULL) {1425 ipc_answer_0(callid, ENOMEM);1426 return ENOMEM;1427 }1428 1429 int rc = async_data_write_finalize(callid, data, size);1430 if (rc != EOK) {1431 free(data);1432 return rc;1433 }1434 1435 data[size] = 0;1436 *str = data;1437 return EOK;1438 }1439 1440 1107 /** @} 1441 1108 */
Note:
See TracChangeset
for help on using the changeset viewer.