Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 49a796f1 in mainline


Ignore:
Timestamp:
2018-05-31T16:11:01Z (3 years ago)
Author:
Jiří Zárevúcky <jiri.zarevucky@…>
Branches:
master
Children:
c8afd5a
Parents:
fda19b8
git-author:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-05-31 15:19:10)
git-committer:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-05-31 16:11:01)
Message:

Split the async framework into several parts.

This segregates existing code into three separate files,
to make the async framework easier to navigate and understand.

Location:
uspace/lib/c
Files:
2 added
5 edited
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/Makefile

    rfda19b8 r49a796f1  
    134134        generic/ipc.c \
    135135        generic/ns.c \
    136         generic/async.c \
     136        generic/async/client.c \
     137        generic/async/server.c \
     138        generic/async/ports.c \
    137139        generic/loader.c \
    138140        generic/getopt.c \
  • uspace/lib/c/generic/async/server.c

    rfda19b8 r49a796f1  
    9898#include <ipc/ipc.h>
    9999#include <async.h>
    100 #include "private/async.h"
     100#include "../private/async.h"
    101101#undef LIBC_ASYNC_C_
    102102
     
    119119#include <as.h>
    120120#include <abi/mm/as.h>
    121 #include "private/libc.h"
    122 
    123 /** Session data */
    124 struct async_sess {
    125         /** List of inactive exchanges */
    126         list_t exch_list;
    127 
    128         /** Session interface */
    129         iface_t iface;
    130 
    131         /** Exchange management style */
    132         exch_mgmt_t mgmt;
    133 
    134         /** Session identification */
    135         cap_phone_handle_t phone;
    136 
    137         /** First clone connection argument */
    138         sysarg_t arg1;
    139 
    140         /** Second clone connection argument */
    141         sysarg_t arg2;
    142 
    143         /** Third clone connection argument */
    144         sysarg_t arg3;
    145 
    146         /** Exchange mutex */
    147         fibril_mutex_t mutex;
    148 
    149         /** Number of opened exchanges */
    150         atomic_t refcnt;
    151 
    152         /** Mutex for stateful connections */
    153         fibril_mutex_t remote_state_mtx;
    154 
    155         /** Data for stateful connections */
    156         void *remote_state_data;
    157 };
    158 
    159 /** Exchange data */
    160 struct async_exch {
    161         /** Link into list of inactive exchanges */
    162         link_t sess_link;
    163 
    164         /** Link into global list of inactive exchanges */
    165         link_t global_link;
    166 
    167         /** Session pointer */
    168         async_sess_t *sess;
    169 
    170         /** Exchange identification */
    171         cap_phone_handle_t phone;
    172 };
     121#include "../private/libc.h"
    173122
    174123/** Async framework global futex */
     
    177126/** Number of threads waiting for IPC in the kernel. */
    178127atomic_t threads_in_ipc_wait = { 0 };
    179 
    180 /** Naming service session */
    181 async_sess_t *session_ns;
    182128
    183129/** Call data */
     
    188134        ipc_call_t call;
    189135} msg_t;
    190 
    191 /** Message data */
    192 typedef struct {
    193         awaiter_t wdata;
    194 
    195         /** If reply was received. */
    196         bool done;
    197 
    198         /** If the message / reply should be discarded on arrival. */
    199         bool forget;
    200 
    201         /** If already destroyed. */
    202         bool destroyed;
    203 
    204         /** Pointer to where the answer data is stored. */
    205         ipc_call_t *dataptr;
    206 
    207         errno_t retval;
    208 } amsg_t;
    209136
    210137/* Client connection data */
     
    252179} connection_t;
    253180
    254 /** Interface data */
    255 typedef struct {
    256         ht_link_t link;
    257 
    258         /** Interface ID */
    259         iface_t iface;
    260 
    261         /** Futex protecting the hash table */
    262         futex_t futex;
    263 
    264         /** Interface ports */
    265         hash_table_t port_hash_table;
    266 
    267         /** Next available port ID */
    268         port_id_t port_id_avail;
    269 } interface_t;
    270 
    271 /* Port data */
    272 typedef struct {
    273         ht_link_t link;
    274 
    275         /** Port ID */
    276         port_id_t id;
    277 
    278         /** Port connection handler */
    279         async_port_handler_t handler;
    280 
    281         /** Client data */
    282         void *data;
    283 } port_t;
    284 
    285181/* Notification data */
    286182typedef struct {
     
    299195/** Identifier of the incoming connection handled by the current fibril. */
    300196static fibril_local connection_t *fibril_connection;
    301 
    302 static void to_event_initialize(to_event_t *to)
    303 {
    304         struct timeval tv = { 0, 0 };
    305 
    306         to->inlist = false;
    307         to->occurred = false;
    308         link_initialize(&to->link);
    309         to->expires = tv;
    310 }
    311 
    312 static void wu_event_initialize(wu_event_t *wu)
    313 {
    314         wu->inlist = false;
    315         link_initialize(&wu->link);
    316 }
    317 
    318 void awaiter_initialize(awaiter_t *aw)
    319 {
    320         aw->fid = 0;
    321         aw->active = false;
    322         to_event_initialize(&aw->to_event);
    323         wu_event_initialize(&aw->wu_event);
    324 }
    325 
    326 static amsg_t *amsg_create(void)
    327 {
    328         amsg_t *msg = malloc(sizeof(amsg_t));
    329         if (msg) {
    330                 msg->done = false;
    331                 msg->forget = false;
    332                 msg->destroyed = false;
    333                 msg->dataptr = NULL;
    334                 msg->retval = EINVAL;
    335                 awaiter_initialize(&msg->wdata);
    336         }
    337 
    338         return msg;
    339 }
    340 
    341 static void amsg_destroy(amsg_t *msg)
    342 {
    343         assert(!msg->destroyed);
    344         msg->destroyed = true;
    345         free(msg);
    346 }
    347197
    348198static void *default_client_data_constructor(void)
     
    370220        assert(async_client_data_destroy == default_client_data_destructor);
    371221        async_client_data_destroy = dtor;
    372 }
    373 
    374 /** Default fallback fibril function.
    375  *
    376  * This fallback fibril function gets called on incomming connections that do
    377  * not have a specific handler defined.
    378  *
    379  * @param chandle  Handle of the incoming call.
    380  * @param call     Data of the incoming call.
    381  * @param arg      Local argument
    382  *
    383  */
    384 static void default_fallback_port_handler(cap_call_handle_t chandle,
    385     ipc_call_t *call, void *arg)
    386 {
    387         ipc_answer_0(chandle, ENOENT);
    388 }
    389 
    390 static async_port_handler_t fallback_port_handler =
    391     default_fallback_port_handler;
    392 static void *fallback_port_data = NULL;
    393 
    394 static hash_table_t interface_hash_table;
    395 
    396 static size_t interface_key_hash(void *key)
    397 {
    398         iface_t iface = *(iface_t *) key;
    399         return iface;
    400 }
    401 
    402 static size_t interface_hash(const ht_link_t *item)
    403 {
    404         interface_t *interface = hash_table_get_inst(item, interface_t, link);
    405         return interface_key_hash(&interface->iface);
    406 }
    407 
    408 static bool interface_key_equal(void *key, const ht_link_t *item)
    409 {
    410         iface_t iface = *(iface_t *) key;
    411         interface_t *interface = hash_table_get_inst(item, interface_t, link);
    412         return iface == interface->iface;
    413 }
    414 
    415 /** Operations for the port hash table. */
    416 static hash_table_ops_t interface_hash_table_ops = {
    417         .hash = interface_hash,
    418         .key_hash = interface_key_hash,
    419         .key_equal = interface_key_equal,
    420         .equal = NULL,
    421         .remove_callback = NULL
    422 };
    423 
    424 static size_t port_key_hash(void *key)
    425 {
    426         port_id_t port_id = *(port_id_t *) key;
    427         return port_id;
    428 }
    429 
    430 static size_t port_hash(const ht_link_t *item)
    431 {
    432         port_t *port = hash_table_get_inst(item, port_t, link);
    433         return port_key_hash(&port->id);
    434 }
    435 
    436 static bool port_key_equal(void *key, const ht_link_t *item)
    437 {
    438         port_id_t port_id = *(port_id_t *) key;
    439         port_t *port = hash_table_get_inst(item, port_t, link);
    440         return port_id == port->id;
    441 }
    442 
    443 /** Operations for the port hash table. */
    444 static hash_table_ops_t port_hash_table_ops = {
    445         .hash = port_hash,
    446         .key_hash = port_key_hash,
    447         .key_equal = port_key_equal,
    448         .equal = NULL,
    449         .remove_callback = NULL
    450 };
    451 
    452 static interface_t *async_new_interface(iface_t iface)
    453 {
    454         interface_t *interface =
    455             (interface_t *) malloc(sizeof(interface_t));
    456         if (!interface)
    457                 return NULL;
    458 
    459         bool ret = hash_table_create(&interface->port_hash_table, 0, 0,
    460             &port_hash_table_ops);
    461         if (!ret) {
    462                 free(interface);
    463                 return NULL;
    464         }
    465 
    466         interface->iface = iface;
    467         futex_initialize(&interface->futex, 1);
    468         interface->port_id_avail = 0;
    469 
    470         hash_table_insert(&interface_hash_table, &interface->link);
    471 
    472         return interface;
    473 }
    474 
    475 static port_t *async_new_port(interface_t *interface,
    476     async_port_handler_t handler, void *data)
    477 {
    478         port_t *port = (port_t *) malloc(sizeof(port_t));
    479         if (!port)
    480                 return NULL;
    481 
    482         futex_down(&interface->futex);
    483 
    484         port_id_t id = interface->port_id_avail;
    485         interface->port_id_avail++;
    486 
    487         port->id = id;
    488         port->handler = handler;
    489         port->data = data;
    490 
    491         hash_table_insert(&interface->port_hash_table, &port->link);
    492 
    493         futex_up(&interface->futex);
    494 
    495         return port;
    496 }
    497 
    498 /** Mutex protecting inactive_exch_list and avail_phone_cv.
    499  *
    500  */
    501 static FIBRIL_MUTEX_INITIALIZE(async_sess_mutex);
    502 
    503 /** List of all currently inactive exchanges.
    504  *
    505  */
    506 static LIST_INITIALIZE(inactive_exch_list);
    507 
    508 /** Condition variable to wait for a phone to become available.
    509  *
    510  */
    511 static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
    512 
    513 static errno_t async_create_port_internal(iface_t iface,
    514     async_port_handler_t handler, void *data, port_id_t *port_id)
    515 {
    516         interface_t *interface;
    517 
    518         futex_down(&async_futex);
    519 
    520         ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
    521         if (link)
    522                 interface = hash_table_get_inst(link, interface_t, link);
    523         else
    524                 interface = async_new_interface(iface);
    525 
    526         if (!interface) {
    527                 futex_up(&async_futex);
    528                 return ENOMEM;
    529         }
    530 
    531         port_t *port = async_new_port(interface, handler, data);
    532         if (!port) {
    533                 futex_up(&async_futex);
    534                 return ENOMEM;
    535         }
    536 
    537         *port_id = port->id;
    538 
    539         futex_up(&async_futex);
    540 
    541         return EOK;
    542 }
    543 
    544 errno_t async_create_port(iface_t iface, async_port_handler_t handler,
    545     void *data, port_id_t *port_id)
    546 {
    547         if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
    548                 return EINVAL;
    549 
    550         return async_create_port_internal(iface, handler, data, port_id);
    551 }
    552 
    553 void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
    554 {
    555         assert(handler != NULL);
    556 
    557         fallback_port_handler = handler;
    558         fallback_port_data = data;
    559222}
    560223
     
    1295958}
    1296959
    1297 static port_t *async_find_port(iface_t iface, port_id_t port_id)
    1298 {
    1299         port_t *port = NULL;
    1300 
    1301         futex_down(&async_futex);
    1302 
    1303         ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
    1304         if (link) {
    1305                 interface_t *interface =
    1306                     hash_table_get_inst(link, interface_t, link);
    1307 
    1308                 link = hash_table_find(&interface->port_hash_table, &port_id);
    1309                 if (link)
    1310                         port = hash_table_get_inst(link, port_t, link);
    1311         }
    1312 
    1313         futex_up(&async_futex);
    1314 
    1315         return port;
    1316 }
    1317 
    1318960/** Handle a call that was received.
    1319961 *
     
    13601002                sysarg_t in_phone_hash = IPC_GET_ARG5(*call);
    13611003
    1362                 async_port_handler_t handler = fallback_port_handler;
    1363                 void *data = fallback_port_data;
    1364 
    1365                 // TODO: Currently ignores all ports but the first one
    1366                 port_t *port = async_find_port(iface, 0);
    1367                 if (port) {
    1368                         handler = port->handler;
    1369                         data = port->data;
    1370                 }
     1004                // TODO: Currently ignores all ports but the first one.
     1005                void *data;
     1006                async_port_handler_t handler =
     1007                    async_get_port_handler(iface, 0, &data);
    13711008
    13721009                async_new_connection(call->in_task_id, in_phone_hash, chandle,
     
    15361173 *
    15371174 */
    1538 void __async_init(void)
    1539 {
    1540         if (!hash_table_create(&interface_hash_table, 0, 0,
    1541             &interface_hash_table_ops))
    1542                 abort();
    1543 
     1175void __async_server_init(void)
     1176{
    15441177        if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops))
    15451178                abort();
     
    15511184            &notification_hash_table_ops))
    15521185                abort();
    1553 
    1554         session_ns = (async_sess_t *) malloc(sizeof(async_sess_t));
    1555         if (session_ns == NULL)
    1556                 abort();
    1557 
    1558         session_ns->iface = 0;
    1559         session_ns->mgmt = EXCHANGE_ATOMIC;
    1560         session_ns->phone = PHONE_NS;
    1561         session_ns->arg1 = 0;
    1562         session_ns->arg2 = 0;
    1563         session_ns->arg3 = 0;
    1564 
    1565         fibril_mutex_initialize(&session_ns->remote_state_mtx);
    1566         session_ns->remote_state_data = NULL;
    1567 
    1568         list_initialize(&session_ns->exch_list);
    1569         fibril_mutex_initialize(&session_ns->mutex);
    1570         atomic_set(&session_ns->refcnt, 0);
    1571 }
    1572 
    1573 /** Reply received callback.
    1574  *
    1575  * This function is called whenever a reply for an asynchronous message sent out
    1576  * by the asynchronous framework is received.
    1577  *
    1578  * Notify the fibril which is waiting for this message that it has arrived.
    1579  *
    1580  * @param arg    Pointer to the asynchronous message record.
    1581  * @param retval Value returned in the answer.
    1582  * @param data   Call data of the answer.
    1583  *
    1584  */
    1585 void reply_received(void *arg, errno_t retval, ipc_call_t *data)
    1586 {
    1587         assert(arg);
    1588 
    1589         futex_down(&async_futex);
    1590 
    1591         amsg_t *msg = (amsg_t *) arg;
    1592         msg->retval = retval;
    1593 
    1594         /* Copy data after futex_down, just in case the call was detached */
    1595         if ((msg->dataptr) && (data))
    1596                 *msg->dataptr = *data;
    1597 
    1598         write_barrier();
    1599 
    1600         /* Remove message from timeout list */
    1601         if (msg->wdata.to_event.inlist)
    1602                 list_remove(&msg->wdata.to_event.link);
    1603 
    1604         msg->done = true;
    1605 
    1606         if (msg->forget) {
    1607                 assert(msg->wdata.active);
    1608                 amsg_destroy(msg);
    1609         } else if (!msg->wdata.active) {
    1610                 msg->wdata.active = true;
    1611                 fibril_add_ready(msg->wdata.fid);
    1612         }
    1613 
    1614         futex_up(&async_futex);
    1615 }
    1616 
    1617 /** Send message and return id of the sent message.
    1618  *
    1619  * The return value can be used as input for async_wait() to wait for
    1620  * completion.
    1621  *
    1622  * @param exch    Exchange for sending the message.
    1623  * @param imethod Service-defined interface and method.
    1624  * @param arg1    Service-defined payload argument.
    1625  * @param arg2    Service-defined payload argument.
    1626  * @param arg3    Service-defined payload argument.
    1627  * @param arg4    Service-defined payload argument.
    1628  * @param dataptr If non-NULL, storage where the reply data will be stored.
    1629  *
    1630  * @return Hash of the sent message or 0 on error.
    1631  *
    1632  */
    1633 aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    1634     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    1635 {
    1636         if (exch == NULL)
    1637                 return 0;
    1638 
    1639         amsg_t *msg = amsg_create();
    1640         if (msg == NULL)
    1641                 return 0;
    1642 
    1643         msg->dataptr = dataptr;
    1644         msg->wdata.active = true;
    1645 
    1646         ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
    1647             reply_received);
    1648 
    1649         return (aid_t) msg;
    1650 }
    1651 
    1652 /** Send message and return id of the sent message
    1653  *
    1654  * The return value can be used as input for async_wait() to wait for
    1655  * completion.
    1656  *
    1657  * @param exch    Exchange for sending the message.
    1658  * @param imethod Service-defined interface and method.
    1659  * @param arg1    Service-defined payload argument.
    1660  * @param arg2    Service-defined payload argument.
    1661  * @param arg3    Service-defined payload argument.
    1662  * @param arg4    Service-defined payload argument.
    1663  * @param arg5    Service-defined payload argument.
    1664  * @param dataptr If non-NULL, storage where the reply data will be
    1665  *                stored.
    1666  *
    1667  * @return Hash of the sent message or 0 on error.
    1668  *
    1669  */
    1670 aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    1671     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    1672     ipc_call_t *dataptr)
    1673 {
    1674         if (exch == NULL)
    1675                 return 0;
    1676 
    1677         amsg_t *msg = amsg_create();
    1678         if (msg == NULL)
    1679                 return 0;
    1680 
    1681         msg->dataptr = dataptr;
    1682         msg->wdata.active = true;
    1683 
    1684         ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
    1685             msg, reply_received);
    1686 
    1687         return (aid_t) msg;
    1688 }
    1689 
    1690 /** Wait for a message sent by the async framework.
    1691  *
    1692  * @param amsgid Hash of the message to wait for.
    1693  * @param retval Pointer to storage where the retval of the answer will
    1694  *               be stored.
    1695  *
    1696  */
    1697 void async_wait_for(aid_t amsgid, errno_t *retval)
    1698 {
    1699         assert(amsgid);
    1700 
    1701         amsg_t *msg = (amsg_t *) amsgid;
    1702 
    1703         futex_down(&async_futex);
    1704 
    1705         assert(!msg->forget);
    1706         assert(!msg->destroyed);
    1707 
    1708         if (msg->done) {
    1709                 futex_up(&async_futex);
    1710                 goto done;
    1711         }
    1712 
    1713         msg->wdata.fid = fibril_get_id();
    1714         msg->wdata.active = false;
    1715         msg->wdata.to_event.inlist = false;
    1716 
    1717         /* Leave the async_futex locked when entering this function */
    1718         fibril_switch(FIBRIL_TO_MANAGER);
    1719 
    1720         /* Futex is up automatically after fibril_switch */
    1721 
    1722 done:
    1723         if (retval)
    1724                 *retval = msg->retval;
    1725 
    1726         amsg_destroy(msg);
    1727 }
    1728 
    1729 /** Wait for a message sent by the async framework, timeout variant.
    1730  *
    1731  * If the wait times out, the caller may choose to either wait again by calling
    1732  * async_wait_for() or async_wait_timeout(), or forget the message via
    1733  * async_forget().
    1734  *
    1735  * @param amsgid  Hash of the message to wait for.
    1736  * @param retval  Pointer to storage where the retval of the answer will
    1737  *                be stored.
    1738  * @param timeout Timeout in microseconds.
    1739  *
    1740  * @return Zero on success, ETIMEOUT if the timeout has expired.
    1741  *
    1742  */
    1743 errno_t async_wait_timeout(aid_t amsgid, errno_t *retval, suseconds_t timeout)
    1744 {
    1745         assert(amsgid);
    1746 
    1747         amsg_t *msg = (amsg_t *) amsgid;
    1748 
    1749         futex_down(&async_futex);
    1750 
    1751         assert(!msg->forget);
    1752         assert(!msg->destroyed);
    1753 
    1754         if (msg->done) {
    1755                 futex_up(&async_futex);
    1756                 goto done;
    1757         }
    1758 
    1759         /*
    1760          * Negative timeout is converted to zero timeout to avoid
    1761          * using tv_add with negative augmenter.
    1762          */
    1763         if (timeout < 0)
    1764                 timeout = 0;
    1765 
    1766         getuptime(&msg->wdata.to_event.expires);
    1767         tv_add_diff(&msg->wdata.to_event.expires, timeout);
    1768 
    1769         /*
    1770          * Current fibril is inserted as waiting regardless of the
    1771          * "size" of the timeout.
    1772          *
    1773          * Checking for msg->done and immediately bailing out when
    1774          * timeout == 0 would mean that the manager fibril would never
    1775          * run (consider single threaded program).
    1776          * Thus the IPC answer would be never retrieved from the kernel.
    1777          *
    1778          * Notice that the actual delay would be very small because we
    1779          * - switch to manager fibril
    1780          * - the manager sees expired timeout
    1781          * - and thus adds us back to ready queue
    1782          * - manager switches back to some ready fibril
    1783          *   (prior it, it checks for incoming IPC).
    1784          *
    1785          */
    1786         msg->wdata.fid = fibril_get_id();
    1787         msg->wdata.active = false;
    1788         async_insert_timeout(&msg->wdata);
    1789 
    1790         /* Leave the async_futex locked when entering this function */
    1791         fibril_switch(FIBRIL_TO_MANAGER);
    1792 
    1793         /* Futex is up automatically after fibril_switch */
    1794 
    1795         if (!msg->done)
    1796                 return ETIMEOUT;
    1797 
    1798 done:
    1799         if (retval)
    1800                 *retval = msg->retval;
    1801 
    1802         amsg_destroy(msg);
    1803 
    1804         return 0;
    1805 }
    1806 
    1807 /** Discard the message / reply on arrival.
    1808  *
    1809  * The message will be marked to be discarded once the reply arrives in
    1810  * reply_received(). It is not allowed to call async_wait_for() or
    1811  * async_wait_timeout() on this message after a call to this function.
    1812  *
    1813  * @param amsgid  Hash of the message to forget.
    1814  */
    1815 void async_forget(aid_t amsgid)
    1816 {
    1817         amsg_t *msg = (amsg_t *) amsgid;
    1818 
    1819         assert(msg);
    1820         assert(!msg->forget);
    1821         assert(!msg->destroyed);
    1822 
    1823         futex_down(&async_futex);
    1824 
    1825         if (msg->done) {
    1826                 amsg_destroy(msg);
    1827         } else {
    1828                 msg->dataptr = NULL;
    1829                 msg->forget = true;
    1830         }
    1831 
    1832         futex_up(&async_futex);
    1833 }
    1834 
    1835 /** Wait for specified time.
    1836  *
    1837  * The current fibril is suspended but the thread continues to execute.
    1838  *
    1839  * @param timeout Duration of the wait in microseconds.
    1840  *
    1841  */
    1842 void async_usleep(suseconds_t timeout)
    1843 {
    1844         awaiter_t awaiter;
    1845         awaiter_initialize(&awaiter);
    1846 
    1847         awaiter.fid = fibril_get_id();
    1848 
    1849         getuptime(&awaiter.to_event.expires);
    1850         tv_add_diff(&awaiter.to_event.expires, timeout);
    1851 
    1852         futex_down(&async_futex);
    1853 
    1854         async_insert_timeout(&awaiter);
    1855 
    1856         /* Leave the async_futex locked when entering this function */
    1857         fibril_switch(FIBRIL_TO_MANAGER);
    1858 
    1859         /* Futex is up automatically after fibril_switch() */
    1860 }
    1861 
    1862 /** Delay execution for the specified number of seconds
    1863  *
    1864  * @param sec Number of seconds to sleep
    1865  */
    1866 void async_sleep(unsigned int sec)
    1867 {
    1868         /*
    1869          * Sleep in 1000 second steps to support
    1870          * full argument range
    1871          */
    1872 
    1873         while (sec > 0) {
    1874                 unsigned int period = (sec > 1000) ? 1000 : sec;
    1875 
    1876                 async_usleep(period * 1000000);
    1877                 sec -= period;
    1878         }
    1879 }
    1880 
    1881 /** Pseudo-synchronous message sending - fast version.
    1882  *
    1883  * Send message asynchronously and return only after the reply arrives.
    1884  *
    1885  * This function can only transfer 4 register payload arguments. For
    1886  * transferring more arguments, see the slower async_req_slow().
    1887  *
    1888  * @param exch    Exchange for sending the message.
    1889  * @param imethod Interface and method of the call.
    1890  * @param arg1    Service-defined payload argument.
    1891  * @param arg2    Service-defined payload argument.
    1892  * @param arg3    Service-defined payload argument.
    1893  * @param arg4    Service-defined payload argument.
    1894  * @param r1      If non-NULL, storage for the 1st reply argument.
    1895  * @param r2      If non-NULL, storage for the 2nd reply argument.
    1896  * @param r3      If non-NULL, storage for the 3rd reply argument.
    1897  * @param r4      If non-NULL, storage for the 4th reply argument.
    1898  * @param r5      If non-NULL, storage for the 5th reply argument.
    1899  *
    1900  * @return Return code of the reply or an error code.
    1901  *
    1902  */
    1903 errno_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    1904     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
    1905     sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    1906 {
    1907         if (exch == NULL)
    1908                 return ENOENT;
    1909 
    1910         ipc_call_t result;
    1911         aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
    1912             &result);
    1913 
    1914         errno_t rc;
    1915         async_wait_for(aid, &rc);
    1916 
    1917         if (r1)
    1918                 *r1 = IPC_GET_ARG1(result);
    1919 
    1920         if (r2)
    1921                 *r2 = IPC_GET_ARG2(result);
    1922 
    1923         if (r3)
    1924                 *r3 = IPC_GET_ARG3(result);
    1925 
    1926         if (r4)
    1927                 *r4 = IPC_GET_ARG4(result);
    1928 
    1929         if (r5)
    1930                 *r5 = IPC_GET_ARG5(result);
    1931 
    1932         return rc;
    1933 }
    1934 
    1935 /** Pseudo-synchronous message sending - slow version.
    1936  *
    1937  * Send message asynchronously and return only after the reply arrives.
    1938  *
    1939  * @param exch    Exchange for sending the message.
    1940  * @param imethod Interface and method of the call.
    1941  * @param arg1    Service-defined payload argument.
    1942  * @param arg2    Service-defined payload argument.
    1943  * @param arg3    Service-defined payload argument.
    1944  * @param arg4    Service-defined payload argument.
    1945  * @param arg5    Service-defined payload argument.
    1946  * @param r1      If non-NULL, storage for the 1st reply argument.
    1947  * @param r2      If non-NULL, storage for the 2nd reply argument.
    1948  * @param r3      If non-NULL, storage for the 3rd reply argument.
    1949  * @param r4      If non-NULL, storage for the 4th reply argument.
    1950  * @param r5      If non-NULL, storage for the 5th reply argument.
    1951  *
    1952  * @return Return code of the reply or an error code.
    1953  *
    1954  */
    1955 errno_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    1956     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
    1957     sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    1958 {
    1959         if (exch == NULL)
    1960                 return ENOENT;
    1961 
    1962         ipc_call_t result;
    1963         aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
    1964             &result);
    1965 
    1966         errno_t rc;
    1967         async_wait_for(aid, &rc);
    1968 
    1969         if (r1)
    1970                 *r1 = IPC_GET_ARG1(result);
    1971 
    1972         if (r2)
    1973                 *r2 = IPC_GET_ARG2(result);
    1974 
    1975         if (r3)
    1976                 *r3 = IPC_GET_ARG3(result);
    1977 
    1978         if (r4)
    1979                 *r4 = IPC_GET_ARG4(result);
    1980 
    1981         if (r5)
    1982                 *r5 = IPC_GET_ARG5(result);
    1983 
    1984         return rc;
    1985 }
    1986 
    1987 void async_msg_0(async_exch_t *exch, sysarg_t imethod)
    1988 {
    1989         if (exch != NULL)
    1990                 ipc_call_async_0(exch->phone, imethod, NULL, NULL);
    1991 }
    1992 
    1993 void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
    1994 {
    1995         if (exch != NULL)
    1996                 ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL);
    1997 }
    1998 
    1999 void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    2000     sysarg_t arg2)
    2001 {
    2002         if (exch != NULL)
    2003                 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL);
    2004 }
    2005 
    2006 void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    2007     sysarg_t arg2, sysarg_t arg3)
    2008 {
    2009         if (exch != NULL)
    2010                 ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
    2011                     NULL);
    2012 }
    2013 
    2014 void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    2015     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
    2016 {
    2017         if (exch != NULL)
    2018                 ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
    2019                     NULL, NULL);
    2020 }
    2021 
    2022 void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    2023     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
    2024 {
    2025         if (exch != NULL)
    2026                 ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
    2027                     arg5, NULL, NULL);
    20281186}
    20291187
     
    21121270}
    21131271
    2114 static errno_t async_connect_me_to_internal(cap_phone_handle_t phone,
    2115     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
    2116     cap_phone_handle_t *out_phone)
    2117 {
    2118         ipc_call_t result;
    2119 
    2120         // XXX: Workaround for GCC's inability to infer association between
    2121         // rc == EOK and *out_phone being assigned.
    2122         *out_phone = CAP_NIL;
    2123 
    2124         amsg_t *msg = amsg_create();
    2125         if (!msg)
    2126                 return ENOENT;
    2127 
    2128         msg->dataptr = &result;
    2129         msg->wdata.active = true;
    2130 
    2131         ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
    2132             msg, reply_received);
    2133 
    2134         errno_t rc;
    2135         async_wait_for((aid_t) msg, &rc);
    2136 
    2137         if (rc != EOK)
    2138                 return rc;
    2139 
    2140         *out_phone = (cap_phone_handle_t) IPC_GET_ARG5(result);
    2141         return EOK;
    2142 }
    2143 
    2144 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    2145  *
    2146  * Ask through for a new connection to some service.
    2147  *
    2148  * @param mgmt Exchange management style.
    2149  * @param exch Exchange for sending the message.
    2150  * @param arg1 User defined argument.
    2151  * @param arg2 User defined argument.
    2152  * @param arg3 User defined argument.
    2153  *
    2154  * @return New session on success or NULL on error.
    2155  *
    2156  */
    2157 async_sess_t *async_connect_me_to(exch_mgmt_t mgmt, async_exch_t *exch,
    2158     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
    2159 {
    2160         if (exch == NULL) {
    2161                 errno = ENOENT;
    2162                 return NULL;
    2163         }
    2164 
    2165         async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
    2166         if (sess == NULL) {
    2167                 errno = ENOMEM;
    2168                 return NULL;
    2169         }
    2170 
    2171         cap_phone_handle_t phone;
    2172         errno_t rc = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
    2173             0, &phone);
    2174         if (rc != EOK) {
    2175                 errno = rc;
    2176                 free(sess);
    2177                 return NULL;
    2178         }
    2179 
    2180         sess->iface = 0;
    2181         sess->mgmt = mgmt;
    2182         sess->phone = phone;
    2183         sess->arg1 = arg1;
    2184         sess->arg2 = arg2;
    2185         sess->arg3 = arg3;
    2186 
    2187         fibril_mutex_initialize(&sess->remote_state_mtx);
    2188         sess->remote_state_data = NULL;
    2189 
    2190         list_initialize(&sess->exch_list);
    2191         fibril_mutex_initialize(&sess->mutex);
    2192         atomic_set(&sess->refcnt, 0);
    2193 
    2194         return sess;
    2195 }
    2196 
    2197 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    2198  *
    2199  * Ask through phone for a new connection to some service and block until
    2200  * success.
    2201  *
    2202  * @param exch  Exchange for sending the message.
    2203  * @param iface Connection interface.
    2204  * @param arg2  User defined argument.
    2205  * @param arg3  User defined argument.
    2206  *
    2207  * @return New session on success or NULL on error.
    2208  *
    2209  */
    2210 async_sess_t *async_connect_me_to_iface(async_exch_t *exch, iface_t iface,
    2211     sysarg_t arg2, sysarg_t arg3)
    2212 {
    2213         if (exch == NULL) {
    2214                 errno = ENOENT;
    2215                 return NULL;
    2216         }
    2217 
    2218         async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
    2219         if (sess == NULL) {
    2220                 errno = ENOMEM;
    2221                 return NULL;
    2222         }
    2223 
    2224         cap_phone_handle_t phone;
    2225         errno_t rc = async_connect_me_to_internal(exch->phone, iface, arg2,
    2226             arg3, 0, &phone);
    2227         if (rc != EOK) {
    2228                 errno = rc;
    2229                 free(sess);
    2230                 return NULL;
    2231         }
    2232 
    2233         sess->iface = iface;
    2234         sess->phone = phone;
    2235         sess->arg1 = iface;
    2236         sess->arg2 = arg2;
    2237         sess->arg3 = arg3;
    2238 
    2239         fibril_mutex_initialize(&sess->remote_state_mtx);
    2240         sess->remote_state_data = NULL;
    2241 
    2242         list_initialize(&sess->exch_list);
    2243         fibril_mutex_initialize(&sess->mutex);
    2244         atomic_set(&sess->refcnt, 0);
    2245 
    2246         return sess;
    2247 }
    2248 
    2249 /** Set arguments for new connections.
    2250  *
    2251  * FIXME This is an ugly hack to work around the problem that parallel
    2252  * exchanges are implemented using parallel connections. When we create
    2253  * a callback session, the framework does not know arguments for the new
    2254  * connections.
    2255  *
    2256  * The proper solution seems to be to implement parallel exchanges using
    2257  * tagging.
    2258  */
    2259 void async_sess_args_set(async_sess_t *sess, sysarg_t arg1, sysarg_t arg2,
    2260     sysarg_t arg3)
    2261 {
    2262         sess->arg1 = arg1;
    2263         sess->arg2 = arg2;
    2264         sess->arg3 = arg3;
    2265 }
    2266 
    2267 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    2268  *
    2269  * Ask through phone for a new connection to some service and block until
    2270  * success.
    2271  *
    2272  * @param mgmt Exchange management style.
    2273  * @param exch Exchange for sending the message.
    2274  * @param arg1 User defined argument.
    2275  * @param arg2 User defined argument.
    2276  * @param arg3 User defined argument.
    2277  *
    2278  * @return New session on success or NULL on error.
    2279  *
    2280  */
    2281 async_sess_t *async_connect_me_to_blocking(exch_mgmt_t mgmt, async_exch_t *exch,
    2282     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
    2283 {
    2284         if (exch == NULL) {
    2285                 errno = ENOENT;
    2286                 return NULL;
    2287         }
    2288 
    2289         async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
    2290         if (sess == NULL) {
    2291                 errno = ENOMEM;
    2292                 return NULL;
    2293         }
    2294 
    2295         cap_phone_handle_t phone;
    2296         errno_t rc = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
    2297             IPC_FLAG_BLOCKING, &phone);
    2298 
    2299         if (rc != EOK) {
    2300                 errno = rc;
    2301                 free(sess);
    2302                 return NULL;
    2303         }
    2304 
    2305         sess->iface = 0;
    2306         sess->mgmt = mgmt;
    2307         sess->phone = phone;
    2308         sess->arg1 = arg1;
    2309         sess->arg2 = arg2;
    2310         sess->arg3 = arg3;
    2311 
    2312         fibril_mutex_initialize(&sess->remote_state_mtx);
    2313         sess->remote_state_data = NULL;
    2314 
    2315         list_initialize(&sess->exch_list);
    2316         fibril_mutex_initialize(&sess->mutex);
    2317         atomic_set(&sess->refcnt, 0);
    2318 
    2319         return sess;
    2320 }
    2321 
    2322 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    2323  *
    2324  * Ask through phone for a new connection to some service and block until
    2325  * success.
    2326  *
    2327  * @param exch  Exchange for sending the message.
    2328  * @param iface Connection interface.
    2329  * @param arg2  User defined argument.
    2330  * @param arg3  User defined argument.
    2331  *
    2332  * @return New session on success or NULL on error.
    2333  *
    2334  */
    2335 async_sess_t *async_connect_me_to_blocking_iface(async_exch_t *exch, iface_t iface,
    2336     sysarg_t arg2, sysarg_t arg3)
    2337 {
    2338         if (exch == NULL) {
    2339                 errno = ENOENT;
    2340                 return NULL;
    2341         }
    2342 
    2343         async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
    2344         if (sess == NULL) {
    2345                 errno = ENOMEM;
    2346                 return NULL;
    2347         }
    2348 
    2349         cap_phone_handle_t phone;
    2350         errno_t rc = async_connect_me_to_internal(exch->phone, iface, arg2,
    2351             arg3, IPC_FLAG_BLOCKING, &phone);
    2352         if (rc != EOK) {
    2353                 errno = rc;
    2354                 free(sess);
    2355                 return NULL;
    2356         }
    2357 
    2358         sess->iface = iface;
    2359         sess->phone = phone;
    2360         sess->arg1 = iface;
    2361         sess->arg2 = arg2;
    2362         sess->arg3 = arg3;
    2363 
    2364         fibril_mutex_initialize(&sess->remote_state_mtx);
    2365         sess->remote_state_data = NULL;
    2366 
    2367         list_initialize(&sess->exch_list);
    2368         fibril_mutex_initialize(&sess->mutex);
    2369         atomic_set(&sess->refcnt, 0);
    2370 
    2371         return sess;
    2372 }
    2373 
    2374 /** Connect to a task specified by id.
    2375  *
    2376  */
    2377 async_sess_t *async_connect_kbox(task_id_t id)
    2378 {
    2379         async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
    2380         if (sess == NULL) {
    2381                 errno = ENOMEM;
    2382                 return NULL;
    2383         }
    2384 
    2385         cap_phone_handle_t phone;
    2386         errno_t rc = ipc_connect_kbox(id, &phone);
    2387         if (rc != EOK) {
    2388                 errno = rc;
    2389                 free(sess);
    2390                 return NULL;
    2391         }
    2392 
    2393         sess->iface = 0;
    2394         sess->mgmt = EXCHANGE_ATOMIC;
    2395         sess->phone = phone;
    2396         sess->arg1 = 0;
    2397         sess->arg2 = 0;
    2398         sess->arg3 = 0;
    2399 
    2400         fibril_mutex_initialize(&sess->remote_state_mtx);
    2401         sess->remote_state_data = NULL;
    2402 
    2403         list_initialize(&sess->exch_list);
    2404         fibril_mutex_initialize(&sess->mutex);
    2405         atomic_set(&sess->refcnt, 0);
    2406 
    2407         return sess;
    2408 }
    2409 
    2410 static errno_t async_hangup_internal(cap_phone_handle_t phone)
    2411 {
    2412         return ipc_hangup(phone);
    2413 }
    2414 
    2415 /** Wrapper for ipc_hangup.
    2416  *
    2417  * @param sess Session to hung up.
    2418  *
    2419  * @return Zero on success or an error code.
    2420  *
    2421  */
    2422 errno_t async_hangup(async_sess_t *sess)
    2423 {
    2424         async_exch_t *exch;
    2425 
    2426         assert(sess);
    2427 
    2428         if (atomic_get(&sess->refcnt) > 0)
    2429                 return EBUSY;
    2430 
    2431         fibril_mutex_lock(&async_sess_mutex);
    2432 
    2433         errno_t rc = async_hangup_internal(sess->phone);
    2434 
    2435         while (!list_empty(&sess->exch_list)) {
    2436                 exch = (async_exch_t *)
    2437                     list_get_instance(list_first(&sess->exch_list),
    2438                     async_exch_t, sess_link);
    2439 
    2440                 list_remove(&exch->sess_link);
    2441                 list_remove(&exch->global_link);
    2442                 async_hangup_internal(exch->phone);
    2443                 free(exch);
    2444         }
    2445 
    2446         free(sess);
    2447 
    2448         fibril_mutex_unlock(&async_sess_mutex);
    2449 
    2450         return rc;
    2451 }
    2452 
    24531272/** Interrupt one thread of this task from waiting for IPC. */
    24541273void async_poke(void)
    24551274{
    24561275        ipc_poke();
    2457 }
    2458 
    2459 /** Start new exchange in a session.
    2460  *
    2461  * @param session Session.
    2462  *
    2463  * @return New exchange or NULL on error.
    2464  *
    2465  */
    2466 async_exch_t *async_exchange_begin(async_sess_t *sess)
    2467 {
    2468         if (sess == NULL)
    2469                 return NULL;
    2470 
    2471         exch_mgmt_t mgmt = sess->mgmt;
    2472         if (sess->iface != 0)
    2473                 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
    2474 
    2475         async_exch_t *exch = NULL;
    2476 
    2477         fibril_mutex_lock(&async_sess_mutex);
    2478 
    2479         if (!list_empty(&sess->exch_list)) {
    2480                 /*
    2481                  * There are inactive exchanges in the session.
    2482                  */
    2483                 exch = (async_exch_t *)
    2484                     list_get_instance(list_first(&sess->exch_list),
    2485                     async_exch_t, sess_link);
    2486 
    2487                 list_remove(&exch->sess_link);
    2488                 list_remove(&exch->global_link);
    2489         } else {
    2490                 /*
    2491                  * There are no available exchanges in the session.
    2492                  */
    2493 
    2494                 if ((mgmt == EXCHANGE_ATOMIC) ||
    2495                     (mgmt == EXCHANGE_SERIALIZE)) {
    2496                         exch = (async_exch_t *) malloc(sizeof(async_exch_t));
    2497                         if (exch != NULL) {
    2498                                 link_initialize(&exch->sess_link);
    2499                                 link_initialize(&exch->global_link);
    2500                                 exch->sess = sess;
    2501                                 exch->phone = sess->phone;
    2502                         }
    2503                 } else if (mgmt == EXCHANGE_PARALLEL) {
    2504                         cap_phone_handle_t phone;
    2505                         errno_t rc;
    2506 
    2507                 retry:
    2508                         /*
    2509                          * Make a one-time attempt to connect a new data phone.
    2510                          */
    2511                         rc = async_connect_me_to_internal(sess->phone, sess->arg1,
    2512                             sess->arg2, sess->arg3, 0, &phone);
    2513                         if (rc == EOK) {
    2514                                 exch = (async_exch_t *) malloc(sizeof(async_exch_t));
    2515                                 if (exch != NULL) {
    2516                                         link_initialize(&exch->sess_link);
    2517                                         link_initialize(&exch->global_link);
    2518                                         exch->sess = sess;
    2519                                         exch->phone = phone;
    2520                                 } else
    2521                                         async_hangup_internal(phone);
    2522                         } else if (!list_empty(&inactive_exch_list)) {
    2523                                 /*
    2524                                  * We did not manage to connect a new phone. But we
    2525                                  * can try to close some of the currently inactive
    2526                                  * connections in other sessions and try again.
    2527                                  */
    2528                                 exch = (async_exch_t *)
    2529                                     list_get_instance(list_first(&inactive_exch_list),
    2530                                     async_exch_t, global_link);
    2531 
    2532                                 list_remove(&exch->sess_link);
    2533                                 list_remove(&exch->global_link);
    2534                                 async_hangup_internal(exch->phone);
    2535                                 free(exch);
    2536                                 goto retry;
    2537                         } else {
    2538                                 /*
    2539                                  * Wait for a phone to become available.
    2540                                  */
    2541                                 fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
    2542                                 goto retry;
    2543                         }
    2544                 }
    2545         }
    2546 
    2547         fibril_mutex_unlock(&async_sess_mutex);
    2548 
    2549         if (exch != NULL) {
    2550                 atomic_inc(&sess->refcnt);
    2551 
    2552                 if (mgmt == EXCHANGE_SERIALIZE)
    2553                         fibril_mutex_lock(&sess->mutex);
    2554         }
    2555 
    2556         return exch;
    2557 }
    2558 
    2559 /** Finish an exchange.
    2560  *
    2561  * @param exch Exchange to finish.
    2562  *
    2563  */
    2564 void async_exchange_end(async_exch_t *exch)
    2565 {
    2566         if (exch == NULL)
    2567                 return;
    2568 
    2569         async_sess_t *sess = exch->sess;
    2570         assert(sess != NULL);
    2571 
    2572         exch_mgmt_t mgmt = sess->mgmt;
    2573         if (sess->iface != 0)
    2574                 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
    2575 
    2576         atomic_dec(&sess->refcnt);
    2577 
    2578         if (mgmt == EXCHANGE_SERIALIZE)
    2579                 fibril_mutex_unlock(&sess->mutex);
    2580 
    2581         fibril_mutex_lock(&async_sess_mutex);
    2582 
    2583         list_append(&exch->sess_link, &sess->exch_list);
    2584         list_append(&exch->global_link, &inactive_exch_list);
    2585         fibril_condvar_signal(&avail_phone_cv);
    2586 
    2587         fibril_mutex_unlock(&async_sess_mutex);
    2588 }
    2589 
    2590 /** Wrapper for IPC_M_SHARE_IN calls using the async framework.
    2591  *
    2592  * @param exch  Exchange for sending the message.
    2593  * @param size  Size of the destination address space area.
    2594  * @param arg   User defined argument.
    2595  * @param flags Storage for the received flags. Can be NULL.
    2596  * @param dst   Address of the storage for the destination address space area
    2597  *              base address. Cannot be NULL.
    2598  *
    2599  * @return Zero on success or an error code from errno.h.
    2600  *
    2601  */
    2602 errno_t async_share_in_start(async_exch_t *exch, size_t size, sysarg_t arg,
    2603     unsigned int *flags, void **dst)
    2604 {
    2605         if (exch == NULL)
    2606                 return ENOENT;
    2607 
    2608         sysarg_t _flags = 0;
    2609         sysarg_t _dst = (sysarg_t) -1;
    2610         errno_t res = async_req_2_4(exch, IPC_M_SHARE_IN, (sysarg_t) size,
    2611             arg, NULL, &_flags, NULL, &_dst);
    2612 
    2613         if (flags)
    2614                 *flags = (unsigned int) _flags;
    2615 
    2616         *dst = (void *) _dst;
    2617         return res;
    26181276}
    26191277
     
    26681326}
    26691327
    2670 /** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
    2671  *
    2672  * @param exch  Exchange for sending the message.
    2673  * @param src   Source address space area base address.
    2674  * @param flags Flags to be used for sharing. Bits can be only cleared.
    2675  *
    2676  * @return Zero on success or an error code from errno.h.
    2677  *
    2678  */
    2679 errno_t async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
    2680 {
    2681         if (exch == NULL)
    2682                 return ENOENT;
    2683 
    2684         return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
    2685             (sysarg_t) flags);
    2686 }
    2687 
    26881328/** Wrapper for receiving the IPC_M_SHARE_OUT calls using the async framework.
    26891329 *
     
    27351375{
    27361376        return ipc_answer_2(chandle, EOK, (sysarg_t) _end, (sysarg_t) dst);
    2737 }
    2738 
    2739 /** Start IPC_M_DATA_READ using the async framework.
    2740  *
    2741  * @param exch    Exchange for sending the message.
    2742  * @param dst     Address of the beginning of the destination buffer.
    2743  * @param size    Size of the destination buffer (in bytes).
    2744  * @param dataptr Storage of call data (arg 2 holds actual data size).
    2745  *
    2746  * @return Hash of the sent message or 0 on error.
    2747  *
    2748  */
    2749 aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
    2750     ipc_call_t *dataptr)
    2751 {
    2752         return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
    2753             (sysarg_t) size, dataptr);
    2754 }
    2755 
    2756 /** Wrapper for IPC_M_DATA_READ calls using the async framework.
    2757  *
    2758  * @param exch Exchange for sending the message.
    2759  * @param dst  Address of the beginning of the destination buffer.
    2760  * @param size Size of the destination buffer.
    2761  *
    2762  * @return Zero on success or an error code from errno.h.
    2763  *
    2764  */
    2765 errno_t async_data_read_start(async_exch_t *exch, void *dst, size_t size)
    2766 {
    2767         if (exch == NULL)
    2768                 return ENOENT;
    2769 
    2770         return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
    2771             (sysarg_t) size);
    27721377}
    27731378
     
    28781483
    28791484        return (errno_t) rc;
    2880 }
    2881 
    2882 /** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
    2883  *
    2884  * @param exch Exchange for sending the message.
    2885  * @param src  Address of the beginning of the source buffer.
    2886  * @param size Size of the source buffer.
    2887  *
    2888  * @return Zero on success or an error code from errno.h.
    2889  *
    2890  */
    2891 errno_t async_data_write_start(async_exch_t *exch, const void *src, size_t size)
    2892 {
    2893         if (exch == NULL)
    2894                 return ENOENT;
    2895 
    2896         return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
    2897             (sysarg_t) size);
    28981485}
    28991486
     
    31901777}
    31911778
    3192 errno_t async_state_change_start(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
    3193     sysarg_t arg3, async_exch_t *other_exch)
    3194 {
    3195         return async_req_5_0(exch, IPC_M_STATE_CHANGE_AUTHORIZE,
    3196             arg1, arg2, arg3, 0, CAP_HANDLE_RAW(other_exch->phone));
    3197 }
    3198 
    31991779bool async_state_change_receive(cap_call_handle_t *chandle, sysarg_t *arg1,
    32001780    sysarg_t *arg2, sysarg_t *arg3)
     
    32241804}
    32251805
    3226 /** Lock and get session remote state
    3227  *
    3228  * Lock and get the local replica of the remote state
    3229  * in stateful sessions. The call should be paired
    3230  * with async_remote_state_release*().
    3231  *
    3232  * @param[in] sess Stateful session.
    3233  *
    3234  * @return Local replica of the remote state.
    3235  *
    3236  */
    3237 void *async_remote_state_acquire(async_sess_t *sess)
    3238 {
    3239         fibril_mutex_lock(&sess->remote_state_mtx);
    3240         return sess->remote_state_data;
    3241 }
    3242 
    3243 /** Update the session remote state
    3244  *
    3245  * Update the local replica of the remote state
    3246  * in stateful sessions. The remote state must
    3247  * be already locked.
    3248  *
    3249  * @param[in] sess  Stateful session.
    3250  * @param[in] state New local replica of the remote state.
    3251  *
    3252  */
    3253 void async_remote_state_update(async_sess_t *sess, void *state)
    3254 {
    3255         assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
    3256         sess->remote_state_data = state;
    3257 }
    3258 
    3259 /** Release the session remote state
    3260  *
    3261  * Unlock the local replica of the remote state
    3262  * in stateful sessions.
    3263  *
    3264  * @param[in] sess Stateful session.
    3265  *
    3266  */
    3267 void async_remote_state_release(async_sess_t *sess)
    3268 {
    3269         assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
    3270 
    3271         fibril_mutex_unlock(&sess->remote_state_mtx);
    3272 }
    3273 
    3274 /** Release the session remote state and end an exchange
    3275  *
    3276  * Unlock the local replica of the remote state
    3277  * in stateful sessions. This is convenience function
    3278  * which gets the session pointer from the exchange
    3279  * and also ends the exchange.
    3280  *
    3281  * @param[in] exch Stateful session's exchange.
    3282  *
    3283  */
    3284 void async_remote_state_release_exchange(async_exch_t *exch)
    3285 {
    3286         if (exch == NULL)
    3287                 return;
    3288 
    3289         async_sess_t *sess = exch->sess;
    3290         assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
    3291 
    3292         async_exchange_end(exch);
    3293         fibril_mutex_unlock(&sess->remote_state_mtx);
    3294 }
    3295 
    3296 void *async_as_area_create(void *base, size_t size, unsigned int flags,
    3297     async_sess_t *pager, sysarg_t id1, sysarg_t id2, sysarg_t id3)
    3298 {
    3299         as_area_pager_info_t pager_info = {
    3300                 .pager = pager->phone,
    3301                 .id1 = id1,
    3302                 .id2 = id2,
    3303                 .id3 = id3
    3304         };
    3305         return as_area_create(base, size, flags, &pager_info);
    3306 }
    3307 
    33081806/** @}
    33091807 */
  • uspace/lib/c/generic/fibril_synch.c

    rfda19b8 r49a796f1  
    5555         * fibril back to fruitful work.
    5656         */
    57         if (atomic_get(&threads_in_ipc_wait) > 0)
    58                 async_poke();
     57        async_poke();
    5958}
    6059
  • uspace/lib/c/generic/libc.c

    rfda19b8 r49a796f1  
    9595#endif
    9696
    97         __async_init();
     97        __async_server_init();
     98        __async_client_init();
     99        __async_ports_init();
    98100
    99101        /* The basic run-time environment is setup */
  • uspace/lib/c/generic/private/async.h

    rfda19b8 r49a796f1  
    8181} awaiter_t;
    8282
     83/** Session data */
     84struct async_sess {
     85        /** List of inactive exchanges */
     86        list_t exch_list;
     87
     88        /** Session interface */
     89        iface_t iface;
     90
     91        /** Exchange management style */
     92        exch_mgmt_t mgmt;
     93
     94        /** Session identification */
     95        cap_phone_handle_t phone;
     96
     97        /** First clone connection argument */
     98        sysarg_t arg1;
     99
     100        /** Second clone connection argument */
     101        sysarg_t arg2;
     102
     103        /** Third clone connection argument */
     104        sysarg_t arg3;
     105
     106        /** Exchange mutex */
     107        fibril_mutex_t mutex;
     108
     109        /** Number of opened exchanges */
     110        atomic_t refcnt;
     111
     112        /** Mutex for stateful connections */
     113        fibril_mutex_t remote_state_mtx;
     114
     115        /** Data for stateful connections */
     116        void *remote_state_data;
     117};
     118
     119/** Exchange data */
     120struct async_exch {
     121        /** Link into list of inactive exchanges */
     122        link_t sess_link;
     123
     124        /** Link into global list of inactive exchanges */
     125        link_t global_link;
     126
     127        /** Session pointer */
     128        async_sess_t *sess;
     129
     130        /** Exchange identification */
     131        cap_phone_handle_t phone;
     132};
     133
    83134extern void awaiter_initialize(awaiter_t *);
    84135
    85 extern void __async_init(void);
     136extern void __async_server_init(void);
     137extern void __async_client_init(void);
     138extern void __async_ports_init(void);
    86139extern void async_insert_timeout(awaiter_t *);
    87 extern void reply_received(void *, errno_t, ipc_call_t *);
     140
     141extern errno_t async_create_port_internal(iface_t, async_port_handler_t,
     142    void *, port_id_t *);
     143extern async_port_handler_t async_get_port_handler(iface_t, port_id_t, void **);
    88144
    89145#endif
  • uspace/lib/c/include/async.h

    rfda19b8 r49a796f1  
    107107typedef struct async_sess async_sess_t;
    108108typedef struct async_exch async_exch_t;
    109 
    110 extern atomic_t threads_in_ipc_wait;
    111109
    112110#define async_manager() \
Note: See TracChangeset for help on using the changeset viewer.