Changeset 41811af in mainline for uspace/lib/c/generic/async.c


Ignore:
Timestamp:
2011-06-10T10:14:26Z (14 years ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ab547063
Parents:
9536e6e (diff), 390d80d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline

File:
1 edited

Legend:

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

    r9536e6e r41811af  
    4040 * programming.
    4141 *
    42  * You should be able to write very simple multithreaded programs, the async
    43  * framework will automatically take care of most synchronization problems.
     42 * You should be able to write very simple multithreaded programs. The async
     43 * framework will automatically take care of most of the synchronization
     44 * problems.
    4445 *
    4546 * Example of use (pseudo C):
     
    5354 *   int fibril1(void *arg)
    5455 *   {
    55  *     conn = async_connect_me_to();
    56  *     c1 = async_send(conn);
    57  *     c2 = async_send(conn);
     56 *     conn = async_connect_me_to(...);
     57 *
     58 *     exch = async_exchange_begin(conn);
     59 *     c1 = async_send(exch);
     60 *     async_exchange_end(exch);
     61 *
     62 *     exch = async_exchange_begin(conn);
     63 *     c2 = async_send(exch);
     64 *     async_exchange_end(exch);
     65 *
    5866 *     async_wait_for(c1);
    5967 *     async_wait_for(c2);
     
    94102#include <futex.h>
    95103#include <fibril.h>
    96 #include <stdio.h>
    97104#include <adt/hash_table.h>
    98105#include <adt/list.h>
     
    102109#include <arch/barrier.h>
    103110#include <bool.h>
     111#include <malloc.h>
     112#include <mem.h>
    104113#include <stdlib.h>
    105 #include <malloc.h>
    106114#include "private/async.h"
    107115
     116#define CLIENT_HASH_TABLE_BUCKETS  32
     117#define CONN_HASH_TABLE_BUCKETS    32
     118
     119/** Async framework global futex */
    108120atomic_t async_futex = FUTEX_INITIALIZER;
    109121
     
    111123atomic_t threads_in_ipc_wait = { 0 };
    112124
    113 typedef struct {
    114         awaiter_t wdata;
    115        
    116         /** If reply was received. */
    117         bool done;
    118        
    119         /** Pointer to where the answer data is stored. */
    120         ipc_call_t *dataptr;
    121        
    122         sysarg_t retval;
    123 } amsg_t;
    124 
    125 /**
    126  * Structures of this type are used to group information about
    127  * a call and about a message queue link.
    128  */
     125/** Naming service session */
     126async_sess_t *session_ns;
     127
     128/** Call data */
    129129typedef struct {
    130130        link_t link;
     131       
    131132        ipc_callid_t callid;
    132133        ipc_call_t call;
    133134} msg_t;
    134135
     136/* Client connection data */
    135137typedef struct {
     138        link_t link;
     139       
    136140        sysarg_t in_task_hash;
    137         link_t link;
    138         int refcnt;
     141        atomic_t refcnt;
    139142        void *data;
    140143} client_t;
    141144
     145/* Server connection data */
    142146typedef struct {
    143147        awaiter_t wdata;
     
    148152        /** Incoming client task hash. */
    149153        sysarg_t in_task_hash;
     154       
    150155        /** Incoming phone hash. */
    151156        sysarg_t in_phone_hash;
     
    170175
    171176/** Identifier of the incoming connection handled by the current fibril. */
    172 static fibril_local connection_t *FIBRIL_connection;
     177static fibril_local connection_t *fibril_connection;
    173178
    174179static void *default_client_data_constructor(void)
     
    196201}
    197202
    198 void *async_client_data_get(void)
    199 {
    200         assert(FIBRIL_connection);
    201         return FIBRIL_connection->client->data;
     203void *async_get_client_data(void)
     204{
     205        assert(fibril_connection);
     206        return fibril_connection->client->data;
    202207}
    203208
     
    215220}
    216221
    217 /**
    218  * Pointer to a fibril function that will be used to handle connections.
    219  */
    220 static async_client_conn_t client_connection = default_client_connection;
    221 
    222222/** Default fibril function that gets called to handle interrupt notifications.
    223223 *
     
    232232}
    233233
    234 /**
    235  * Pointer to a fibril function that will be used to handle interrupt
    236  * notifications.
    237  */
     234static async_client_conn_t client_connection = default_client_connection;
    238235static async_client_conn_t interrupt_received = default_interrupt_received;
     236
     237/** Setter for client_connection function pointer.
     238 *
     239 * @param conn Function that will implement a new connection fibril.
     240 *
     241 */
     242void async_set_client_connection(async_client_conn_t conn)
     243{
     244        client_connection = conn;
     245}
     246
     247/** Setter for interrupt_received function pointer.
     248 *
     249 * @param intr Function that will implement a new interrupt
     250 *             notification fibril.
     251 */
     252void async_set_interrupt_received(async_client_conn_t intr)
     253{
     254        interrupt_received = intr;
     255}
     256
     257/** Mutex protecting inactive_exch_list and avail_phone_cv.
     258 *
     259 */
     260static FIBRIL_MUTEX_INITIALIZE(async_sess_mutex);
     261
     262/** List of all currently inactive exchanges.
     263 *
     264 */
     265static LIST_INITIALIZE(inactive_exch_list);
     266
     267/** Condition variable to wait for a phone to become available.
     268 *
     269 */
     270static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
    239271
    240272static hash_table_t client_hash_table;
     
    242274static LIST_INITIALIZE(timeout_list);
    243275
    244 #define CLIENT_HASH_TABLE_BUCKETS  32
    245 #define CONN_HASH_TABLE_BUCKETS    32
    246 
    247276static hash_index_t client_hash(unsigned long key[])
    248277{
    249278        assert(key);
     279       
    250280        return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
    251281}
     
    253283static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
    254284{
     285        assert(key);
     286        assert(item);
     287       
    255288        client_t *client = hash_table_get_instance(item, client_t, link);
    256289        return (key[0] == client->in_task_hash);
     
    278311{
    279312        assert(key);
     313       
    280314        return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
    281315}
     
    292326static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
    293327{
     328        assert(key);
     329        assert(item);
     330       
    294331        connection_t *conn = hash_table_get_instance(item, connection_t, link);
    295332        return (key[0] == conn->in_phone_hash);
     
    314351void async_insert_timeout(awaiter_t *wd)
    315352{
     353        assert(wd);
     354       
    316355        wd->to_event.occurred = false;
    317356        wd->to_event.inlist = true;
     
    346385static bool route_call(ipc_callid_t callid, ipc_call_t *call)
    347386{
     387        assert(call);
     388       
    348389        futex_down(&async_futex);
    349390       
     
    400441static int notification_fibril(void *arg)
    401442{
     443        assert(arg);
     444       
    402445        msg_t *msg = (msg_t *) arg;
    403446        interrupt_received(msg->callid, &msg->call);
     
    420463static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
    421464{
     465        assert(call);
     466       
    422467        futex_down(&async_futex);
    423468       
     
    458503ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
    459504{
    460         assert(FIBRIL_connection);
     505        assert(call);
     506        assert(fibril_connection);
    461507       
    462508        /* Why doing this?
    463          * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
     509         * GCC 4.1.0 coughs on fibril_connection-> dereference.
    464510         * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
    465511         *           I would never expect to find so many errors in
    466512         *           a compiler.
    467513         */
    468         connection_t *conn = FIBRIL_connection;
     514        connection_t *conn = fibril_connection;
    469515       
    470516        futex_down(&async_futex);
     
    541587static int connection_fibril(void *arg)
    542588{
     589        assert(arg);
     590       
    543591        /*
    544592         * Setup fibril-local connection pointer.
    545593         */
    546         FIBRIL_connection = (connection_t *) arg;
     594        fibril_connection = (connection_t *) arg;
    547595       
    548596        futex_down(&async_futex);
     
    554602         */
    555603       
    556         unsigned long key = FIBRIL_connection->in_task_hash;
     604        unsigned long key = fibril_connection->in_task_hash;
    557605        link_t *lnk = hash_table_find(&client_hash_table, &key);
    558606       
     
    561609        if (lnk) {
    562610                client = hash_table_get_instance(lnk, client_t, link);
    563                 client->refcnt++;
     611                atomic_inc(&client->refcnt);
    564612        } else {
    565613                client = malloc(sizeof(client_t));
    566614                if (!client) {
    567                         ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
     615                        ipc_answer_0(fibril_connection->callid, ENOMEM);
    568616                        futex_up(&async_futex);
    569617                        return 0;
    570618                }
    571619               
    572                 client->in_task_hash = FIBRIL_connection->in_task_hash;
    573                
    574                 async_serialize_start();
     620                client->in_task_hash = fibril_connection->in_task_hash;
    575621                client->data = async_client_data_create();
    576                 async_serialize_end();
    577                
    578                 client->refcnt = 1;
     622               
     623                atomic_set(&client->refcnt, 1);
    579624                hash_table_insert(&client_hash_table, &key, &client->link);
    580625        }
     
    582627        futex_up(&async_futex);
    583628       
    584         FIBRIL_connection->client = client;
     629        fibril_connection->client = client;
    585630       
    586631        /*
    587632         * Call the connection handler function.
    588633         */
    589         FIBRIL_connection->cfibril(FIBRIL_connection->callid,
    590             &FIBRIL_connection->call);
     634        fibril_connection->cfibril(fibril_connection->callid,
     635            &fibril_connection->call);
    591636       
    592637        /*
     
    597642        futex_down(&async_futex);
    598643       
    599         if (--client->refcnt == 0) {
     644        if (atomic_predec(&client->refcnt) == 0) {
    600645                hash_table_remove(&client_hash_table, &key, 1);
    601646                destroy = true;
     
    616661         */
    617662        futex_down(&async_futex);
    618         key = FIBRIL_connection->in_phone_hash;
     663        key = fibril_connection->in_phone_hash;
    619664        hash_table_remove(&conn_hash_table, &key, 1);
    620665        futex_up(&async_futex);
     
    623668         * Answer all remaining messages with EHANGUP.
    624669         */
    625         while (!list_empty(&FIBRIL_connection->msg_queue)) {
     670        while (!list_empty(&fibril_connection->msg_queue)) {
    626671                msg_t *msg =
    627                     list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
     672                    list_get_instance(fibril_connection->msg_queue.next, msg_t,
    628673                    link);
    629674               
     
    637682         * i.e. IPC_M_PHONE_HUNGUP.
    638683         */
    639         if (FIBRIL_connection->close_callid)
    640                 ipc_answer_0(FIBRIL_connection->close_callid, EOK);
    641        
    642         free(FIBRIL_connection);
     684        if (fibril_connection->close_callid)
     685                ipc_answer_0(fibril_connection->close_callid, EOK);
     686       
     687        free(fibril_connection);
    643688        return 0;
    644689}
     
    646691/** Create a new fibril for a new connection.
    647692 *
    648  * Create new fibril for connection, fill in connection structures and inserts
     693 * Create new fibril for connection, fill in connection structures and insert
    649694 * it into the hash table, so that later we can easily do routing of messages to
    650695 * particular fibrils.
     
    665710fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
    666711    ipc_callid_t callid, ipc_call_t *call,
    667     void (*cfibril)(ipc_callid_t, ipc_call_t *))
     712    async_client_conn_t cfibril)
    668713{
    669714        connection_t *conn = malloc(sizeof(*conn));
     
    721766static void handle_call(ipc_callid_t callid, ipc_call_t *call)
    722767{
     768        assert(call);
     769       
    723770        /* Unrouted call - take some default action */
    724771        if ((callid & IPC_CALLID_NOTIFICATION)) {
     
    878925void __async_init(void)
    879926{
    880         if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
    881             &client_hash_table_ops))
     927        if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS,
     928            1, &client_hash_table_ops))
    882929                abort();
    883930       
    884         if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1,
    885             &conn_hash_table_ops))
     931        if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS,
     932            1, &conn_hash_table_ops))
    886933                abort();
     934       
     935        session_ns = (async_sess_t *) malloc(sizeof(async_sess_t));
     936        if (session_ns == NULL)
     937                abort();
     938       
     939        session_ns->mgmt = EXCHANGE_ATOMIC;
     940        session_ns->phone = PHONE_NS;
     941        session_ns->arg1 = 0;
     942        session_ns->arg2 = 0;
     943        session_ns->arg3 = 0;
     944       
     945        list_initialize(&session_ns->exch_list);
     946        fibril_mutex_initialize(&session_ns->mutex);
     947        atomic_set(&session_ns->refcnt, 0);
    887948}
    888949
     
    899960 *
    900961 */
    901 static void reply_received(void *arg, int retval, ipc_call_t *data)
    902 {
     962void reply_received(void *arg, int retval, ipc_call_t *data)
     963{
     964        assert(arg);
     965       
    903966        futex_down(&async_futex);
    904967       
     
    930993 * completion.
    931994 *
    932  * @param phoneid Handle of the phone that will be used for the send.
    933  * @param method  Service-defined method.
     995 * @param exch    Exchange for sending the message.
     996 * @param imethod Service-defined interface and method.
    934997 * @param arg1    Service-defined payload argument.
    935998 * @param arg2    Service-defined payload argument.
     
    9421005 *
    9431006 */
    944 aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
     1007aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    9451008    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    9461009{
     1010        if (exch == NULL)
     1011                return 0;
     1012       
    9471013        amsg_t *msg = malloc(sizeof(amsg_t));
    948        
    949         if (!msg)
     1014        if (msg == NULL)
    9501015                return 0;
    9511016       
     
    9611026        msg->wdata.active = true;
    9621027       
    963         ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
     1028        ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
    9641029            reply_received, true);
    9651030       
     
    9721037 * completion.
    9731038 *
    974  * @param phoneid Handle of the phone that will be used for the send.
    975  * @param method  Service-defined method.
     1039 * @param exch    Exchange for sending the message.
     1040 * @param imethod Service-defined interface and method.
    9761041 * @param arg1    Service-defined payload argument.
    9771042 * @param arg2    Service-defined payload argument.
     
    9851050 *
    9861051 */
    987 aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
     1052aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    9881053    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    9891054    ipc_call_t *dataptr)
    9901055{
     1056        if (exch == NULL)
     1057                return 0;
     1058       
    9911059        amsg_t *msg = malloc(sizeof(amsg_t));
    9921060       
    993         if (!msg)
     1061        if (msg == NULL)
    9941062                return 0;
    9951063       
     
    10051073        msg->wdata.active = true;
    10061074       
    1007         ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
    1008             reply_received, true);
     1075        ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
     1076            msg, reply_received, true);
    10091077       
    10101078        return (aid_t) msg;
     
    10201088void async_wait_for(aid_t amsgid, sysarg_t *retval)
    10211089{
     1090        assert(amsgid);
     1091       
    10221092        amsg_t *msg = (amsg_t *) amsgid;
    10231093       
     
    10561126int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout)
    10571127{
     1128        assert(amsgid);
     1129       
    10581130        amsg_t *msg = (amsg_t *) amsgid;
    10591131       
     
    11241196}
    11251197
    1126 /** Setter for client_connection function pointer.
    1127  *
    1128  * @param conn Function that will implement a new connection fibril.
    1129  *
    1130  */
    1131 void async_set_client_connection(async_client_conn_t conn)
    1132 {
    1133         client_connection = conn;
    1134 }
    1135 
    1136 /** Setter for interrupt_received function pointer.
    1137  *
    1138  * @param intr Function that will implement a new interrupt
    1139  *             notification fibril.
    1140  */
    1141 void async_set_interrupt_received(async_client_conn_t intr)
    1142 {
    1143         interrupt_received = intr;
    1144 }
    1145 
    11461198/** Pseudo-synchronous message sending - fast version.
    11471199 *
     
    11511203 * transferring more arguments, see the slower async_req_slow().
    11521204 *
    1153  * @param phoneid Hash of the phone through which to make the call.
    1154  * @param method  Method of the call.
     1205 * @param exch    Exchange for sending the message.
     1206 * @param imethod Interface and method of the call.
    11551207 * @param arg1    Service-defined payload argument.
    11561208 * @param arg2    Service-defined payload argument.
     
    11661218 *
    11671219 */
    1168 sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
     1220sysarg_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    11691221    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
    11701222    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    11711223{
     1224        if (exch == NULL)
     1225                return ENOENT;
     1226       
    11721227        ipc_call_t result;
    1173         aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
     1228        aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
    11741229            &result);
    11751230       
    11761231        sysarg_t rc;
    1177         async_wait_for(eid, &rc);
     1232        async_wait_for(aid, &rc);
    11781233       
    11791234        if (r1)
     
    11991254 * Send message asynchronously and return only after the reply arrives.
    12001255 *
    1201  * @param phoneid Hash of the phone through which to make the call.
    1202  * @param method  Method of the call.
     1256 * @param exch    Exchange for sending the message.
     1257 * @param imethod Interface and method of the call.
    12031258 * @param arg1    Service-defined payload argument.
    12041259 * @param arg2    Service-defined payload argument.
     
    12151270 *
    12161271 */
    1217 sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
     1272sysarg_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    12181273    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
    12191274    sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    12201275{
     1276        if (exch == NULL)
     1277                return ENOENT;
     1278       
    12211279        ipc_call_t result;
    1222         aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
     1280        aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
    12231281            &result);
    12241282       
    12251283        sysarg_t rc;
    1226         async_wait_for(eid, &rc);
     1284        async_wait_for(aid, &rc);
    12271285       
    12281286        if (r1)
     
    12441302}
    12451303
    1246 void async_msg_0(int phone, sysarg_t imethod)
    1247 {
    1248         ipc_call_async_0(phone, imethod, NULL, NULL, true);
    1249 }
    1250 
    1251 void async_msg_1(int phone, sysarg_t imethod, sysarg_t arg1)
    1252 {
    1253         ipc_call_async_1(phone, imethod, arg1, NULL, NULL, true);
    1254 }
    1255 
    1256 void async_msg_2(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
    1257 {
    1258         ipc_call_async_2(phone, imethod, arg1, arg2, NULL, NULL, true);
    1259 }
    1260 
    1261 void async_msg_3(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
    1262     sysarg_t arg3)
    1263 {
    1264         ipc_call_async_3(phone, imethod, arg1, arg2, arg3, NULL, NULL, true);
    1265 }
    1266 
    1267 void async_msg_4(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
    1268     sysarg_t arg3, sysarg_t arg4)
    1269 {
    1270         ipc_call_async_4(phone, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
    1271             true);
    1272 }
    1273 
    1274 void async_msg_5(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
    1275     sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
    1276 {
    1277         ipc_call_async_5(phone, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
    1278             NULL, true);
     1304void async_msg_0(async_exch_t *exch, sysarg_t imethod)
     1305{
     1306        if (exch != NULL)
     1307                ipc_call_async_0(exch->phone, imethod, NULL, NULL, true);
     1308}
     1309
     1310void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
     1311{
     1312        if (exch != NULL)
     1313                ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL, true);
     1314}
     1315
     1316void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1317    sysarg_t arg2)
     1318{
     1319        if (exch != NULL)
     1320                ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL,
     1321                    true);
     1322}
     1323
     1324void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1325    sysarg_t arg2, sysarg_t arg3)
     1326{
     1327        if (exch != NULL)
     1328                ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
     1329                    NULL, true);
     1330}
     1331
     1332void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1333    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
     1334{
     1335        if (exch != NULL)
     1336                ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
     1337                    NULL, NULL, true);
     1338}
     1339
     1340void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1341    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
     1342{
     1343        if (exch != NULL)
     1344                ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
     1345                    arg5, NULL, NULL, true);
    12791346}
    12801347
     
    13131380}
    13141381
    1315 int async_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
    1316     sysarg_t arg1, sysarg_t arg2, unsigned int mode)
    1317 {
    1318         return ipc_forward_fast(callid, phoneid, imethod, arg1, arg2, mode);
    1319 }
    1320 
    1321 int async_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
    1322     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    1323     unsigned int mode)
    1324 {
    1325         return ipc_forward_slow(callid, phoneid, imethod, arg1, arg2, arg3, arg4,
    1326             arg5, mode);
     1382int async_forward_fast(ipc_callid_t callid, async_exch_t *exch,
     1383    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
     1384{
     1385        if (exch == NULL)
     1386                return ENOENT;
     1387       
     1388        return ipc_forward_fast(callid, exch->phone, imethod, arg1, arg2, mode);
     1389}
     1390
     1391int async_forward_slow(ipc_callid_t callid, async_exch_t *exch,
     1392    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
     1393    sysarg_t arg4, sysarg_t arg5, unsigned int mode)
     1394{
     1395        if (exch == NULL)
     1396                return ENOENT;
     1397       
     1398        return ipc_forward_slow(callid, exch->phone, imethod, arg1, arg2, arg3,
     1399            arg4, arg5, mode);
    13271400}
    13281401
     
    13311404 * Ask through phone for a new connection to some service.
    13321405 *
    1333  * @param phone           Phone handle used for contacting the other side.
     1406 * @param exch            Exchange for sending the message.
    13341407 * @param arg1            User defined argument.
    13351408 * @param arg2            User defined argument.
     
    13371410 * @param client_receiver Connection handing routine.
    13381411 *
    1339  * @return New phone handle on success or a negative error code.
    1340  *
    1341  */
    1342 int async_connect_to_me(int phone, sysarg_t arg1, sysarg_t arg2,
     1412 * @return Zero on success or a negative error code.
     1413 *
     1414 */
     1415int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
    13431416    sysarg_t arg3, async_client_conn_t client_receiver)
    13441417{
     1418        if (exch == NULL)
     1419                return ENOENT;
     1420       
    13451421        sysarg_t task_hash;
    13461422        sysarg_t phone_hash;
    1347         int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     1423        int rc = async_req_3_5(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
    13481424            NULL, NULL, NULL, &task_hash, &phone_hash);
    13491425        if (rc != EOK)
     
    13571433}
    13581434
    1359 /** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    1360  *
    1361  * Ask through phone for a new connection to some service.
    1362  *
    1363  * @param phone Phone handle used for contacting the other side.
    1364  * @param arg1  User defined argument.
    1365  * @param arg2  User defined argument.
    1366  * @param arg3  User defined argument.
    1367  *
    1368  * @return New phone handle on success or a negative error code.
    1369  *
    1370  */
    1371 int async_connect_me_to(int phone, sysarg_t arg1, sysarg_t arg2,
    1372     sysarg_t arg3)
    1373 {
    1374         sysarg_t newphid;
    1375         int rc = async_req_3_5(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
    1376             NULL, NULL, NULL, NULL, &newphid);
     1435/** Wrapper for making IPC_M_CONNECT_ME calls using the async framework.
     1436 *
     1437 * Ask through for a cloned connection to some service.
     1438 *
     1439 * @param mgmt Exchange management style.
     1440 * @param exch Exchange for sending the message.
     1441 *
     1442 * @return New session on success or NULL on error.
     1443 *
     1444 */
     1445async_sess_t *async_connect_me(exch_mgmt_t mgmt, async_exch_t *exch)
     1446{
     1447        if (exch == NULL) {
     1448                errno = ENOENT;
     1449                return NULL;
     1450        }
     1451       
     1452        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1453        if (sess == NULL) {
     1454                errno = ENOMEM;
     1455                return NULL;
     1456        }
     1457       
     1458        ipc_call_t result;
     1459       
     1460        amsg_t *msg = malloc(sizeof(amsg_t));
     1461        if (msg == NULL) {
     1462                free(sess);
     1463                errno = ENOMEM;
     1464                return NULL;
     1465        }
     1466       
     1467        msg->done = false;
     1468        msg->dataptr = &result;
     1469       
     1470        msg->wdata.to_event.inlist = false;
     1471       
     1472        /*
     1473         * We may sleep in the next method,
     1474         * but it will use its own means
     1475         */
     1476        msg->wdata.active = true;
     1477       
     1478        ipc_call_async_0(exch->phone, IPC_M_CONNECT_ME, msg,
     1479            reply_received, true);
     1480       
     1481        sysarg_t rc;
     1482        async_wait_for((aid_t) msg, &rc);
     1483       
     1484        if (rc != EOK) {
     1485                errno = rc;
     1486                free(sess);
     1487                return NULL;
     1488        }
     1489       
     1490        int phone = (int) IPC_GET_ARG5(result);
     1491       
     1492        if (phone < 0) {
     1493                errno = phone;
     1494                free(sess);
     1495                return NULL;
     1496        }
     1497       
     1498        sess->mgmt = mgmt;
     1499        sess->phone = phone;
     1500        sess->arg1 = 0;
     1501        sess->arg2 = 0;
     1502        sess->arg3 = 0;
     1503       
     1504        list_initialize(&sess->exch_list);
     1505        fibril_mutex_initialize(&sess->mutex);
     1506        atomic_set(&sess->refcnt, 0);
     1507       
     1508        return sess;
     1509}
     1510
     1511static int async_connect_me_to_internal(int phone, sysarg_t arg1, sysarg_t arg2,
     1512    sysarg_t arg3, sysarg_t arg4)
     1513{
     1514        ipc_call_t result;
     1515       
     1516        amsg_t *msg = malloc(sizeof(amsg_t));
     1517        if (msg == NULL)
     1518                return ENOENT;
     1519       
     1520        msg->done = false;
     1521        msg->dataptr = &result;
     1522       
     1523        msg->wdata.to_event.inlist = false;
     1524       
     1525        /*
     1526         * We may sleep in the next method,
     1527         * but it will use its own means
     1528         */
     1529        msg->wdata.active = true;
     1530       
     1531        ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
     1532            msg, reply_received, true);
     1533       
     1534        sysarg_t rc;
     1535        async_wait_for((aid_t) msg, &rc);
    13771536       
    13781537        if (rc != EOK)
    13791538                return rc;
    13801539       
    1381         return newphid;
     1540        return (int) IPC_GET_ARG5(result);
     1541}
     1542
     1543/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
     1544 *
     1545 * Ask through for a new connection to some service.
     1546 *
     1547 * @param mgmt Exchange management style.
     1548 * @param exch Exchange for sending the message.
     1549 * @param arg1 User defined argument.
     1550 * @param arg2 User defined argument.
     1551 * @param arg3 User defined argument.
     1552 *
     1553 * @return New session on success or NULL on error.
     1554 *
     1555 */
     1556async_sess_t *async_connect_me_to(exch_mgmt_t mgmt, async_exch_t *exch,
     1557    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
     1558{
     1559        if (exch == NULL) {
     1560                errno = ENOENT;
     1561                return NULL;
     1562        }
     1563       
     1564        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1565        if (sess == NULL) {
     1566                errno = ENOMEM;
     1567                return NULL;
     1568        }
     1569       
     1570        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
     1571            0);
     1572       
     1573        if (phone < 0) {
     1574                errno = phone;
     1575                free(sess);
     1576                return NULL;
     1577        }
     1578       
     1579        sess->mgmt = mgmt;
     1580        sess->phone = phone;
     1581        sess->arg1 = arg1;
     1582        sess->arg2 = arg2;
     1583        sess->arg3 = arg3;
     1584       
     1585        list_initialize(&sess->exch_list);
     1586        fibril_mutex_initialize(&sess->mutex);
     1587        atomic_set(&sess->refcnt, 0);
     1588       
     1589        return sess;
    13821590}
    13831591
     
    13871595 * success.
    13881596 *
    1389  * @param phoneid Phone handle used for contacting the other side.
    1390  * @param arg1    User defined argument.
    1391  * @param arg2    User defined argument.
    1392  * @param arg3    User defined argument.
    1393  *
    1394  * @return New phone handle on success or a negative error code.
    1395  *
    1396  */
    1397 int async_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
    1398     sysarg_t arg3)
    1399 {
    1400         sysarg_t newphid;
    1401         int rc = async_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
    1402             IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
    1403        
    1404         if (rc != EOK)
    1405                 return rc;
    1406        
    1407         return newphid;
     1597 * @param mgmt Exchange management style.
     1598 * @param exch Exchange for sending the message.
     1599 * @param arg1 User defined argument.
     1600 * @param arg2 User defined argument.
     1601 * @param arg3 User defined argument.
     1602 *
     1603 * @return New session on success or NULL on error.
     1604 *
     1605 */
     1606async_sess_t *async_connect_me_to_blocking(exch_mgmt_t mgmt, async_exch_t *exch,
     1607    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
     1608{
     1609        if (exch == NULL) {
     1610                errno = ENOENT;
     1611                return NULL;
     1612        }
     1613       
     1614        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1615        if (sess == NULL) {
     1616                errno = ENOMEM;
     1617                return NULL;
     1618        }
     1619       
     1620        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
     1621            IPC_FLAG_BLOCKING);
     1622       
     1623        if (phone < 0) {
     1624                errno = phone;
     1625                free(sess);
     1626                return NULL;
     1627        }
     1628       
     1629        sess->mgmt = mgmt;
     1630        sess->phone = phone;
     1631        sess->arg1 = arg1;
     1632        sess->arg2 = arg2;
     1633        sess->arg3 = arg3;
     1634       
     1635        list_initialize(&sess->exch_list);
     1636        fibril_mutex_initialize(&sess->mutex);
     1637        atomic_set(&sess->refcnt, 0);
     1638       
     1639        return sess;
    14081640}
    14091641
     
    14111643 *
    14121644 */
    1413 int async_connect_kbox(task_id_t id)
    1414 {
    1415         return ipc_connect_kbox(id);
     1645async_sess_t *async_connect_kbox(task_id_t id)
     1646{
     1647        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1648        if (sess == NULL) {
     1649                errno = ENOMEM;
     1650                return NULL;
     1651        }
     1652       
     1653        int phone = ipc_connect_kbox(id);
     1654        if (phone < 0) {
     1655                errno = phone;
     1656                free(sess);
     1657                return NULL;
     1658        }
     1659       
     1660        sess->mgmt = EXCHANGE_ATOMIC;
     1661        sess->phone = phone;
     1662        sess->arg1 = 0;
     1663        sess->arg2 = 0;
     1664        sess->arg3 = 0;
     1665       
     1666        list_initialize(&sess->exch_list);
     1667        fibril_mutex_initialize(&sess->mutex);
     1668        atomic_set(&sess->refcnt, 0);
     1669       
     1670        return sess;
     1671}
     1672
     1673static int async_hangup_internal(int phone)
     1674{
     1675        return ipc_hangup(phone);
    14161676}
    14171677
    14181678/** Wrapper for ipc_hangup.
    14191679 *
    1420  * @param phone Phone handle to hung up.
     1680 * @param sess Session to hung up.
    14211681 *
    14221682 * @return Zero on success or a negative error code.
    14231683 *
    14241684 */
    1425 int async_hangup(int phone)
    1426 {
    1427         return ipc_hangup(phone);
     1685int async_hangup(async_sess_t *sess)
     1686{
     1687        assert(sess);
     1688       
     1689        if (atomic_get(&sess->refcnt) > 0)
     1690                return EBUSY;
     1691       
     1692        int rc = async_hangup_internal(sess->phone);
     1693        if (rc == EOK)
     1694                free(sess);
     1695       
     1696        return rc;
    14281697}
    14291698
     
    14341703}
    14351704
     1705/** Start new exchange in a session.
     1706 *
     1707 * @param session Session.
     1708 *
     1709 * @return New exchange or NULL on error.
     1710 *
     1711 */
     1712async_exch_t *async_exchange_begin(async_sess_t *sess)
     1713{
     1714        if (sess == NULL)
     1715                return NULL;
     1716       
     1717        async_exch_t *exch;
     1718       
     1719        fibril_mutex_lock(&async_sess_mutex);
     1720       
     1721        if (!list_empty(&sess->exch_list)) {
     1722                /*
     1723                 * There are inactive exchanges in the session.
     1724                 */
     1725                exch = (async_exch_t *)
     1726                    list_get_instance(sess->exch_list.next, async_exch_t, sess_link);
     1727                list_remove(&exch->sess_link);
     1728                list_remove(&exch->global_link);
     1729        } else {
     1730                /*
     1731                 * There are no available exchanges in the session.
     1732                 */
     1733               
     1734                if ((sess->mgmt == EXCHANGE_ATOMIC) ||
     1735                    (sess->mgmt == EXCHANGE_SERIALIZE)) {
     1736                        exch = (async_exch_t *) malloc(sizeof(async_exch_t));
     1737                        if (exch != NULL) {
     1738                                list_initialize(&exch->sess_link);
     1739                                list_initialize(&exch->global_link);
     1740                                exch->sess = sess;
     1741                                exch->phone = sess->phone;
     1742                        }
     1743                } else {  /* EXCHANGE_PARALLEL */
     1744                        /*
     1745                         * Make a one-time attempt to connect a new data phone.
     1746                         */
     1747                       
     1748                        int phone;
     1749                       
     1750retry:
     1751                        phone = async_connect_me_to_internal(sess->phone, sess->arg1,
     1752                            sess->arg2, sess->arg3, 0);
     1753                        if (phone >= 0) {
     1754                                exch = (async_exch_t *) malloc(sizeof(async_exch_t));
     1755                                if (exch != NULL) {
     1756                                        list_initialize(&exch->sess_link);
     1757                                        list_initialize(&exch->global_link);
     1758                                        exch->sess = sess;
     1759                                        exch->phone = phone;
     1760                                } else
     1761                                        async_hangup_internal(phone);
     1762                        } else if (!list_empty(&inactive_exch_list)) {
     1763                                /*
     1764                                 * We did not manage to connect a new phone. But we
     1765                                 * can try to close some of the currently inactive
     1766                                 * connections in other sessions and try again.
     1767                                 */
     1768                                exch = (async_exch_t *)
     1769                                    list_get_instance(inactive_exch_list.next, async_exch_t,
     1770                                    global_link);
     1771                                list_remove(&exch->sess_link);
     1772                                list_remove(&exch->global_link);
     1773                                async_hangup_internal(exch->phone);
     1774                                free(exch);
     1775                                goto retry;
     1776                        } else {
     1777                                /*
     1778                                 * Wait for a phone to become available.
     1779                                 */
     1780                                fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
     1781                                goto retry;
     1782                        }
     1783                }
     1784        }
     1785       
     1786        fibril_mutex_unlock(&async_sess_mutex);
     1787       
     1788        if (exch != NULL) {
     1789                atomic_inc(&sess->refcnt);
     1790               
     1791                if (sess->mgmt == EXCHANGE_SERIALIZE)
     1792                        fibril_mutex_lock(&sess->mutex);
     1793        }
     1794       
     1795        return exch;
     1796}
     1797
     1798/** Finish an exchange.
     1799 *
     1800 * @param exch Exchange to finish.
     1801 *
     1802 */
     1803void async_exchange_end(async_exch_t *exch)
     1804{
     1805        if (exch == NULL)
     1806                return;
     1807       
     1808        async_sess_t *sess = exch->sess;
     1809       
     1810        if (sess->mgmt == EXCHANGE_SERIALIZE)
     1811                fibril_mutex_unlock(&sess->mutex);
     1812       
     1813        fibril_mutex_lock(&async_sess_mutex);
     1814       
     1815        list_append(&exch->sess_link, &sess->exch_list);
     1816        list_append(&exch->global_link, &inactive_exch_list);
     1817        fibril_condvar_signal(&avail_phone_cv);
     1818       
     1819        fibril_mutex_unlock(&async_sess_mutex);
     1820}
     1821
    14361822/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
    14371823 *
    1438  * @param phoneid Phone that will be used to contact the receiving side.
    1439  * @param dst     Destination address space area base.
    1440  * @param size    Size of the destination address space area.
    1441  * @param arg     User defined argument.
    1442  * @param flags   Storage for the received flags. Can be NULL.
     1824 * @param exch  Exchange for sending the message.
     1825 * @param dst   Destination address space area base.
     1826 * @param size  Size of the destination address space area.
     1827 * @param arg   User defined argument.
     1828 * @param flags Storage for the received flags. Can be NULL.
    14431829 *
    14441830 * @return Zero on success or a negative error code from errno.h.
    14451831 *
    14461832 */
    1447 int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
    1448     unsigned int *flags)
    1449 {
     1833int async_share_in_start(async_exch_t *exch, void *dst, size_t size,
     1834    sysarg_t arg, unsigned int *flags)
     1835{
     1836        if (exch == NULL)
     1837                return ENOENT;
     1838       
    14501839        sysarg_t tmp_flags;
    1451         int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
     1840        int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
    14521841            (sysarg_t) size, arg, NULL, &tmp_flags);
    14531842       
     
    15071896/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
    15081897 *
    1509  * @param phoneid Phone that will be used to contact the receiving side.
    1510  * @param src     Source address space area base address.
    1511  * @param flags   Flags to be used for sharing. Bits can be only cleared.
     1898 * @param exch  Exchange for sending the message.
     1899 * @param src   Source address space area base address.
     1900 * @param flags Flags to be used for sharing. Bits can be only cleared.
    15121901 *
    15131902 * @return Zero on success or a negative error code from errno.h.
    15141903 *
    15151904 */
    1516 int async_share_out_start(int phoneid, void *src, unsigned int flags)
    1517 {
    1518         return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
     1905int async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
     1906{
     1907        if (exch == NULL)
     1908                return ENOENT;
     1909       
     1910        return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
    15191911            (sysarg_t) flags);
    15201912}
     
    15691961}
    15701962
     1963/** Start IPC_M_DATA_READ using the async framework.
     1964 *
     1965 * @param exch    Exchange for sending the message.
     1966 * @param dst     Address of the beginning of the destination buffer.
     1967 * @param size    Size of the destination buffer (in bytes).
     1968 * @param dataptr Storage of call data (arg 2 holds actual data size).
     1969 *
     1970 * @return Hash of the sent message or 0 on error.
     1971 *
     1972 */
     1973aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
     1974    ipc_call_t *dataptr)
     1975{
     1976        return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
     1977            (sysarg_t) size, dataptr);
     1978}
     1979
    15711980/** Wrapper for IPC_M_DATA_READ calls using the async framework.
    15721981 *
    1573  * @param phoneid Phone that will be used to contact the receiving side.
    1574  * @param dst     Address of the beginning of the destination buffer.
    1575  * @param size    Size of the destination buffer.
    1576  * @param flags   Flags to control the data transfer.
     1982 * @param exch Exchange for sending the message.
     1983 * @param dst  Address of the beginning of the destination buffer.
     1984 * @param size Size of the destination buffer.
    15771985 *
    15781986 * @return Zero on success or a negative error code from errno.h.
    15791987 *
    15801988 */
    1581 int
    1582 async_data_read_start_generic(int phoneid, void *dst, size_t size, int flags)
    1583 {
    1584         return async_req_3_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
    1585             (sysarg_t) size, (sysarg_t) flags);
     1989int async_data_read_start(async_exch_t *exch, void *dst, size_t size)
     1990{
     1991        if (exch == NULL)
     1992                return ENOENT;
     1993       
     1994        return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
     1995            (sysarg_t) size);
    15861996}
    15871997
     
    16382048 *
    16392049 */
    1640 int async_data_read_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
    1641     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    1642 {
     2050int async_data_read_forward_fast(async_exch_t *exch, sysarg_t imethod,
     2051    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
     2052    ipc_call_t *dataptr)
     2053{
     2054        if (exch == NULL)
     2055                return ENOENT;
     2056       
    16432057        ipc_callid_t callid;
    16442058        if (!async_data_read_receive(&callid, NULL)) {
     
    16472061        }
    16482062       
    1649         aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
     2063        aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
    16502064            dataptr);
    16512065        if (msg == 0) {
     
    16542068        }
    16552069       
    1656         int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
     2070        int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
    16572071            IPC_FF_ROUTE_FROM_ME);
    16582072        if (retval != EOK) {
     
    16702084/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
    16712085 *
    1672  * @param phoneid Phone that will be used to contact the receiving side.
    1673  * @param src     Address of the beginning of the source buffer.
    1674  * @param size    Size of the source buffer.
    1675  * @param flags   Flags to control the data transfer.
     2086 * @param exch Exchange for sending the message.
     2087 * @param src  Address of the beginning of the source buffer.
     2088 * @param size Size of the source buffer.
    16762089 *
    16772090 * @return Zero on success or a negative error code from errno.h.
    16782091 *
    16792092 */
    1680 int
    1681 async_data_write_start_generic(int phoneid, const void *src, size_t size,
    1682     int flags)
    1683 {
    1684         return async_req_3_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
    1685             (sysarg_t) size, (sysarg_t) flags);
     2093int async_data_write_start(async_exch_t *exch, const void *src, size_t size)
     2094{
     2095        if (exch == NULL)
     2096                return ENOENT;
     2097       
     2098        return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
     2099            (sysarg_t) size);
    16862100}
    16872101
     
    17592173    size_t *received)
    17602174{
     2175        assert(data);
     2176       
    17612177        ipc_callid_t callid;
    17622178        size_t size;
     
    18262242 *
    18272243 */
    1828 int async_data_write_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
    1829     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    1830 {
     2244int async_data_write_forward_fast(async_exch_t *exch, sysarg_t imethod,
     2245    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
     2246    ipc_call_t *dataptr)
     2247{
     2248        if (exch == NULL)
     2249                return ENOENT;
     2250       
    18312251        ipc_callid_t callid;
    18322252        if (!async_data_write_receive(&callid, NULL)) {
     
    18352255        }
    18362256       
    1837         aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
     2257        aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
    18382258            dataptr);
    18392259        if (msg == 0) {
     
    18422262        }
    18432263       
    1844         int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
     2264        int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
    18452265            IPC_FF_ROUTE_FROM_ME);
    18462266        if (retval != EOK) {
     
    18562276}
    18572277
     2278/** Wrapper for sending an exchange over different exchange for cloning
     2279 *
     2280 * @param exch       Exchange to be used for sending.
     2281 * @param clone_exch Exchange to be cloned.
     2282 *
     2283 */
     2284int async_exchange_clone(async_exch_t *exch, async_exch_t *clone_exch)
     2285{
     2286        return async_req_1_0(exch, IPC_M_CONNECTION_CLONE, clone_exch->phone);
     2287}
     2288
     2289/** Wrapper for receiving the IPC_M_CONNECTION_CLONE calls.
     2290 *
     2291 * If the current call is IPC_M_CONNECTION_CLONE then a new
     2292 * async session is created for the accepted phone.
     2293 *
     2294 * @param mgmt Exchange management style.
     2295 *
     2296 * @return New async session or NULL on failure.
     2297 *
     2298 */
     2299async_sess_t *async_clone_receive(exch_mgmt_t mgmt)
     2300{
     2301        /* Accept the phone */
     2302        ipc_call_t call;
     2303        ipc_callid_t callid = async_get_call(&call);
     2304        int phone = (int) IPC_GET_ARG1(call);
     2305       
     2306        if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECTION_CLONE) ||
     2307            (phone < 0)) {
     2308                async_answer_0(callid, EINVAL);
     2309                return NULL;
     2310        }
     2311       
     2312        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2313        if (sess == NULL) {
     2314                async_answer_0(callid, ENOMEM);
     2315                return NULL;
     2316        }
     2317       
     2318        sess->mgmt = mgmt;
     2319        sess->phone = phone;
     2320        sess->arg1 = 0;
     2321        sess->arg2 = 0;
     2322        sess->arg3 = 0;
     2323       
     2324        list_initialize(&sess->exch_list);
     2325        fibril_mutex_initialize(&sess->mutex);
     2326        atomic_set(&sess->refcnt, 0);
     2327       
     2328        /* Acknowledge the cloned phone */
     2329        async_answer_0(callid, EOK);
     2330       
     2331        return sess;
     2332}
     2333
     2334/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
     2335 *
     2336 * If the current call is IPC_M_CONNECT_TO_ME then a new
     2337 * async session is created for the accepted phone.
     2338 *
     2339 * @param mgmt Exchange management style.
     2340 *
     2341 * @return New async session.
     2342 * @return NULL on failure.
     2343 *
     2344 */
     2345async_sess_t *async_callback_receive(exch_mgmt_t mgmt)
     2346{
     2347        /* Accept the phone */
     2348        ipc_call_t call;
     2349        ipc_callid_t callid = async_get_call(&call);
     2350        int phone = (int) IPC_GET_ARG5(call);
     2351       
     2352        if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) ||
     2353            (phone < 0)) {
     2354                async_answer_0(callid, EINVAL);
     2355                return NULL;
     2356        }
     2357       
     2358        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2359        if (sess == NULL) {
     2360                async_answer_0(callid, ENOMEM);
     2361                return NULL;
     2362        }
     2363       
     2364        sess->mgmt = mgmt;
     2365        sess->phone = phone;
     2366        sess->arg1 = 0;
     2367        sess->arg2 = 0;
     2368        sess->arg3 = 0;
     2369       
     2370        list_initialize(&sess->exch_list);
     2371        fibril_mutex_initialize(&sess->mutex);
     2372        atomic_set(&sess->refcnt, 0);
     2373       
     2374        /* Acknowledge the connected phone */
     2375        async_answer_0(callid, EOK);
     2376       
     2377        return sess;
     2378}
     2379
     2380/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
     2381 *
     2382 * If the call is IPC_M_CONNECT_TO_ME then a new
     2383 * async session is created. However, the phone is
     2384 * not accepted automatically.
     2385 *
     2386 * @param mgmt   Exchange management style.
     2387 * @param call   Call data.
     2388 *
     2389 * @return New async session.
     2390 * @return NULL on failure.
     2391 * @return NULL if the call is not IPC_M_CONNECT_TO_ME.
     2392 *
     2393 */
     2394async_sess_t *async_callback_receive_start(exch_mgmt_t mgmt, ipc_call_t *call)
     2395{
     2396        int phone = (int) IPC_GET_ARG5(*call);
     2397       
     2398        if ((IPC_GET_IMETHOD(*call) != IPC_M_CONNECT_TO_ME) ||
     2399            (phone < 0))
     2400                return NULL;
     2401       
     2402        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2403        if (sess == NULL)
     2404                return NULL;
     2405       
     2406        sess->mgmt = mgmt;
     2407        sess->phone = phone;
     2408        sess->arg1 = 0;
     2409        sess->arg2 = 0;
     2410        sess->arg3 = 0;
     2411       
     2412        list_initialize(&sess->exch_list);
     2413        fibril_mutex_initialize(&sess->mutex);
     2414        atomic_set(&sess->refcnt, 0);
     2415       
     2416        return sess;
     2417}
     2418
    18582419/** @}
    18592420 */
Note: See TracChangeset for help on using the changeset viewer.