Changes in uspace/lib/libc/generic/async.c [db24058:0da4e41] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libc/generic/async.c
rdb24058 r0da4e41 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> … … 107 108 atomic_t async_futex = FUTEX_INITIALIZER; 108 109 109 /** Structures of this type represent a waiting fibril. */ 110 typedef struct { 111 /** Expiration time. */ 112 struct timeval expires; 113 114 /** If true, this struct is in the timeout list. */ 115 bool inlist; 116 117 /** Timeout list link. */ 118 link_t link; 119 120 /** Identification of and link to the waiting fibril. */ 121 fid_t fid; 122 123 /** If true, this fibril is currently active. */ 124 bool active; 125 126 /** If true, we have timed out. */ 127 bool timedout; 128 } awaiter_t; 110 /** Number of threads waiting for IPC in the kernel. */ 111 atomic_t threads_in_ipc_wait = { 0 }; 129 112 130 113 typedef struct { … … 250 233 * 251 234 */ 252 static voidinsert_timeout(awaiter_t *wd)253 { 254 wd->t imedout= false;255 wd-> inlist = true;235 void async_insert_timeout(awaiter_t *wd) 236 { 237 wd->to_event.occurred = false; 238 wd->to_event.inlist = true; 256 239 257 240 link_t *tmp = timeout_list.next; 258 241 while (tmp != &timeout_list) { 259 awaiter_t *cur = list_get_instance(tmp, awaiter_t, link); 260 261 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)) 262 246 break; 263 264 247 tmp = tmp->next; 265 248 } 266 249 267 list_append(&wd-> link, tmp);250 list_append(&wd->to_event.link, tmp); 268 251 } 269 252 … … 312 295 313 296 /* If in timeout list, remove it */ 314 if (conn->wdata. inlist) {315 conn->wdata. inlist = false;316 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); 317 300 } 318 301 … … 402 385 403 386 if (usecs) { 404 gettimeofday(&conn->wdata. expires, NULL);405 tv_add(&conn->wdata. expires, usecs);387 gettimeofday(&conn->wdata.to_event.expires, NULL); 388 tv_add(&conn->wdata.to_event.expires, usecs); 406 389 } else 407 conn->wdata. inlist = false;390 conn->wdata.to_event.inlist = false; 408 391 409 392 /* If nothing in queue, wait until something arrives */ 410 393 while (list_empty(&conn->msg_queue)) { 411 394 if (usecs) 412 insert_timeout(&conn->wdata);395 async_insert_timeout(&conn->wdata); 413 396 414 397 conn->wdata.active = false; … … 427 410 */ 428 411 futex_down(&async_futex); 429 if ((usecs) && (conn->wdata.t imedout)412 if ((usecs) && (conn->wdata.to_event.occurred) 430 413 && (list_empty(&conn->msg_queue))) { 431 414 /* If we timed out -> exit */ … … 622 605 link_t *cur = timeout_list.next; 623 606 while (cur != &timeout_list) { 624 awaiter_t *waiter = list_get_instance(cur, awaiter_t, link); 625 626 if (tv_gt(&waiter->expires, &tv)) 607 awaiter_t *waiter; 608 609 waiter = list_get_instance(cur, awaiter_t, to_event.link); 610 if (tv_gt(&waiter->to_event.expires, &tv)) 627 611 break; 628 612 629 613 cur = cur->next; 630 631 list_remove(&waiter-> link);632 waiter-> inlist = false;633 waiter->t imedout= true;614 615 list_remove(&waiter->to_event.link); 616 waiter->to_event.inlist = false; 617 waiter->to_event.occurred = true; 634 618 635 619 /* … … 668 652 if (!list_empty(&timeout_list)) { 669 653 awaiter_t *waiter = list_get_instance(timeout_list.next, 670 awaiter_t, link);654 awaiter_t, to_event.link); 671 655 672 656 struct timeval tv; 673 657 gettimeofday(&tv, NULL); 674 658 675 if (tv_gteq(&tv, &waiter-> expires)) {659 if (tv_gteq(&tv, &waiter->to_event.expires)) { 676 660 futex_up(&async_futex); 677 661 handle_expired_timeouts(); 678 662 continue; 679 663 } else 680 timeout = tv_sub(&waiter->expires, &tv); 664 timeout = tv_sub(&waiter->to_event.expires, 665 &tv); 681 666 } else 682 667 timeout = SYNCH_NO_TIMEOUT; 683 668 684 669 futex_up(&async_futex); 670 671 atomic_inc(&threads_in_ipc_wait); 685 672 686 673 ipc_call_t call; … … 688 675 SYNCH_FLAGS_NONE); 689 676 677 atomic_dec(&threads_in_ipc_wait); 678 690 679 if (!callid) { 691 680 handle_expired_timeouts(); … … 775 764 776 765 /* Remove message from timeout list */ 777 if (msg->wdata. inlist)778 list_remove(&msg->wdata. link);766 if (msg->wdata.to_event.inlist) 767 list_remove(&msg->wdata.to_event.link); 779 768 780 769 msg->done = true; … … 815 804 msg->dataptr = dataptr; 816 805 817 msg->wdata. inlist = false;806 msg->wdata.to_event.inlist = false; 818 807 /* We may sleep in the next method, but it will use its own mechanism */ 819 808 msg->wdata.active = true; … … 855 844 msg->dataptr = dataptr; 856 845 857 msg->wdata. inlist = false;846 msg->wdata.to_event.inlist = false; 858 847 /* We may sleep in next method, but it will use its own mechanism */ 859 848 msg->wdata.active = true; … … 884 873 msg->wdata.fid = fibril_get_id(); 885 874 msg->wdata.active = false; 886 msg->wdata. inlist = false;875 msg->wdata.to_event.inlist = false; 887 876 888 877 /* Leave the async_futex locked when entering this function */ … … 922 911 } 923 912 924 gettimeofday(&msg->wdata. expires, NULL);925 tv_add(&msg->wdata. expires, timeout);913 gettimeofday(&msg->wdata.to_event.expires, NULL); 914 tv_add(&msg->wdata.to_event.expires, timeout); 926 915 927 916 msg->wdata.fid = fibril_get_id(); 928 917 msg->wdata.active = false; 929 insert_timeout(&msg->wdata);918 async_insert_timeout(&msg->wdata); 930 919 931 920 /* Leave the async_futex locked when entering this function */ … … 963 952 msg->wdata.active = false; 964 953 965 gettimeofday(&msg->wdata. expires, NULL);966 tv_add(&msg->wdata. expires, timeout);954 gettimeofday(&msg->wdata.to_event.expires, NULL); 955 tv_add(&msg->wdata.to_event.expires, timeout); 967 956 968 957 futex_down(&async_futex); 969 958 970 insert_timeout(&msg->wdata);959 async_insert_timeout(&msg->wdata); 971 960 972 961 /* Leave the async_futex locked when entering this function */ … … 1098 1087 } 1099 1088 1089 /** Wrapper for making IPC_M_SHARE_IN calls using the async framework. 1090 * 1091 * @param phoneid Phone that will be used to contact the receiving side. 1092 * @param dst Destination address space area base. 1093 * @param size Size of the destination address space area. 1094 * @param arg User defined argument. 1095 * @param flags Storage where the received flags will be stored. Can be 1096 * NULL. 1097 * 1098 * @return Zero on success or a negative error code from errno.h. 1099 */ 1100 int async_share_in_start(int phoneid, void *dst, size_t size, ipcarg_t arg, 1101 int *flags) 1102 { 1103 int res; 1104 sysarg_t tmp_flags; 1105 res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst, 1106 (ipcarg_t) size, arg, NULL, &tmp_flags); 1107 if (flags) 1108 *flags = tmp_flags; 1109 return res; 1110 } 1111 1112 /** Wrapper for receiving the IPC_M_SHARE_IN calls using the async framework. 1113 * 1114 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN calls 1115 * so that the user doesn't have to remember the meaning of each IPC argument. 1116 * 1117 * So far, this wrapper is to be used from within a connection fibril. 1118 * 1119 * @param callid Storage where the hash of the IPC_M_SHARE_IN call will 1120 * be stored. 1121 * @param size Destination address space area size. 1122 * 1123 * @return Non-zero on success, zero on failure. 1124 */ 1125 int async_share_in_receive(ipc_callid_t *callid, size_t *size) 1126 { 1127 ipc_call_t data; 1128 1129 assert(callid); 1130 assert(size); 1131 1132 *callid = async_get_call(&data); 1133 if (IPC_GET_METHOD(data) != IPC_M_SHARE_IN) 1134 return 0; 1135 *size = (size_t) IPC_GET_ARG2(data); 1136 return 1; 1137 } 1138 1139 /** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework. 1140 * 1141 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls 1142 * so that the user doesn't have to remember the meaning of each IPC argument. 1143 * 1144 * @param callid Hash of the IPC_M_DATA_READ call to answer. 1145 * @param src Source address space base. 1146 * @param flags Flags to be used for sharing. Bits can be only cleared. 1147 * 1148 * @return Zero on success or a value from @ref errno.h on failure. 1149 */ 1150 int async_share_in_finalize(ipc_callid_t callid, void *src, int flags) 1151 { 1152 return ipc_share_in_finalize(callid, src, flags); 1153 } 1154 1155 /** Wrapper for making IPC_M_SHARE_OUT calls using the async framework. 1156 * 1157 * @param phoneid Phone that will be used to contact the receiving side. 1158 * @param src Source address space area base address. 1159 * @param flags Flags to be used for sharing. Bits can be only cleared. 1160 * 1161 * @return Zero on success or a negative error code from errno.h. 1162 */ 1163 int async_share_out_start(int phoneid, void *src, int flags) 1164 { 1165 return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0, 1166 (ipcarg_t) flags); 1167 } 1168 1169 /** Wrapper for receiving the IPC_M_SHARE_OUT calls using the async framework. 1170 * 1171 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT calls 1172 * so that the user doesn't have to remember the meaning of each IPC argument. 1173 * 1174 * So far, this wrapper is to be used from within a connection fibril. 1175 * 1176 * @param callid Storage where the hash of the IPC_M_SHARE_OUT call will 1177 * be stored. 1178 * @param size Storage where the source address space area size will be 1179 * stored. 1180 * @param flags Storage where the sharing flags will be stored. 1181 * 1182 * @return Non-zero on success, zero on failure. 1183 */ 1184 int async_share_out_receive(ipc_callid_t *callid, size_t *size, int *flags) 1185 { 1186 ipc_call_t data; 1187 1188 assert(callid); 1189 assert(size); 1190 assert(flags); 1191 1192 *callid = async_get_call(&data); 1193 if (IPC_GET_METHOD(data) != IPC_M_SHARE_OUT) 1194 return 0; 1195 *size = (size_t) IPC_GET_ARG2(data); 1196 *flags = (int) IPC_GET_ARG3(data); 1197 return 1; 1198 } 1199 1200 /** Wrapper for answering the IPC_M_SHARE_OUT calls using the async framework. 1201 * 1202 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT calls 1203 * so that the user doesn't have to remember the meaning of each IPC argument. 1204 * 1205 * @param callid Hash of the IPC_M_DATA_WRITE call to answer. 1206 * @param dst Destination address space area base address. 1207 * 1208 * @return Zero on success or a value from @ref errno.h on failure. 1209 */ 1210 int async_share_out_finalize(ipc_callid_t callid, void *dst) 1211 { 1212 return ipc_share_out_finalize(callid, dst); 1213 } 1214 1215 1216 /** Wrapper for making IPC_M_DATA_READ calls using the async framework. 1217 * 1218 * @param phoneid Phone that will be used to contact the receiving side. 1219 * @param dst Address of the beginning of the destination buffer. 1220 * @param size Size of the destination buffer. 1221 * 1222 * @return Zero on success or a negative error code from errno.h. 1223 */ 1224 int async_data_read_start(int phoneid, void *dst, size_t size) 1225 { 1226 return async_req_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst, 1227 (ipcarg_t) size); 1228 } 1229 1230 /** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework. 1231 * 1232 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls 1233 * so that the user doesn't have to remember the meaning of each IPC argument. 1234 * 1235 * So far, this wrapper is to be used from within a connection fibril. 1236 * 1237 * @param callid Storage where the hash of the IPC_M_DATA_READ call will 1238 * be stored. 1239 * @param size Storage where the maximum size will be stored. Can be 1240 * NULL. 1241 * 1242 * @return Non-zero on success, zero on failure. 1243 */ 1244 int async_data_read_receive(ipc_callid_t *callid, size_t *size) 1245 { 1246 ipc_call_t data; 1247 1248 assert(callid); 1249 1250 *callid = async_get_call(&data); 1251 if (IPC_GET_METHOD(data) != IPC_M_DATA_READ) 1252 return 0; 1253 if (size) 1254 *size = (size_t) IPC_GET_ARG2(data); 1255 return 1; 1256 } 1257 1258 /** Wrapper for answering the IPC_M_DATA_READ calls using the async framework. 1259 * 1260 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls 1261 * so that the user doesn't have to remember the meaning of each IPC argument. 1262 * 1263 * @param callid Hash of the IPC_M_DATA_READ call to answer. 1264 * @param src Source address for the IPC_M_DATA_READ call. 1265 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than 1266 * the maximum size announced by the sender. 1267 * 1268 * @return Zero on success or a value from @ref errno.h on failure. 1269 */ 1270 int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size) 1271 { 1272 return ipc_data_read_finalize(callid, src, size); 1273 } 1274 1275 /** Wrapper for making IPC_M_DATA_WRITE calls using the async framework. 1276 * 1277 * @param phoneid Phone that will be used to contact the receiving side. 1278 * @param src Address of the beginning of the source buffer. 1279 * @param size Size of the source buffer. 1280 * 1281 * @return Zero on success or a negative error code from errno.h. 1282 */ 1283 int async_data_write_start(int phoneid, const void *src, size_t size) 1284 { 1285 return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src, 1286 (ipcarg_t) size); 1287 } 1288 1289 /** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework. 1290 * 1291 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE calls 1292 * so that the user doesn't have to remember the meaning of each IPC argument. 1293 * 1294 * So far, this wrapper is to be used from within a connection fibril. 1295 * 1296 * @param callid Storage where the hash of the IPC_M_DATA_WRITE call will 1297 * be stored. 1298 * @param size Storage where the suggested size will be stored. May be 1299 * NULL 1300 * 1301 * @return Non-zero on success, zero on failure. 1302 */ 1303 int async_data_write_receive(ipc_callid_t *callid, size_t *size) 1304 { 1305 ipc_call_t data; 1306 1307 assert(callid); 1308 1309 *callid = async_get_call(&data); 1310 if (IPC_GET_METHOD(data) != IPC_M_DATA_WRITE) 1311 return 0; 1312 if (size) 1313 *size = (size_t) IPC_GET_ARG2(data); 1314 return 1; 1315 } 1316 1317 /** Wrapper for answering the IPC_M_DATA_WRITE calls using the async framework. 1318 * 1319 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE calls 1320 * so that the user doesn't have to remember the meaning of each IPC argument. 1321 * 1322 * @param callid Hash of the IPC_M_DATA_WRITE call to answer. 1323 * @param dst Final destination address for the IPC_M_DATA_WRITE call. 1324 * @param size Final size for the IPC_M_DATA_WRITE call. 1325 * 1326 * @return Zero on success or a value from @ref errno.h on failure. 1327 */ 1328 int async_data_write_finalize(ipc_callid_t callid, void *dst, size_t size) 1329 { 1330 return ipc_data_write_finalize(callid, dst, size); 1331 } 1332 1100 1333 /** @} 1101 1334 */
Note:
See TracChangeset
for help on using the changeset viewer.