Changeset 9c16c36 in mainline
- Timestamp:
- 2018-06-07T17:00:32Z (7 years ago)
- Children:
- 95faa4d
- Parents:
- 8404342
- git-author:
- Jiří Zárevúcky <jiri.zarevucky@…> (2018-05-25 17:07:26)
- git-committer:
- Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-07 17:00:32)
- Location:
- uspace/lib/c
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/async/client.c
r8404342 r9c16c36 1346 1346 } 1347 1347 1348 void async_call_begin(async_call_t *call, async_sess_t *sess, sysarg_t imethod, 1349 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4) 1350 { 1351 memset(call, 0, sizeof(*call)); 1352 1353 call->exch = async_exchange_begin(sess); 1354 if (!call->exch) { 1355 call->rc = ENOMEM; 1356 return; 1357 } 1358 1359 async_call_method(call, &call->initial, imethod, 1360 arg1, arg2, arg3, arg4); 1361 } 1362 1363 static suseconds_t time_until(const struct timeval *t) 1364 { 1365 struct timeval tv; 1366 getuptime(&tv); 1367 if (tv_gteq(&tv, t)) 1368 return 1; 1369 1370 return tv_sub_diff(t, &tv); 1371 } 1372 1373 static errno_t async_call_finish_internal(async_call_t *call, const struct timeval *expires) 1374 { 1375 errno_t rc; 1376 1377 /* Wait for all the fragments. */ 1378 while (!list_empty(&call->fragments)) { 1379 link_t *tmp = list_first(&call->fragments); 1380 async_call_data_t *frag = 1381 list_get_instance(tmp, async_call_data_t, link); 1382 1383 if (expires) { 1384 errno_t trc = async_wait_timeout(frag->msgid, &rc, 1385 time_until(expires)); 1386 if (trc != EOK) 1387 return trc; 1388 } else { 1389 async_wait_for(frag->msgid, &rc); 1390 } 1391 1392 list_remove(tmp); 1393 1394 if (rc != EOK) 1395 return rc; 1396 1397 if (frag->finalizer) { 1398 rc = frag->finalizer(frag); 1399 if (rc != EOK) 1400 return rc; 1401 } 1402 } 1403 1404 return EOK; 1405 } 1406 1407 errno_t async_call_finish_timeout(async_call_t *call, const struct timeval *expires) 1408 { 1409 assert(call); 1410 1411 if (call->rc) 1412 return call->rc; 1413 1414 if (call->exch) { 1415 async_exchange_end(call->exch); 1416 call->exch = NULL; 1417 } 1418 1419 errno_t rc = async_call_finish_internal(call, expires); 1420 if (rc == ETIMEOUT) 1421 return rc; 1422 1423 /* If one fails, abort the call. */ 1424 if (rc != EOK) 1425 async_call_abort(call); 1426 1427 assert(list_empty(&call->fragments)); 1428 call->rc = rc; 1429 return rc; 1430 } 1431 1432 // Ends the call, and waits for all in-flight fragments to finish. 1433 errno_t async_call_finish(async_call_t *call) 1434 { 1435 return async_call_finish_timeout(call, NULL); 1436 } 1437 1438 // Aborts the call. After this function returns, auxiliary structures 1439 // and buffers are safe to deallocate. 1440 extern void async_call_abort(async_call_t *call) 1441 { 1442 // FIXME: Proper abort needs kernel support. A system call should 1443 // clean up bookkeeping structures in the kernel and notify 1444 // the server of the abort as well. 1445 1446 // Currently, we just wait, which is less than ideal, 1447 // but at the same time, nothing in HelenOS currently 1448 // benefits from timeouts. 1449 1450 assert(call); 1451 1452 if (call->exch) { 1453 async_exchange_end(call->exch); 1454 call->exch = NULL; 1455 } 1456 1457 /* Wait for all the fragments. */ 1458 while (!list_empty(&call->fragments)) { 1459 // TODO: abort instead of waiting 1460 (void) async_call_finish_internal(call, NULL); 1461 } 1462 1463 assert(list_empty(&call->fragments)); 1464 } 1465 1466 // Waits for all in-flight fragments to finish, but doesn't end the call. 1467 errno_t async_call_wait(async_call_t *call) 1468 { 1469 return async_call_wait_timeout(call, NULL); 1470 } 1471 1472 errno_t async_call_wait_timeout(async_call_t *call, const struct timeval *expires) 1473 { 1474 assert(call); 1475 1476 if (call->rc) 1477 return call->rc; 1478 1479 /* Wait for all the fragments except the initial one. */ 1480 assert(list_first(&call->fragments) == &call->initial.link); 1481 list_remove(&call->initial.link); 1482 1483 errno_t rc = async_call_finish_internal(call, expires); 1484 list_prepend(&call->initial.link, &call->fragments); 1485 1486 if (rc == ETIMEOUT) 1487 return rc; 1488 1489 /* If one fails, abort the call. */ 1490 if (rc != EOK) 1491 async_call_abort(call); 1492 1493 call->rc = rc; 1494 return rc; 1495 } 1496 1497 void async_call_method_with_finalizer(async_call_t *call, 1498 async_call_data_t *data, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, 1499 sysarg_t arg3, sysarg_t arg4, async_call_finalizer_t finalizer) 1500 { 1501 assert(call); 1502 assert(data); 1503 data->finalizer = finalizer; 1504 1505 if (!call->exch) 1506 call->rc = ENOENT; 1507 1508 if (call->rc) 1509 return; 1510 1511 data->msgid = async_send_fast(call->exch, imethod, 1512 arg1, arg2, arg3, arg4, &data->answer); 1513 if (!data->msgid) { 1514 async_call_abort(call); 1515 call->rc = ENOMEM; 1516 } 1517 1518 list_append(&data->link, &call->fragments); 1519 } 1520 1521 void async_call_method(async_call_t *call, async_call_data_t *data, 1522 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4) 1523 { 1524 assert(call); 1525 assert(data); 1526 memset(data, 0, sizeof(*data)); 1527 1528 async_call_method_with_finalizer(call, data, imethod, 1529 arg1, arg2, arg3, arg4, NULL); 1530 } 1531 1532 static errno_t call_read_write_finalizer(async_call_data_t *data) 1533 { 1534 size_t *sz = data->arg1; 1535 if (sz) 1536 *sz = IPC_GET_ARG2(data->answer); 1537 return EOK; 1538 } 1539 1540 void async_call_read(async_call_t *call, async_call_data_t *data, 1541 void *dst, size_t size, size_t *nread) 1542 { 1543 assert(call); 1544 assert(data); 1545 memset(data, 0, sizeof(*data)); 1546 1547 data->arg1 = nread; 1548 1549 async_call_method_with_finalizer(call, data, 1550 IPC_M_DATA_READ, (sysarg_t) dst, (sysarg_t) size, 0, 0, 1551 call_read_write_finalizer); 1552 } 1553 1554 /** 1555 * After the call is successfully finished, 1556 * `IPC_GET_ARG2(&data->answer)` holds the actual number of bytes written. 1557 */ 1558 void async_call_write(async_call_t *call, async_call_data_t *data, 1559 const void *src, size_t size, size_t *nwritten) 1560 { 1561 assert(call); 1562 assert(data); 1563 memset(data, 0, sizeof(*data)); 1564 1565 data->arg1 = nwritten; 1566 1567 async_call_method_with_finalizer(call, data, 1568 IPC_M_DATA_WRITE, (sysarg_t) src, (sysarg_t) size, 0, 0, 1569 call_read_write_finalizer); 1570 } 1571 1572 static errno_t call_share_in_finalizer(async_call_data_t *data) 1573 { 1574 unsigned int *flags = data->arg1; 1575 void **dst = data->arg2; 1576 1577 if (flags) 1578 *flags = IPC_GET_ARG2(data->answer); 1579 1580 if (dst) 1581 *dst = (void *) IPC_GET_ARG4(data->answer); 1582 1583 return EOK; 1584 } 1585 1586 void async_call_share_in(async_call_t *call, async_call_data_t *data, 1587 size_t size, sysarg_t arg, unsigned int *flags, void **dst) 1588 { 1589 assert(call); 1590 assert(data); 1591 memset(data, 0, sizeof(*data)); 1592 1593 data->arg1 = flags; 1594 data->arg2 = dst; 1595 1596 async_call_method_with_finalizer(call, data, 1597 IPC_M_SHARE_IN, (sysarg_t) size, (sysarg_t) arg, 0, 0, 1598 call_share_in_finalizer); 1599 } 1600 1601 void async_call_share_out(async_call_t *call, async_call_data_t *data, 1602 void *src, unsigned int flags) 1603 { 1604 async_call_method(call, data, 1605 IPC_M_SHARE_OUT, (sysarg_t) src, 0, (sysarg_t) flags, 0); 1606 } 1607 1608 // TODO: connect me to, connect to me, vfs handle, etc. 1609 1348 1610 /** @} 1349 1611 */ -
uspace/lib/c/generic/time.c
r8404342 r9c16c36 503 503 * 504 504 */ 505 suseconds_t tv_sub_diff( struct timeval *tv1,struct timeval *tv2)505 suseconds_t tv_sub_diff(const struct timeval *tv1, const struct timeval *tv2) 506 506 { 507 507 return (tv1->tv_usec - tv2->tv_usec) + … … 531 531 * 532 532 */ 533 int tv_gt( struct timeval *tv1,struct timeval *tv2)533 int tv_gt(const struct timeval *tv1, const struct timeval *tv2) 534 534 { 535 535 if (tv1->tv_sec > tv2->tv_sec) … … 551 551 * 552 552 */ 553 int tv_gteq( struct timeval *tv1,struct timeval *tv2)553 int tv_gteq(const struct timeval *tv1, const struct timeval *tv2) 554 554 { 555 555 if (tv1->tv_sec > tv2->tv_sec) -
uspace/lib/c/include/async.h
r8404342 r9c16c36 492 492 sysarg_t, sysarg_t, sysarg_t); 493 493 494 struct async_call_data; 495 496 typedef errno_t (*async_call_finalizer_t)(struct async_call_data *); 497 498 typedef struct async_call_data { 499 // public 500 ipc_call_t answer; 501 502 // private 503 link_t link; 504 void *arg1; 505 void *arg2; 506 aid_t msgid; 507 async_call_finalizer_t finalizer; 508 } async_call_data_t; 509 510 typedef struct async_call { 511 // public 512 async_call_data_t initial; 513 514 // private 515 list_t fragments; 516 async_exch_t *exch; 517 errno_t rc; 518 } async_call_t; 519 520 extern void async_call_begin(async_call_t *, async_sess_t *, sysarg_t, 521 sysarg_t, sysarg_t, sysarg_t, sysarg_t); 522 523 // Waits for all in-flight fragments to finish, and ends the call. 524 extern errno_t async_call_finish(async_call_t *); 525 extern errno_t async_call_finish_timeout(async_call_t *, const struct timeval *); 526 527 // Aborts the call. After this function returns, auxiliary structures 528 // and buffers are safe to deallocate. 529 // TODO: might need some extra support from kernel 530 extern void async_call_abort(async_call_t *); 531 532 // Waits for all in-flight fragments to finish, but doesn't end the call. 533 extern errno_t async_call_wait(async_call_t *); 534 extern errno_t async_call_wait_timeout(async_call_t *, const struct timeval *); 535 536 extern void async_call_method_with_finalizer(async_call_t *, 537 async_call_data_t *, sysarg_t, sysarg_t, sysarg_t, sysarg_t, sysarg_t, 538 async_call_finalizer_t); 539 extern void async_call_method(async_call_t *, async_call_data_t *, sysarg_t, 540 sysarg_t, sysarg_t, sysarg_t, sysarg_t); 541 542 extern void async_call_read(async_call_t *, async_call_data_t *, 543 void *, size_t, size_t *); 544 extern void async_call_write(async_call_t *, async_call_data_t *, 545 const void *, size_t, size_t *); 546 547 extern void async_call_share_in(async_call_t *, async_call_data_t *, 548 size_t, sysarg_t, unsigned int *, void **); 549 extern void async_call_share_out(async_call_t *, async_call_data_t *, 550 void *, unsigned int); 551 552 // TODO: connect me to, connect to me, vfs handle, etc. 553 494 554 #endif 495 555 -
uspace/lib/c/include/sys/time.h
r8404342 r9c16c36 76 76 extern void tv_add_diff(struct timeval *, suseconds_t); 77 77 extern void tv_add(struct timeval *, struct timeval *); 78 extern suseconds_t tv_sub_diff( struct timeval *,struct timeval *);78 extern suseconds_t tv_sub_diff(const struct timeval *, const struct timeval *); 79 79 extern void tv_sub(struct timeval *, struct timeval *); 80 extern int tv_gt( struct timeval *,struct timeval *);81 extern int tv_gteq( struct timeval *,struct timeval *);80 extern int tv_gt(const struct timeval *, const struct timeval *); 81 extern int tv_gteq(const struct timeval *, const struct timeval *); 82 82 extern void gettimeofday(struct timeval *, struct timezone *); 83 83 extern void getuptime(struct timeval *);
Note:
See TracChangeset
for help on using the changeset viewer.