Ignore:
File:
1 edited

Legend:

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

    r8aa42e3 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)) {
    394                 if (conn->close_callid) {
    395                         /*
    396                          * Handle the case when the connection was already
    397                          * closed by the client but the server did not notice
    398                          * the first IPC_M_PHONE_HUNGUP call and continues to
    399                          * call async_get_call_timeout(). Repeat
    400                          * IPC_M_PHONE_HUNGUP until the caller notices.
    401                          */
    402                         memset(call, 0, sizeof(ipc_call_t));
    403                         IPC_SET_METHOD(*call, IPC_M_PHONE_HUNGUP);
    404                         futex_up(&async_futex);
    405                         return conn->close_callid;
    406                 }
    407 
    408414                if (usecs)
    409                         async_insert_timeout(&conn->wdata);
     415                        insert_timeout(&conn->wdata);
    410416               
    411417                conn->wdata.active = false;
     
    424430                 */
    425431                futex_down(&async_futex);
    426                 if ((usecs) && (conn->wdata.to_event.occurred)
     432                if ((usecs) && (conn->wdata.timedout)
    427433                    && (list_empty(&conn->msg_queue))) {
    428434                        /* If we timed out -> exit */
     
    542548        list_initialize(&conn->msg_queue);
    543549        conn->callid = callid;
    544         conn->close_callid = 0;
     550        conn->close_callid = false;
    545551       
    546552        if (call)
     
    619625        link_t *cur = timeout_list.next;
    620626        while (cur != &timeout_list) {
    621                 awaiter_t *waiter;
    622                
    623                 waiter = list_get_instance(cur, awaiter_t, to_event.link);
    624                 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))
    625630                        break;
    626 
     631               
    627632                cur = cur->next;
    628 
    629                 list_remove(&waiter->to_event.link);
    630                 waiter->to_event.inlist = false;
    631                 waiter->to_event.occurred = true;
     633               
     634                list_remove(&waiter->link);
     635                waiter->inlist = false;
     636                waiter->timedout = true;
    632637               
    633638                /*
     
    666671                if (!list_empty(&timeout_list)) {
    667672                        awaiter_t *waiter = list_get_instance(timeout_list.next,
    668                             awaiter_t, to_event.link);
     673                            awaiter_t, link);
    669674                       
    670675                        struct timeval tv;
    671676                        gettimeofday(&tv, NULL);
    672677                       
    673                         if (tv_gteq(&tv, &waiter->to_event.expires)) {
     678                        if (tv_gteq(&tv, &waiter->expires)) {
    674679                                futex_up(&async_futex);
    675680                                handle_expired_timeouts();
    676681                                continue;
    677682                        } else
    678                                 timeout = tv_sub(&waiter->to_event.expires,
    679                                     &tv);
     683                                timeout = tv_sub(&waiter->expires, &tv);
    680684                } else
    681685                        timeout = SYNCH_NO_TIMEOUT;
     
    778782       
    779783        /* Remove message from timeout list */
    780         if (msg->wdata.to_event.inlist)
    781                 list_remove(&msg->wdata.to_event.link);
     784        if (msg->wdata.inlist)
     785                list_remove(&msg->wdata.link);
    782786       
    783787        msg->done = true;
     
    818822        msg->dataptr = dataptr;
    819823       
    820         msg->wdata.to_event.inlist = false;
     824        msg->wdata.inlist = false;
    821825        /* We may sleep in the next method, but it will use its own mechanism */
    822826        msg->wdata.active = true;
     
    858862        msg->dataptr = dataptr;
    859863       
    860         msg->wdata.to_event.inlist = false;
     864        msg->wdata.inlist = false;
    861865        /* We may sleep in next method, but it will use its own mechanism */
    862866        msg->wdata.active = true;
     
    887891        msg->wdata.fid = fibril_get_id();
    888892        msg->wdata.active = false;
    889         msg->wdata.to_event.inlist = false;
     893        msg->wdata.inlist = false;
    890894       
    891895        /* Leave the async_futex locked when entering this function */
     
    925929        }
    926930       
    927         gettimeofday(&msg->wdata.to_event.expires, NULL);
    928         tv_add(&msg->wdata.to_event.expires, timeout);
     931        gettimeofday(&msg->wdata.expires, NULL);
     932        tv_add(&msg->wdata.expires, timeout);
    929933       
    930934        msg->wdata.fid = fibril_get_id();
    931935        msg->wdata.active = false;
    932         async_insert_timeout(&msg->wdata);
     936        insert_timeout(&msg->wdata);
    933937       
    934938        /* Leave the async_futex locked when entering this function */
     
    966970        msg->wdata.active = false;
    967971       
    968         gettimeofday(&msg->wdata.to_event.expires, NULL);
    969         tv_add(&msg->wdata.to_event.expires, timeout);
     972        gettimeofday(&msg->wdata.expires, NULL);
     973        tv_add(&msg->wdata.expires, timeout);
    970974       
    971975        futex_down(&async_futex);
    972976       
    973         async_insert_timeout(&msg->wdata);
     977        insert_timeout(&msg->wdata);
    974978       
    975979        /* Leave the async_futex locked when entering this function */
     
    11011105}
    11021106
    1103 /** Wrapper for making IPC_M_SHARE_IN calls using the async framework.
    1104  *
    1105  * @param phoneid       Phone that will be used to contact the receiving side.
    1106  * @param dst           Destination address space area base.
    1107  * @param size          Size of the destination address space area.
    1108  * @param arg           User defined argument.
    1109  * @param flags         Storage where the received flags will be stored. Can be
    1110  *                      NULL.
    1111  *
    1112  * @return              Zero on success or a negative error code from errno.h.
    1113  */
    1114 int async_share_in_start(int phoneid, void *dst, size_t size, ipcarg_t arg,
    1115     int *flags)
    1116 {
    1117         int res;
    1118         sysarg_t tmp_flags;
    1119         res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (ipcarg_t) dst,
    1120             (ipcarg_t) size, arg, NULL, &tmp_flags);
    1121         if (flags)
    1122                 *flags = tmp_flags;
    1123         return res;
    1124 }
    1125 
    1126 /** Wrapper for receiving the IPC_M_SHARE_IN calls using the async framework.
    1127  *
    1128  * This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN calls
    1129  * so that the user doesn't have to remember the meaning of each IPC argument.
    1130  *
    1131  * So far, this wrapper is to be used from within a connection fibril.
    1132  *
    1133  * @param callid        Storage where the hash of the IPC_M_SHARE_IN call will
    1134  *                      be stored.
    1135  * @param size          Destination address space area size.   
    1136  *
    1137  * @return              Non-zero on success, zero on failure.
    1138  */
    1139 int async_share_in_receive(ipc_callid_t *callid, size_t *size)
    1140 {
    1141         ipc_call_t data;
    1142        
    1143         assert(callid);
    1144         assert(size);
    1145 
    1146         *callid = async_get_call(&data);
    1147         if (IPC_GET_METHOD(data) != IPC_M_SHARE_IN)
    1148                 return 0;
    1149         *size = (size_t) IPC_GET_ARG2(data);
    1150         return 1;
    1151 }
    1152 
    1153 /** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework.
    1154  *
    1155  * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
    1156  * so that the user doesn't have to remember the meaning of each IPC argument.
    1157  *
    1158  * @param callid        Hash of the IPC_M_DATA_READ call to answer.
    1159  * @param src           Source address space base.
    1160  * @param flags         Flags to be used for sharing. Bits can be only cleared.
    1161  *
    1162  * @return              Zero on success or a value from @ref errno.h on failure.
    1163  */
    1164 int async_share_in_finalize(ipc_callid_t callid, void *src, int flags)
    1165 {
    1166         return ipc_share_in_finalize(callid, src, flags);
    1167 }
    1168 
    1169 /** Wrapper for making IPC_M_SHARE_OUT calls using the async framework.
    1170  *
    1171  * @param phoneid       Phone that will be used to contact the receiving side.
    1172  * @param src           Source address space area base address.
    1173  * @param flags         Flags to be used for sharing. Bits can be only cleared.
    1174  *
    1175  * @return              Zero on success or a negative error code from errno.h.
    1176  */
    1177 int async_share_out_start(int phoneid, void *src, int flags)
    1178 {
    1179         return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (ipcarg_t) src, 0,
    1180             (ipcarg_t) flags);
    1181 }
    1182 
    1183 /** Wrapper for receiving the IPC_M_SHARE_OUT calls using the async framework.
    1184  *
    1185  * This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT calls
    1186  * so that the user doesn't have to remember the meaning of each IPC argument.
    1187  *
    1188  * So far, this wrapper is to be used from within a connection fibril.
    1189  *
    1190  * @param callid        Storage where the hash of the IPC_M_SHARE_OUT call will
    1191  *                      be stored.
    1192  * @param size          Storage where the source address space area size will be
    1193  *                      stored.
    1194  * @param flags         Storage where the sharing flags will be stored.
    1195  *
    1196  * @return              Non-zero on success, zero on failure.
    1197  */
    1198 int async_share_out_receive(ipc_callid_t *callid, size_t *size, int *flags)
    1199 {
    1200         ipc_call_t data;
    1201        
    1202         assert(callid);
    1203         assert(size);
    1204         assert(flags);
    1205 
    1206         *callid = async_get_call(&data);
    1207         if (IPC_GET_METHOD(data) != IPC_M_SHARE_OUT)
    1208                 return 0;
    1209         *size = (size_t) IPC_GET_ARG2(data);
    1210         *flags = (int) IPC_GET_ARG3(data);
    1211         return 1;
    1212 }
    1213 
    1214 /** Wrapper for answering the IPC_M_SHARE_OUT calls using the async framework.
    1215  *
    1216  * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT calls
    1217  * so that the user doesn't have to remember the meaning of each IPC argument.
    1218  *
    1219  * @param callid        Hash of the IPC_M_DATA_WRITE call to answer.
    1220  * @param dst           Destination address space area base address.   
    1221  *
    1222  * @return              Zero on success or a value from @ref errno.h on failure.
    1223  */
    1224 int async_share_out_finalize(ipc_callid_t callid, void *dst)
    1225 {
    1226         return ipc_share_out_finalize(callid, dst);
    1227 }
    1228 
    1229 
    1230 /** Wrapper for making IPC_M_DATA_READ calls using the async framework.
    1231  *
    1232  * @param phoneid       Phone that will be used to contact the receiving side.
    1233  * @param dst           Address of the beginning of the destination buffer.
    1234  * @param size          Size of the destination buffer.
    1235  *
    1236  * @return              Zero on success or a negative error code from errno.h.
    1237  */
    1238 int async_data_read_start(int phoneid, void *dst, size_t size)
    1239 {
    1240         return async_req_2_0(phoneid, IPC_M_DATA_READ, (ipcarg_t) dst,
    1241             (ipcarg_t) size);
    1242 }
    1243 
    1244 /** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework.
    1245  *
    1246  * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ calls
    1247  * so that the user doesn't have to remember the meaning of each IPC argument.
    1248  *
    1249  * So far, this wrapper is to be used from within a connection fibril.
    1250  *
    1251  * @param callid        Storage where the hash of the IPC_M_DATA_READ call will
    1252  *                      be stored.
    1253  * @param size          Storage where the maximum size will be stored. Can be
    1254  *                      NULL.
    1255  *
    1256  * @return              Non-zero on success, zero on failure.
    1257  */
    1258 int async_data_read_receive(ipc_callid_t *callid, size_t *size)
    1259 {
    1260         ipc_call_t data;
    1261        
    1262         assert(callid);
    1263 
    1264         *callid = async_get_call(&data);
    1265         if (IPC_GET_METHOD(data) != IPC_M_DATA_READ)
    1266                 return 0;
    1267         if (size)
    1268                 *size = (size_t) IPC_GET_ARG2(data);
    1269         return 1;
    1270 }
    1271 
    1272 /** Wrapper for answering the IPC_M_DATA_READ calls using the async framework.
    1273  *
    1274  * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ calls
    1275  * so that the user doesn't have to remember the meaning of each IPC argument.
    1276  *
    1277  * @param callid        Hash of the IPC_M_DATA_READ call to answer.
    1278  * @param src           Source address for the IPC_M_DATA_READ call.
    1279  * @param size          Size for the IPC_M_DATA_READ call. Can be smaller than
    1280  *                      the maximum size announced by the sender.
    1281  *
    1282  * @return              Zero on success or a value from @ref errno.h on failure.
    1283  */
    1284 int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
    1285 {
    1286         return ipc_data_read_finalize(callid, src, size);
    1287 }
    1288 
    1289 /** Wrapper for making IPC_M_DATA_WRITE calls using the async framework.
    1290  *
    1291  * @param phoneid       Phone that will be used to contact the receiving side.
    1292  * @param src           Address of the beginning of the source buffer.
    1293  * @param size          Size of the source buffer.
    1294  *
    1295  * @return              Zero on success or a negative error code from errno.h.
    1296  */
    1297 int async_data_write_start(int phoneid, const void *src, size_t size)
    1298 {
    1299         return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (ipcarg_t) src,
    1300             (ipcarg_t) size);
    1301 }
    1302 
    1303 /** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework.
    1304  *
    1305  * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE calls
    1306  * so that the user doesn't have to remember the meaning of each IPC argument.
    1307  *
    1308  * So far, this wrapper is to be used from within a connection fibril.
    1309  *
    1310  * @param callid        Storage where the hash of the IPC_M_DATA_WRITE call will
    1311  *                      be stored.
    1312  * @param size          Storage where the suggested size will be stored. May be
    1313  *                      NULL
    1314  *
    1315  * @return              Non-zero on success, zero on failure.
    1316  */
    1317 int async_data_write_receive(ipc_callid_t *callid, size_t *size)
    1318 {
    1319         ipc_call_t data;
    1320        
    1321         assert(callid);
    1322 
    1323         *callid = async_get_call(&data);
    1324         if (IPC_GET_METHOD(data) != IPC_M_DATA_WRITE)
    1325                 return 0;
    1326         if (size)
    1327                 *size = (size_t) IPC_GET_ARG2(data);
    1328         return 1;
    1329 }
    1330 
    1331 /** Wrapper for answering the IPC_M_DATA_WRITE calls using the async framework.
    1332  *
    1333  * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE calls
    1334  * so that the user doesn't have to remember the meaning of each IPC argument.
    1335  *
    1336  * @param callid        Hash of the IPC_M_DATA_WRITE call to answer.
    1337  * @param dst           Final destination address for the IPC_M_DATA_WRITE call.
    1338  * @param size          Final size for the IPC_M_DATA_WRITE call.
    1339  *
    1340  * @return              Zero on success or a value from @ref errno.h on failure.
    1341  */
    1342 int async_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
    1343 {
    1344         return ipc_data_write_finalize(callid, dst, size);
    1345 }
    1346 
    1347 /** Wrapper for receiving blobs via the async_data_write_*
    1348  *
    1349  * This wrapper only makes it more comfortable to use async_data_write_*
    1350  * functions to receive blobs.
    1351  *
    1352  * @param blob     Pointer to data pointer (which should be later disposed
    1353  *                 by free()). If the operation fails, the pointer is not
    1354  *                 touched.
    1355  * @param max_size Maximum size (in bytes) of the blob to receive. 0 means
    1356  *                 no limit.
    1357  * @param received If not NULL, the size of the received data is stored here.
    1358  *
    1359  * @return Zero on success or a value from @ref errno.h on failure.
    1360  *
    1361  */
    1362 int async_data_blob_receive(char **blob, const size_t max_size, size_t *received)
    1363 {
    1364         ipc_callid_t callid;
    1365         size_t size;
    1366         if (!async_data_write_receive(&callid, &size)) {
    1367                 ipc_answer_0(callid, EINVAL);
    1368                 return EINVAL;
    1369         }
    1370        
    1371         if ((max_size > 0) && (size > max_size)) {
    1372                 ipc_answer_0(callid, EINVAL);
    1373                 return EINVAL;
    1374         }
    1375        
    1376         char *data = (char *) malloc(size);
    1377         if (data == NULL) {
    1378                 ipc_answer_0(callid, ENOMEM);
    1379                 return ENOMEM;
    1380         }
    1381        
    1382         int rc = async_data_write_finalize(callid, data, size);
    1383         if (rc != EOK) {
    1384                 free(data);
    1385                 return rc;
    1386         }
    1387        
    1388         *blob = data;
    1389         if (received != NULL)
    1390                 *received = size;
    1391        
    1392         return EOK;
    1393 }
    1394 
    1395 /** Wrapper for receiving strings via the async_data_write_*
    1396  *
    1397  * This wrapper only makes it more comfortable to use async_data_write_*
    1398  * functions to receive strings.
    1399  *
    1400  * @param str      Pointer to string pointer (which should be later disposed
    1401  *                 by free()). If the operation fails, the pointer is not
    1402  *                 touched.
    1403  * @param max_size Maximum size (in bytes) of the string to receive. 0 means
    1404  *                 no limit.
    1405  *
    1406  * @return Zero on success or a value from @ref errno.h on failure.
    1407  *
    1408  */
    1409 int async_data_string_receive(char **str, const size_t max_size)
    1410 {
    1411         ipc_callid_t callid;
    1412         size_t size;
    1413         if (!async_data_write_receive(&callid, &size)) {
    1414                 ipc_answer_0(callid, EINVAL);
    1415                 return EINVAL;
    1416         }
    1417        
    1418         if ((max_size > 0) && (size > max_size)) {
    1419                 ipc_answer_0(callid, EINVAL);
    1420                 return EINVAL;
    1421         }
    1422        
    1423         char *data = (char *) malloc(size + 1);
    1424         if (data == NULL) {
    1425                 ipc_answer_0(callid, ENOMEM);
    1426                 return ENOMEM;
    1427         }
    1428        
    1429         int rc = async_data_write_finalize(callid, data, size);
    1430         if (rc != EOK) {
    1431                 free(data);
    1432                 return rc;
    1433         }
    1434        
    1435         data[size] = 0;
    1436         *str = data;
    1437         return EOK;
    1438 }
    1439 
    14401107/** @}
    14411108 */
Note: See TracChangeset for help on using the changeset viewer.