Changes in uspace/lib/c/generic/async.c [1db6dfd:cff3fb6] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async.c
r1db6dfd rcff3fb6 189 189 /** If reply was received. */ 190 190 bool done; 191 192 /** If the message / reply should be discarded on arrival. */193 bool forget;194 195 /** If already destroyed. */196 bool destroyed;197 191 198 192 /** Pointer to where the answer data is stored. */ … … 247 241 static fibril_local connection_t *fibril_connection; 248 242 249 static void to_event_initialize(to_event_t *to)250 {251 struct timeval tv = { 0, 0 };252 253 to->inlist = false;254 to->occurred = false;255 link_initialize(&to->link);256 to->expires = tv;257 }258 259 static void wu_event_initialize(wu_event_t *wu)260 {261 wu->inlist = false;262 link_initialize(&wu->link);263 }264 265 void awaiter_initialize(awaiter_t *aw)266 {267 aw->fid = 0;268 aw->active = false;269 to_event_initialize(&aw->to_event);270 wu_event_initialize(&aw->wu_event);271 }272 273 static amsg_t *amsg_create(void)274 {275 amsg_t *msg;276 277 msg = malloc(sizeof(amsg_t));278 if (msg) {279 msg->done = false;280 msg->forget = false;281 msg->destroyed = false;282 msg->dataptr = NULL;283 msg->retval = (sysarg_t) EINVAL;284 awaiter_initialize(&msg->wdata);285 }286 287 return msg;288 }289 290 static void amsg_destroy(amsg_t *msg)291 {292 assert(!msg->destroyed);293 msg->destroyed = true;294 free(msg);295 }296 297 243 static void *default_client_data_constructor(void) 298 244 { … … 311 257 void async_set_client_data_constructor(async_client_data_ctor_t ctor) 312 258 { 313 assert(async_client_data_create == default_client_data_constructor);314 259 async_client_data_create = ctor; 315 260 } … … 317 262 void async_set_client_data_destructor(async_client_data_dtor_t dtor) 318 263 { 319 assert(async_client_data_destroy == default_client_data_destructor);320 264 async_client_data_destroy = dtor; 321 265 } … … 359 303 void async_set_client_connection(async_client_conn_t conn) 360 304 { 361 assert(client_connection == default_client_connection);362 305 client_connection = conn; 363 306 } … … 1017 960 1018 961 suseconds_t timeout; 1019 unsigned int flags = SYNCH_FLAGS_NONE;1020 962 if (!list_empty(&timeout_list)) { 1021 963 awaiter_t *waiter = list_get_instance( … … 1028 970 futex_up(&async_futex); 1029 971 handle_expired_timeouts(); 1030 /* 1031 * Notice that even if the event(s) already 1032 * expired (and thus the other fibril was 1033 * supposed to be running already), 1034 * we check for incoming IPC. 1035 * 1036 * Otherwise, a fibril that continuously 1037 * creates (almost) expired events could 1038 * prevent IPC retrieval from the kernel. 1039 */ 1040 timeout = 0; 1041 flags = SYNCH_FLAGS_NON_BLOCKING; 1042 1043 } else { 972 continue; 973 } else 1044 974 timeout = tv_sub(&waiter->to_event.expires, &tv); 1045 futex_up(&async_futex); 1046 } 1047 } else { 1048 futex_up(&async_futex); 975 } else 1049 976 timeout = SYNCH_NO_TIMEOUT; 1050 } 977 978 futex_up(&async_futex); 1051 979 1052 980 atomic_inc(&threads_in_ipc_wait); 1053 981 1054 982 ipc_call_t call; 1055 ipc_callid_t callid = ipc_wait_cycle(&call, timeout, flags); 983 ipc_callid_t callid = ipc_wait_cycle(&call, timeout, 984 SYNCH_FLAGS_NONE); 1056 985 1057 986 atomic_dec(&threads_in_ipc_wait); … … 1168 1097 1169 1098 msg->done = true; 1170 1171 if (msg->forget) { 1172 assert(msg->wdata.active); 1173 amsg_destroy(msg); 1174 } else if (!msg->wdata.active) { 1099 if (!msg->wdata.active) { 1175 1100 msg->wdata.active = true; 1176 1101 fibril_add_ready(msg->wdata.fid); 1177 1102 } 1178 1103 1179 1104 futex_up(&async_futex); 1180 1105 } … … 1203 1128 return 0; 1204 1129 1205 amsg_t *msg = amsg_create();1130 amsg_t *msg = malloc(sizeof(amsg_t)); 1206 1131 if (msg == NULL) 1207 1132 return 0; 1208 1133 1134 msg->done = false; 1209 1135 msg->dataptr = dataptr; 1136 1137 msg->wdata.to_event.inlist = false; 1138 1139 /* 1140 * We may sleep in the next method, 1141 * but it will use its own means 1142 */ 1210 1143 msg->wdata.active = true; 1211 1144 … … 1241 1174 return 0; 1242 1175 1243 amsg_t *msg = amsg_create(); 1176 amsg_t *msg = malloc(sizeof(amsg_t)); 1177 1244 1178 if (msg == NULL) 1245 1179 return 0; 1246 1180 1181 msg->done = false; 1247 1182 msg->dataptr = dataptr; 1183 1184 msg->wdata.to_event.inlist = false; 1185 1186 /* 1187 * We may sleep in the next method, 1188 * but it will use its own means 1189 */ 1248 1190 msg->wdata.active = true; 1249 1191 … … 1268 1210 1269 1211 futex_down(&async_futex); 1270 1271 assert(!msg->forget);1272 assert(!msg->destroyed);1273 1274 1212 if (msg->done) { 1275 1213 futex_up(&async_futex); … … 1290 1228 *retval = msg->retval; 1291 1229 1292 amsg_destroy(msg);1230 free(msg); 1293 1231 } 1294 1232 1295 1233 /** Wait for a message sent by the async framework, timeout variant. 1296 *1297 * If the wait times out, the caller may choose to either wait again by calling1298 * async_wait_for() or async_wait_timeout(), or forget the message via1299 * async_forget().1300 1234 * 1301 1235 * @param amsgid Hash of the message to wait for. … … 1312 1246 1313 1247 amsg_t *msg = (amsg_t *) amsgid; 1314 1248 1249 /* TODO: Let it go through the event read at least once */ 1250 if (timeout < 0) 1251 return ETIMEOUT; 1252 1315 1253 futex_down(&async_futex); 1316 1317 assert(!msg->forget);1318 assert(!msg->destroyed);1319 1320 1254 if (msg->done) { 1321 1255 futex_up(&async_futex); … … 1323 1257 } 1324 1258 1325 /*1326 * Negative timeout is converted to zero timeout to avoid1327 * using tv_add with negative augmenter.1328 */1329 if (timeout < 0)1330 timeout = 0;1331 1332 1259 gettimeofday(&msg->wdata.to_event.expires, NULL); 1333 1260 tv_add(&msg->wdata.to_event.expires, timeout); 1334 1261 1335 /*1336 * Current fibril is inserted as waiting regardless of the1337 * "size" of the timeout.1338 *1339 * Checking for msg->done and immediately bailing out when1340 * timeout == 0 would mean that the manager fibril would never1341 * run (consider single threaded program).1342 * Thus the IPC answer would be never retrieved from the kernel.1343 *1344 * Notice that the actual delay would be very small because we1345 * - switch to manager fibril1346 * - the manager sees expired timeout1347 * - and thus adds us back to ready queue1348 * - manager switches back to some ready fibril1349 * (prior it, it checks for incoming IPC).1350 *1351 */1352 1262 msg->wdata.fid = fibril_get_id(); 1353 1263 msg->wdata.active = false; … … 1366 1276 *retval = msg->retval; 1367 1277 1368 amsg_destroy(msg);1278 free(msg); 1369 1279 1370 1280 return 0; 1371 1281 } 1372 1373 /** Discard the message / reply on arrival.1374 *1375 * The message will be marked to be discarded once the reply arrives in1376 * reply_received(). It is not allowed to call async_wait_for() or1377 * async_wait_timeout() on this message after a call to this function.1378 *1379 * @param amsgid Hash of the message to forget.1380 */1381 void async_forget(aid_t amsgid)1382 {1383 amsg_t *msg = (amsg_t *) amsgid;1384 1385 assert(msg);1386 assert(!msg->forget);1387 assert(!msg->destroyed);1388 1389 futex_down(&async_futex);1390 if (msg->done)1391 amsg_destroy(msg);1392 else1393 msg->forget = true;1394 futex_up(&async_futex);1395 }1396 1282 1397 1283 /** Wait for specified time. … … 1404 1290 void async_usleep(suseconds_t timeout) 1405 1291 { 1406 amsg_t *msg = amsg_create(); 1292 amsg_t *msg = malloc(sizeof(amsg_t)); 1293 1407 1294 if (!msg) 1408 1295 return; 1409 1296 1410 1297 msg->wdata.fid = fibril_get_id(); 1298 msg->wdata.active = false; 1411 1299 1412 1300 gettimeofday(&msg->wdata.to_event.expires, NULL); … … 1422 1310 /* Futex is up automatically after fibril_switch() */ 1423 1311 1424 amsg_destroy(msg);1312 free(msg); 1425 1313 } 1426 1314 … … 1693 1581 ipc_call_t result; 1694 1582 1695 amsg_t *msg = amsg_create();1696 if ( !msg) {1583 amsg_t *msg = malloc(sizeof(amsg_t)); 1584 if (msg == NULL) { 1697 1585 free(sess); 1698 1586 errno = ENOMEM; … … 1700 1588 } 1701 1589 1590 msg->done = false; 1702 1591 msg->dataptr = &result; 1592 1593 msg->wdata.to_event.inlist = false; 1594 1595 /* 1596 * We may sleep in the next method, 1597 * but it will use its own means 1598 */ 1703 1599 msg->wdata.active = true; 1704 1600 … … 1744 1640 ipc_call_t result; 1745 1641 1746 amsg_t *msg = amsg_create();1747 if ( !msg)1642 amsg_t *msg = malloc(sizeof(amsg_t)); 1643 if (msg == NULL) 1748 1644 return ENOENT; 1749 1645 1646 msg->done = false; 1750 1647 msg->dataptr = &result; 1648 1649 msg->wdata.to_event.inlist = false; 1650 1651 /* 1652 * We may sleep in the next method, 1653 * but it will use its own means 1654 */ 1751 1655 msg->wdata.active = true; 1752 1656 … … 1942 1846 1943 1847 fibril_mutex_lock(&async_sess_mutex); 1944 1848 1945 1849 int rc = async_hangup_internal(sess->phone); 1946 1850 … … 2094 1998 * 2095 1999 * @param exch Exchange for sending the message. 2000 * @param dst Destination address space area base. 2096 2001 * @param size Size of the destination address space area. 2097 2002 * @param arg User defined argument. 2098 2003 * @param flags Storage for the received flags. Can be NULL. 2099 * @param dst Destination address space area base. Cannot be NULL.2100 2004 * 2101 2005 * @return Zero on success or a negative error code from errno.h. 2102 2006 * 2103 2007 */ 2104 int async_share_in_start(async_exch_t *exch, size_t size, sysarg_t arg,2105 unsigned int *flags, void **dst)2008 int async_share_in_start(async_exch_t *exch, void *dst, size_t size, 2009 sysarg_t arg, unsigned int *flags) 2106 2010 { 2107 2011 if (exch == NULL) 2108 2012 return ENOENT; 2109 2013 2110 sysarg_t _flags = 0; 2111 sysarg_t _dst = (sysarg_t) -1; 2112 int res = async_req_2_4(exch, IPC_M_SHARE_IN, (sysarg_t) size, 2113 arg, NULL, &_flags, NULL, &_dst); 2014 sysarg_t tmp_flags; 2015 int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst, 2016 (sysarg_t) size, arg, NULL, &tmp_flags); 2114 2017 2115 2018 if (flags) 2116 *flags = (unsigned int) _flags; 2117 2118 *dst = (void *) _dst; 2019 *flags = (unsigned int) tmp_flags; 2020 2119 2021 return res; 2120 2022 } … … 2145 2047 return false; 2146 2048 2147 *size = (size_t) IPC_GET_ARG 1(data);2049 *size = (size_t) IPC_GET_ARG2(data); 2148 2050 return true; 2149 2051 } … … 2151 2053 /** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework. 2152 2054 * 2153 * This wrapper only makes it more comfortable to answer IPC_M_ SHARE_IN2055 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ 2154 2056 * calls so that the user doesn't have to remember the meaning of each IPC 2155 2057 * argument. … … 2229 2131 * 2230 2132 */ 2231 int async_share_out_finalize(ipc_callid_t callid, void * *dst)2133 int async_share_out_finalize(ipc_callid_t callid, void *dst) 2232 2134 { 2233 2135 return ipc_share_out_finalize(callid, dst); … … 2344 2246 IPC_FF_ROUTE_FROM_ME); 2345 2247 if (retval != EOK) { 2346 async_ forget(msg);2248 async_wait_for(msg, NULL); 2347 2249 ipc_answer_0(callid, retval); 2348 2250 return retval; … … 2538 2440 IPC_FF_ROUTE_FROM_ME); 2539 2441 if (retval != EOK) { 2540 async_ forget(msg);2442 async_wait_for(msg, NULL); 2541 2443 ipc_answer_0(callid, retval); 2542 2444 return retval;
Note:
See TracChangeset
for help on using the changeset viewer.