Ignore:
File:
1 edited

Legend:

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

    r0da4e41 rdb24058  
    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>
     
    108107atomic_t async_futex = FUTEX_INITIALIZER;
    109108
    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. */
     110typedef 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;
    112129
    113130typedef struct {
     
    233250 *
    234251 */
    235 void async_insert_timeout(awaiter_t *wd)
    236 {
    237         wd->to_event.occurred = false;
    238         wd->to_event.inlist = true;
     252static void insert_timeout(awaiter_t *wd)
     253{
     254        wd->timedout = false;
     255        wd->inlist = true;
    239256       
    240257        link_t *tmp = timeout_list.next;
    241258        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))
    246262                        break;
     263               
    247264                tmp = tmp->next;
    248265        }
    249266       
    250         list_append(&wd->to_event.link, tmp);
     267        list_append(&wd->link, tmp);
    251268}
    252269
     
    295312               
    296313                /* 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);
    300317                }
    301318               
     
    385402       
    386403        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);
    389406        } else
    390                 conn->wdata.to_event.inlist = false;
     407                conn->wdata.inlist = false;
    391408       
    392409        /* If nothing in queue, wait until something arrives */
    393410        while (list_empty(&conn->msg_queue)) {
    394411                if (usecs)
    395                         async_insert_timeout(&conn->wdata);
     412                        insert_timeout(&conn->wdata);
    396413               
    397414                conn->wdata.active = false;
     
    410427                 */
    411428                futex_down(&async_futex);
    412                 if ((usecs) && (conn->wdata.to_event.occurred)
     429                if ((usecs) && (conn->wdata.timedout)
    413430                    && (list_empty(&conn->msg_queue))) {
    414431                        /* If we timed out -> exit */
     
    605622        link_t *cur = timeout_list.next;
    606623        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))
    611627                        break;
    612 
     628               
    613629                cur = cur->next;
    614 
    615                 list_remove(&waiter->to_event.link);
    616                 waiter->to_event.inlist = false;
    617                 waiter->to_event.occurred = true;
     630               
     631                list_remove(&waiter->link);
     632                waiter->inlist = false;
     633                waiter->timedout = true;
    618634               
    619635                /*
     
    652668                if (!list_empty(&timeout_list)) {
    653669                        awaiter_t *waiter = list_get_instance(timeout_list.next,
    654                             awaiter_t, to_event.link);
     670                            awaiter_t, link);
    655671                       
    656672                        struct timeval tv;
    657673                        gettimeofday(&tv, NULL);
    658674                       
    659                         if (tv_gteq(&tv, &waiter->to_event.expires)) {
     675                        if (tv_gteq(&tv, &waiter->expires)) {
    660676                                futex_up(&async_futex);
    661677                                handle_expired_timeouts();
    662678                                continue;
    663679                        } else
    664                                 timeout = tv_sub(&waiter->to_event.expires,
    665                                     &tv);
     680                                timeout = tv_sub(&waiter->expires, &tv);
    666681                } else
    667682                        timeout = SYNCH_NO_TIMEOUT;
    668683               
    669684                futex_up(&async_futex);
    670 
    671                 atomic_inc(&threads_in_ipc_wait);
    672685               
    673686                ipc_call_t call;
     
    675688                    SYNCH_FLAGS_NONE);
    676689               
    677                 atomic_dec(&threads_in_ipc_wait);
    678 
    679690                if (!callid) {
    680691                        handle_expired_timeouts();
     
    764775       
    765776        /* 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);
    768779       
    769780        msg->done = true;
     
    804815        msg->dataptr = dataptr;
    805816       
    806         msg->wdata.to_event.inlist = false;
     817        msg->wdata.inlist = false;
    807818        /* We may sleep in the next method, but it will use its own mechanism */
    808819        msg->wdata.active = true;
     
    844855        msg->dataptr = dataptr;
    845856       
    846         msg->wdata.to_event.inlist = false;
     857        msg->wdata.inlist = false;
    847858        /* We may sleep in next method, but it will use its own mechanism */
    848859        msg->wdata.active = true;
     
    873884        msg->wdata.fid = fibril_get_id();
    874885        msg->wdata.active = false;
    875         msg->wdata.to_event.inlist = false;
     886        msg->wdata.inlist = false;
    876887       
    877888        /* Leave the async_futex locked when entering this function */
     
    911922        }
    912923       
    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);
    915926       
    916927        msg->wdata.fid = fibril_get_id();
    917928        msg->wdata.active = false;
    918         async_insert_timeout(&msg->wdata);
     929        insert_timeout(&msg->wdata);
    919930       
    920931        /* Leave the async_futex locked when entering this function */
     
    952963        msg->wdata.active = false;
    953964       
    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);
    956967       
    957968        futex_down(&async_futex);
    958969       
    959         async_insert_timeout(&msg->wdata);
     970        insert_timeout(&msg->wdata);
    960971       
    961972        /* Leave the async_futex locked when entering this function */
     
    10871098}
    10881099
    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 
    13331100/** @}
    13341101 */
Note: See TracChangeset for help on using the changeset viewer.