Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/libc/generic/async.c

    r0da4e41 r8619f25  
    8383 *
    8484 *     callid = async_get_call(&call);
    85  *     somehow_handle_the_call(callid, call);
     85 *     handle_call(callid, call);
    8686 *     ipc_answer_2(callid, 1, 2, 3);
    8787 *
     
    9494#include <futex.h>
    9595#include <async.h>
    96 #include <async_priv.h>
    9796#include <fibril.h>
    9897#include <stdio.h>
     
    111110atomic_t threads_in_ipc_wait = { 0 };
    112111
     112/** Structures of this type represent a waiting fibril. */
     113typedef 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
    113133typedef struct {
    114134        awaiter_t wdata;
     
    233253 *
    234254 */
    235 void async_insert_timeout(awaiter_t *wd)
    236 {
    237         wd->to_event.occurred = false;
    238         wd->to_event.inlist = true;
     255static void insert_timeout(awaiter_t *wd)
     256{
     257        wd->timedout = false;
     258        wd->inlist = true;
    239259       
    240260        link_t *tmp = timeout_list.next;
    241261        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))
    246265                        break;
     266               
    247267                tmp = tmp->next;
    248268        }
    249269       
    250         list_append(&wd->to_event.link, tmp);
     270        list_append(&wd->link, tmp);
    251271}
    252272
     
    295315               
    296316                /* 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);
    300320                }
    301321               
     
    385405       
    386406        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);
    389409        } else
    390                 conn->wdata.to_event.inlist = false;
     410                conn->wdata.inlist = false;
    391411       
    392412        /* If nothing in queue, wait until something arrives */
    393413        while (list_empty(&conn->msg_queue)) {
    394414                if (usecs)
    395                         async_insert_timeout(&conn->wdata);
     415                        insert_timeout(&conn->wdata);
    396416               
    397417                conn->wdata.active = false;
     
    410430                 */
    411431                futex_down(&async_futex);
    412                 if ((usecs) && (conn->wdata.to_event.occurred)
     432                if ((usecs) && (conn->wdata.timedout)
    413433                    && (list_empty(&conn->msg_queue))) {
    414434                        /* If we timed out -> exit */
     
    605625        link_t *cur = timeout_list.next;
    606626        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))
     627                awaiter_t *waiter = list_get_instance(cur, awaiter_t, link);
     628               
     629                if (tv_gt(&waiter->expires, &tv))
    611630                        break;
    612 
     631               
    613632                cur = cur->next;
    614 
    615                 list_remove(&waiter->to_event.link);
    616                 waiter->to_event.inlist = false;
    617                 waiter->to_event.occurred = true;
     633               
     634                list_remove(&waiter->link);
     635                waiter->inlist = false;
     636                waiter->timedout = true;
    618637               
    619638                /*
     
    652671                if (!list_empty(&timeout_list)) {
    653672                        awaiter_t *waiter = list_get_instance(timeout_list.next,
    654                             awaiter_t, to_event.link);
     673                            awaiter_t, link);
    655674                       
    656675                        struct timeval tv;
    657676                        gettimeofday(&tv, NULL);
    658677                       
    659                         if (tv_gteq(&tv, &waiter->to_event.expires)) {
     678                        if (tv_gteq(&tv, &waiter->expires)) {
    660679                                futex_up(&async_futex);
    661680                                handle_expired_timeouts();
    662681                                continue;
    663682                        } else
    664                                 timeout = tv_sub(&waiter->to_event.expires,
    665                                     &tv);
     683                                timeout = tv_sub(&waiter->expires, &tv);
    666684                } else
    667685                        timeout = SYNCH_NO_TIMEOUT;
     
    764782       
    765783        /* Remove message from timeout list */
    766         if (msg->wdata.to_event.inlist)
    767                 list_remove(&msg->wdata.to_event.link);
     784        if (msg->wdata.inlist)
     785                list_remove(&msg->wdata.link);
    768786       
    769787        msg->done = true;
     
    804822        msg->dataptr = dataptr;
    805823       
    806         msg->wdata.to_event.inlist = false;
     824        msg->wdata.inlist = false;
    807825        /* We may sleep in the next method, but it will use its own mechanism */
    808826        msg->wdata.active = true;
     
    844862        msg->dataptr = dataptr;
    845863       
    846         msg->wdata.to_event.inlist = false;
     864        msg->wdata.inlist = false;
    847865        /* We may sleep in next method, but it will use its own mechanism */
    848866        msg->wdata.active = true;
     
    873891        msg->wdata.fid = fibril_get_id();
    874892        msg->wdata.active = false;
    875         msg->wdata.to_event.inlist = false;
     893        msg->wdata.inlist = false;
    876894       
    877895        /* Leave the async_futex locked when entering this function */
     
    911929        }
    912930       
    913         gettimeofday(&msg->wdata.to_event.expires, NULL);
    914         tv_add(&msg->wdata.to_event.expires, timeout);
     931        gettimeofday(&msg->wdata.expires, NULL);
     932        tv_add(&msg->wdata.expires, timeout);
    915933       
    916934        msg->wdata.fid = fibril_get_id();
    917935        msg->wdata.active = false;
    918         async_insert_timeout(&msg->wdata);
     936        insert_timeout(&msg->wdata);
    919937       
    920938        /* Leave the async_futex locked when entering this function */
     
    952970        msg->wdata.active = false;
    953971       
    954         gettimeofday(&msg->wdata.to_event.expires, NULL);
    955         tv_add(&msg->wdata.to_event.expires, timeout);
     972        gettimeofday(&msg->wdata.expires, NULL);
     973        tv_add(&msg->wdata.expires, timeout);
    956974       
    957975        futex_down(&async_futex);
    958976       
    959         async_insert_timeout(&msg->wdata);
     977        insert_timeout(&msg->wdata);
    960978       
    961979        /* Leave the async_futex locked when entering this function */
     
    10871105}
    10881106
    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 
    13331107/** @}
    13341108 */
Note: See TracChangeset for help on using the changeset viewer.