Changes in uspace/lib/libc/generic/async.c [8619f25:8aa42e3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libc/generic/async.c
r8619f25 r8aa42e3 83 83 * 84 84 * callid = async_get_call(&call); 85 * handle_call(callid, call);85 * somehow_handle_the_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> 96 97 #include <fibril.h> 97 98 #include <stdio.h> … … 110 111 atomic_t threads_in_ipc_wait = { 0 }; 111 112 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 133 113 typedef struct { 134 114 awaiter_t wdata; … … 253 233 * 254 234 */ 255 static voidinsert_timeout(awaiter_t *wd)256 { 257 wd->t imedout= false;258 wd-> inlist = true;235 void async_insert_timeout(awaiter_t *wd) 236 { 237 wd->to_event.occurred = false; 238 wd->to_event.inlist = true; 259 239 260 240 link_t *tmp = timeout_list.next; 261 241 while (tmp != &timeout_list) { 262 awaiter_t *cur = list_get_instance(tmp, awaiter_t, link); 263 264 if (tv_gteq(&cur->expires, &wd->expires)) 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)) 265 246 break; 266 267 247 tmp = tmp->next; 268 248 } 269 249 270 list_append(&wd-> link, tmp);250 list_append(&wd->to_event.link, tmp); 271 251 } 272 252 … … 315 295 316 296 /* If in timeout list, remove it */ 317 if (conn->wdata. inlist) {318 conn->wdata. inlist = false;319 list_remove(&conn->wdata. link);297 if (conn->wdata.to_event.inlist) { 298 conn->wdata.to_event.inlist = false; 299 list_remove(&conn->wdata.to_event.link); 320 300 } 321 301 … … 405 385 406 386 if (usecs) { 407 gettimeofday(&conn->wdata. expires, NULL);408 tv_add(&conn->wdata. expires, usecs);387 gettimeofday(&conn->wdata.to_event.expires, NULL); 388 tv_add(&conn->wdata.to_event.expires, usecs); 409 389 } else 410 conn->wdata. inlist = false;390 conn->wdata.to_event.inlist = false; 411 391 412 392 /* If nothing in queue, wait until something arrives */ 413 393 while (list_empty(&conn->msg_queue)) { 394 if (conn->close_callid) { 395 /* 396 * Handle the case when the connection was already 397 * closed by the client but the server did not notice 398 * the first IPC_M_PHONE_HUNGUP call and continues to 399 * call async_get_call_timeout(). Repeat 400 * 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 414 408 if (usecs) 415 insert_timeout(&conn->wdata);409 async_insert_timeout(&conn->wdata); 416 410 417 411 conn->wdata.active = false; … … 430 424 */ 431 425 futex_down(&async_futex); 432 if ((usecs) && (conn->wdata.t imedout)426 if ((usecs) && (conn->wdata.to_event.occurred) 433 427 && (list_empty(&conn->msg_queue))) { 434 428 /* If we timed out -> exit */ … … 548 542 list_initialize(&conn->msg_queue); 549 543 conn->callid = callid; 550 conn->close_callid = false;544 conn->close_callid = 0; 551 545 552 546 if (call) … … 625 619 link_t *cur = timeout_list.next; 626 620 while (cur != &timeout_list) { 627 awaiter_t *waiter = list_get_instance(cur, awaiter_t, link); 628 629 if (tv_gt(&waiter->expires, &tv)) 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)) 630 625 break; 631 626 632 627 cur = cur->next; 633 634 list_remove(&waiter-> link);635 waiter-> inlist = false;636 waiter->t imedout= true;628 629 list_remove(&waiter->to_event.link); 630 waiter->to_event.inlist = false; 631 waiter->to_event.occurred = true; 637 632 638 633 /* … … 671 666 if (!list_empty(&timeout_list)) { 672 667 awaiter_t *waiter = list_get_instance(timeout_list.next, 673 awaiter_t, link);668 awaiter_t, to_event.link); 674 669 675 670 struct timeval tv; 676 671 gettimeofday(&tv, NULL); 677 672 678 if (tv_gteq(&tv, &waiter-> expires)) {673 if (tv_gteq(&tv, &waiter->to_event.expires)) { 679 674 futex_up(&async_futex); 680 675 handle_expired_timeouts(); 681 676 continue; 682 677 } else 683 timeout = tv_sub(&waiter->expires, &tv); 678 timeout = tv_sub(&waiter->to_event.expires, 679 &tv); 684 680 } else 685 681 timeout = SYNCH_NO_TIMEOUT; … … 782 778 783 779 /* Remove message from timeout list */ 784 if (msg->wdata. inlist)785 list_remove(&msg->wdata. link);780 if (msg->wdata.to_event.inlist) 781 list_remove(&msg->wdata.to_event.link); 786 782 787 783 msg->done = true; … … 822 818 msg->dataptr = dataptr; 823 819 824 msg->wdata. inlist = false;820 msg->wdata.to_event.inlist = false; 825 821 /* We may sleep in the next method, but it will use its own mechanism */ 826 822 msg->wdata.active = true; … … 862 858 msg->dataptr = dataptr; 863 859 864 msg->wdata. inlist = false;860 msg->wdata.to_event.inlist = false; 865 861 /* We may sleep in next method, but it will use its own mechanism */ 866 862 msg->wdata.active = true; … … 891 887 msg->wdata.fid = fibril_get_id(); 892 888 msg->wdata.active = false; 893 msg->wdata. inlist = false;889 msg->wdata.to_event.inlist = false; 894 890 895 891 /* Leave the async_futex locked when entering this function */ … … 929 925 } 930 926 931 gettimeofday(&msg->wdata. expires, NULL);932 tv_add(&msg->wdata. expires, timeout);927 gettimeofday(&msg->wdata.to_event.expires, NULL); 928 tv_add(&msg->wdata.to_event.expires, timeout); 933 929 934 930 msg->wdata.fid = fibril_get_id(); 935 931 msg->wdata.active = false; 936 insert_timeout(&msg->wdata);932 async_insert_timeout(&msg->wdata); 937 933 938 934 /* Leave the async_futex locked when entering this function */ … … 970 966 msg->wdata.active = false; 971 967 972 gettimeofday(&msg->wdata. expires, NULL);973 tv_add(&msg->wdata. expires, timeout);968 gettimeofday(&msg->wdata.to_event.expires, NULL); 969 tv_add(&msg->wdata.to_event.expires, timeout); 974 970 975 971 futex_down(&async_futex); 976 972 977 insert_timeout(&msg->wdata);973 async_insert_timeout(&msg->wdata); 978 974 979 975 /* Leave the async_futex locked when entering this function */ … … 1105 1101 } 1106 1102 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 be 1110 * 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 calls 1129 * 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 will 1134 * 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 calls 1156 * 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 calls 1186 * 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 will 1191 * be stored. 1192 * @param size Storage where the source address space area size will be 1193 * 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 calls 1217 * 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 calls 1247 * 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 will 1252 * be stored. 1253 * @param size Storage where the maximum size will be stored. Can be 1254 * 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 calls 1275 * 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 than 1280 * 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 calls 1306 * 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 will 1311 * be stored. 1312 * @param size Storage where the suggested size will be stored. May be 1313 * NULL 1314 * 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 calls 1334 * 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 disposed 1353 * by free()). If the operation fails, the pointer is not 1354 * touched. 1355 * @param max_size Maximum size (in bytes) of the blob to receive. 0 means 1356 * 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 disposed 1401 * by free()). If the operation fails, the pointer is not 1402 * touched. 1403 * @param max_size Maximum size (in bytes) of the string to receive. 0 means 1404 * 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 1107 1440 /** @} 1108 1441 */
Note:
See TracChangeset
for help on using the changeset viewer.