Ignore:
File:
1 edited

Legend:

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

    r8619f25 r8aa42e3  
    8383 *
    8484 *     callid = async_get_call(&call);
    85  *     handle_call(callid, call);
     85 *     somehow_handle_the_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>
    9697#include <fibril.h>
    9798#include <stdio.h>
     
    110111atomic_t threads_in_ipc_wait = { 0 };
    111112
    112 /** Structures of this type represent a waiting fibril. */
    113 typedef 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 
    133113typedef struct {
    134114        awaiter_t wdata;
     
    253233 *
    254234 */
    255 static void insert_timeout(awaiter_t *wd)
    256 {
    257         wd->timedout = false;
    258         wd->inlist = true;
     235void async_insert_timeout(awaiter_t *wd)
     236{
     237        wd->to_event.occurred = false;
     238        wd->to_event.inlist = true;
    259239       
    260240        link_t *tmp = timeout_list.next;
    261241        while (tmp != &timeout_list) {
    262                 awaiter_t *cur = list_get_instance(tmp, awaiter_t, link);
    263                
    264                 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))
    265246                        break;
    266                
    267247                tmp = tmp->next;
    268248        }
    269249       
    270         list_append(&wd->link, tmp);
     250        list_append(&wd->to_event.link, tmp);
    271251}
    272252
     
    315295               
    316296                /* If in timeout list, remove it */
    317                 if (conn->wdata.inlist) {
    318                         conn->wdata.inlist = false;
    319                         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);
    320300                }
    321301               
     
    405385       
    406386        if (usecs) {
    407                 gettimeofday(&conn->wdata.expires, NULL);
    408                 tv_add(&conn->wdata.expires, usecs);
     387                gettimeofday(&conn->wdata.to_event.expires, NULL);
     388                tv_add(&conn->wdata.to_event.expires, usecs);
    409389        } else
    410                 conn->wdata.inlist = false;
     390                conn->wdata.to_event.inlist = false;
    411391       
    412392        /* If nothing in queue, wait until something arrives */
    413393        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
    414408                if (usecs)
    415                         insert_timeout(&conn->wdata);
     409                        async_insert_timeout(&conn->wdata);
    416410               
    417411                conn->wdata.active = false;
     
    430424                 */
    431425                futex_down(&async_futex);
    432                 if ((usecs) && (conn->wdata.timedout)
     426                if ((usecs) && (conn->wdata.to_event.occurred)
    433427                    && (list_empty(&conn->msg_queue))) {
    434428                        /* If we timed out -> exit */
     
    548542        list_initialize(&conn->msg_queue);
    549543        conn->callid = callid;
    550         conn->close_callid = false;
     544        conn->close_callid = 0;
    551545       
    552546        if (call)
     
    625619        link_t *cur = timeout_list.next;
    626620        while (cur != &timeout_list) {
    627                 awaiter_t *waiter = list_get_instance(cur, awaiter_t, link);
    628                
    629                 if (tv_gt(&waiter->expires, &tv))
     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))
    630625                        break;
    631                
     626
    632627                cur = cur->next;
    633                
    634                 list_remove(&waiter->link);
    635                 waiter->inlist = false;
    636                 waiter->timedout = true;
     628
     629                list_remove(&waiter->to_event.link);
     630                waiter->to_event.inlist = false;
     631                waiter->to_event.occurred = true;
    637632               
    638633                /*
     
    671666                if (!list_empty(&timeout_list)) {
    672667                        awaiter_t *waiter = list_get_instance(timeout_list.next,
    673                             awaiter_t, link);
     668                            awaiter_t, to_event.link);
    674669                       
    675670                        struct timeval tv;
    676671                        gettimeofday(&tv, NULL);
    677672                       
    678                         if (tv_gteq(&tv, &waiter->expires)) {
     673                        if (tv_gteq(&tv, &waiter->to_event.expires)) {
    679674                                futex_up(&async_futex);
    680675                                handle_expired_timeouts();
    681676                                continue;
    682677                        } else
    683                                 timeout = tv_sub(&waiter->expires, &tv);
     678                                timeout = tv_sub(&waiter->to_event.expires,
     679                                    &tv);
    684680                } else
    685681                        timeout = SYNCH_NO_TIMEOUT;
     
    782778       
    783779        /* Remove message from timeout list */
    784         if (msg->wdata.inlist)
    785                 list_remove(&msg->wdata.link);
     780        if (msg->wdata.to_event.inlist)
     781                list_remove(&msg->wdata.to_event.link);
    786782       
    787783        msg->done = true;
     
    822818        msg->dataptr = dataptr;
    823819       
    824         msg->wdata.inlist = false;
     820        msg->wdata.to_event.inlist = false;
    825821        /* We may sleep in the next method, but it will use its own mechanism */
    826822        msg->wdata.active = true;
     
    862858        msg->dataptr = dataptr;
    863859       
    864         msg->wdata.inlist = false;
     860        msg->wdata.to_event.inlist = false;
    865861        /* We may sleep in next method, but it will use its own mechanism */
    866862        msg->wdata.active = true;
     
    891887        msg->wdata.fid = fibril_get_id();
    892888        msg->wdata.active = false;
    893         msg->wdata.inlist = false;
     889        msg->wdata.to_event.inlist = false;
    894890       
    895891        /* Leave the async_futex locked when entering this function */
     
    929925        }
    930926       
    931         gettimeofday(&msg->wdata.expires, NULL);
    932         tv_add(&msg->wdata.expires, timeout);
     927        gettimeofday(&msg->wdata.to_event.expires, NULL);
     928        tv_add(&msg->wdata.to_event.expires, timeout);
    933929       
    934930        msg->wdata.fid = fibril_get_id();
    935931        msg->wdata.active = false;
    936         insert_timeout(&msg->wdata);
     932        async_insert_timeout(&msg->wdata);
    937933       
    938934        /* Leave the async_futex locked when entering this function */
     
    970966        msg->wdata.active = false;
    971967       
    972         gettimeofday(&msg->wdata.expires, NULL);
    973         tv_add(&msg->wdata.expires, timeout);
     968        gettimeofday(&msg->wdata.to_event.expires, NULL);
     969        tv_add(&msg->wdata.to_event.expires, timeout);
    974970       
    975971        futex_down(&async_futex);
    976972       
    977         insert_timeout(&msg->wdata);
     973        async_insert_timeout(&msg->wdata);
    978974       
    979975        /* Leave the async_futex locked when entering this function */
     
    11051101}
    11061102
     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 */
     1114int 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 */
     1139int 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 */
     1164int 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 */
     1177int 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 */
     1198int 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 */
     1224int 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 */
     1238int 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 */
     1258int 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 */
     1284int 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 */
     1297int 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 */
     1317int 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 */
     1342int 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 */
     1362int 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 */
     1409int 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
    11071440/** @}
    11081441 */
Note: See TracChangeset for help on using the changeset viewer.