Changes in uspace/lib/libc/generic/async.c [0da4e41:db24058] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libc/generic/async.c
r0da4e41 rdb24058 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> … … 108 107 atomic_t async_futex = FUTEX_INITIALIZER; 109 108 110 /** Number of threads waiting for IPC in the kernel. */ 111 atomic_t threads_in_ipc_wait = { 0 }; 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; 112 129 113 130 typedef struct { … … 233 250 * 234 251 */ 235 void async_insert_timeout(awaiter_t *wd)236 { 237 wd->t o_event.occurred= false;238 wd-> to_event.inlist = true;252 static void insert_timeout(awaiter_t *wd) 253 { 254 wd->timedout = false; 255 wd->inlist = true; 239 256 240 257 link_t *tmp = timeout_list.next; 241 258 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)) 259 awaiter_t *cur = list_get_instance(tmp, awaiter_t, link); 260 261 if (tv_gteq(&cur->expires, &wd->expires)) 246 262 break; 263 247 264 tmp = tmp->next; 248 265 } 249 266 250 list_append(&wd-> to_event.link, tmp);267 list_append(&wd->link, tmp); 251 268 } 252 269 … … 295 312 296 313 /* 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);314 if (conn->wdata.inlist) { 315 conn->wdata.inlist = false; 316 list_remove(&conn->wdata.link); 300 317 } 301 318 … … 385 402 386 403 if (usecs) { 387 gettimeofday(&conn->wdata. to_event.expires, NULL);388 tv_add(&conn->wdata. to_event.expires, usecs);404 gettimeofday(&conn->wdata.expires, NULL); 405 tv_add(&conn->wdata.expires, usecs); 389 406 } else 390 conn->wdata. to_event.inlist = false;407 conn->wdata.inlist = false; 391 408 392 409 /* If nothing in queue, wait until something arrives */ 393 410 while (list_empty(&conn->msg_queue)) { 394 411 if (usecs) 395 async_insert_timeout(&conn->wdata);412 insert_timeout(&conn->wdata); 396 413 397 414 conn->wdata.active = false; … … 410 427 */ 411 428 futex_down(&async_futex); 412 if ((usecs) && (conn->wdata.t o_event.occurred)429 if ((usecs) && (conn->wdata.timedout) 413 430 && (list_empty(&conn->msg_queue))) { 414 431 /* If we timed out -> exit */ … … 605 622 link_t *cur = timeout_list.next; 606 623 while (cur != &timeout_list) { 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)) 624 awaiter_t *waiter = list_get_instance(cur, awaiter_t, link); 625 626 if (tv_gt(&waiter->expires, &tv)) 611 627 break; 612 628 613 629 cur = cur->next; 614 615 list_remove(&waiter-> to_event.link);616 waiter-> to_event.inlist = false;617 waiter->t o_event.occurred= true;630 631 list_remove(&waiter->link); 632 waiter->inlist = false; 633 waiter->timedout = true; 618 634 619 635 /* … … 652 668 if (!list_empty(&timeout_list)) { 653 669 awaiter_t *waiter = list_get_instance(timeout_list.next, 654 awaiter_t, to_event.link);670 awaiter_t, link); 655 671 656 672 struct timeval tv; 657 673 gettimeofday(&tv, NULL); 658 674 659 if (tv_gteq(&tv, &waiter-> to_event.expires)) {675 if (tv_gteq(&tv, &waiter->expires)) { 660 676 futex_up(&async_futex); 661 677 handle_expired_timeouts(); 662 678 continue; 663 679 } else 664 timeout = tv_sub(&waiter->to_event.expires, 665 &tv); 680 timeout = tv_sub(&waiter->expires, &tv); 666 681 } else 667 682 timeout = SYNCH_NO_TIMEOUT; 668 683 669 684 futex_up(&async_futex); 670 671 atomic_inc(&threads_in_ipc_wait);672 685 673 686 ipc_call_t call; … … 675 688 SYNCH_FLAGS_NONE); 676 689 677 atomic_dec(&threads_in_ipc_wait);678 679 690 if (!callid) { 680 691 handle_expired_timeouts(); … … 764 775 765 776 /* Remove message from timeout list */ 766 if (msg->wdata. to_event.inlist)767 list_remove(&msg->wdata. to_event.link);777 if (msg->wdata.inlist) 778 list_remove(&msg->wdata.link); 768 779 769 780 msg->done = true; … … 804 815 msg->dataptr = dataptr; 805 816 806 msg->wdata. to_event.inlist = false;817 msg->wdata.inlist = false; 807 818 /* We may sleep in the next method, but it will use its own mechanism */ 808 819 msg->wdata.active = true; … … 844 855 msg->dataptr = dataptr; 845 856 846 msg->wdata. to_event.inlist = false;857 msg->wdata.inlist = false; 847 858 /* We may sleep in next method, but it will use its own mechanism */ 848 859 msg->wdata.active = true; … … 873 884 msg->wdata.fid = fibril_get_id(); 874 885 msg->wdata.active = false; 875 msg->wdata. to_event.inlist = false;886 msg->wdata.inlist = false; 876 887 877 888 /* Leave the async_futex locked when entering this function */ … … 911 922 } 912 923 913 gettimeofday(&msg->wdata. to_event.expires, NULL);914 tv_add(&msg->wdata. to_event.expires, timeout);924 gettimeofday(&msg->wdata.expires, NULL); 925 tv_add(&msg->wdata.expires, timeout); 915 926 916 927 msg->wdata.fid = fibril_get_id(); 917 928 msg->wdata.active = false; 918 async_insert_timeout(&msg->wdata);929 insert_timeout(&msg->wdata); 919 930 920 931 /* Leave the async_futex locked when entering this function */ … … 952 963 msg->wdata.active = false; 953 964 954 gettimeofday(&msg->wdata. to_event.expires, NULL);955 tv_add(&msg->wdata. to_event.expires, timeout);965 gettimeofday(&msg->wdata.expires, NULL); 966 tv_add(&msg->wdata.expires, timeout); 956 967 957 968 futex_down(&async_futex); 958 969 959 async_insert_timeout(&msg->wdata);970 insert_timeout(&msg->wdata); 960 971 961 972 /* Leave the async_futex locked when entering this function */ … … 1087 1098 } 1088 1099 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 be1096 * 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 calls1115 * 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 will1120 * 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 calls1142 * 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 calls1172 * 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 will1177 * be stored.1178 * @param size Storage where the source address space area size will be1179 * 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 calls1203 * 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 calls1233 * 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 will1238 * be stored.1239 * @param size Storage where the maximum size will be stored. Can be1240 * 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 calls1261 * 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 than1266 * 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 calls1292 * 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 will1297 * be stored.1298 * @param size Storage where the suggested size will be stored. May be1299 * NULL1300 *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 calls1320 * 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 1333 1100 /** @} 1334 1101 */
Note:
See TracChangeset
for help on using the changeset viewer.