Changeset 6a44ee4 in mainline for uspace/lib/c/generic/async.c


Ignore:
Timestamp:
2011-07-20T15:26:21Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
efcebe1
Parents:
25bef0ff (diff), a701812 (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 changes.

File:
1 edited

Legend:

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

    r25bef0ff r6a44ee4  
    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;
     
    155160       
    156161        /** Messages that should be delivered to this fibril. */
    157         link_t msg_queue;
     162        list_t msg_queue;
    158163       
    159164        /** Identification of the opening call. */
     
    161166        /** Call data of the opening call. */
    162167        ipc_call_t call;
     168        /** Local argument or NULL if none. */
     169        void *carg;
    163170       
    164171        /** Identification of the closing call. */
     
    166173       
    167174        /** Fibril function that will be used to handle the connection. */
    168         void (*cfibril)(ipc_callid_t, ipc_call_t *);
     175        async_client_conn_t cfibril;
    169176} connection_t;
    170177
    171178/** Identifier of the incoming connection handled by the current fibril. */
    172 static fibril_local connection_t *FIBRIL_connection;
     179static fibril_local connection_t *fibril_connection;
    173180
    174181static void *default_client_data_constructor(void)
     
    196203}
    197204
    198 void *async_client_data_get(void)
    199 {
    200         assert(FIBRIL_connection);
    201         return FIBRIL_connection->client->data;
     205void *async_get_client_data(void)
     206{
     207        assert(fibril_connection);
     208        return fibril_connection->client->data;
    202209}
    203210
     
    208215 * @param callid Hash of the incoming call.
    209216 * @param call   Data of the incoming call.
    210  *
    211  */
    212 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
     217 * @param arg    Local argument
     218 *
     219 */
     220static void default_client_connection(ipc_callid_t callid, ipc_call_t *call,
     221    void *arg)
    213222{
    214223        ipc_answer_0(callid, ENOENT);
    215224}
    216 
    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;
    221225
    222226/** Default fibril function that gets called to handle interrupt notifications.
     
    226230 * @param callid Hash of the incoming call.
    227231 * @param call   Data of the incoming call.
     232 * @param arg    Local argument.
    228233 *
    229234 */
     
    232237}
    233238
    234 /**
    235  * Pointer to a fibril function that will be used to handle interrupt
    236  * notifications.
    237  */
    238 static async_client_conn_t interrupt_received = default_interrupt_received;
     239static async_client_conn_t client_connection = default_client_connection;
     240static async_interrupt_handler_t interrupt_received = default_interrupt_received;
     241
     242/** Setter for client_connection function pointer.
     243 *
     244 * @param conn Function that will implement a new connection fibril.
     245 *
     246 */
     247void async_set_client_connection(async_client_conn_t conn)
     248{
     249        client_connection = conn;
     250}
     251
     252/** Setter for interrupt_received function pointer.
     253 *
     254 * @param intr Function that will implement a new interrupt
     255 *             notification fibril.
     256 */
     257void async_set_interrupt_received(async_interrupt_handler_t intr)
     258{
     259        interrupt_received = intr;
     260}
     261
     262/** Mutex protecting inactive_exch_list and avail_phone_cv.
     263 *
     264 */
     265static FIBRIL_MUTEX_INITIALIZE(async_sess_mutex);
     266
     267/** List of all currently inactive exchanges.
     268 *
     269 */
     270static LIST_INITIALIZE(inactive_exch_list);
     271
     272/** Condition variable to wait for a phone to become available.
     273 *
     274 */
     275static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
    239276
    240277static hash_table_t client_hash_table;
     
    242279static LIST_INITIALIZE(timeout_list);
    243280
    244 #define CLIENT_HASH_TABLE_BUCKETS  32
    245 #define CONN_HASH_TABLE_BUCKETS    32
    246 
    247281static hash_index_t client_hash(unsigned long key[])
    248282{
    249283        assert(key);
     284       
    250285        return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
    251286}
     
    253288static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
    254289{
     290        assert(key);
     291        assert(item);
     292       
    255293        client_t *client = hash_table_get_instance(item, client_t, link);
    256294        return (key[0] == client->in_task_hash);
     
    278316{
    279317        assert(key);
     318       
    280319        return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
    281320}
     
    292331static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
    293332{
     333        assert(key);
     334        assert(item);
     335       
    294336        connection_t *conn = hash_table_get_instance(item, connection_t, link);
    295337        return (key[0] == conn->in_phone_hash);
     
    314356void async_insert_timeout(awaiter_t *wd)
    315357{
     358        assert(wd);
     359       
    316360        wd->to_event.occurred = false;
    317361        wd->to_event.inlist = true;
    318362       
    319         link_t *tmp = timeout_list.next;
    320         while (tmp != &timeout_list) {
     363        link_t *tmp = timeout_list.head.next;
     364        while (tmp != &timeout_list.head) {
    321365                awaiter_t *cur
    322366                    = list_get_instance(tmp, awaiter_t, to_event.link);
     
    328372        }
    329373       
    330         list_append(&wd->to_event.link, tmp);
     374        list_insert_before(&wd->to_event.link, tmp);
    331375}
    332376
     
    346390static bool route_call(ipc_callid_t callid, ipc_call_t *call)
    347391{
     392        assert(call);
     393       
    348394        futex_down(&async_futex);
    349395       
     
    400446static int notification_fibril(void *arg)
    401447{
     448        assert(arg);
     449       
    402450        msg_t *msg = (msg_t *) arg;
    403451        interrupt_received(msg->callid, &msg->call);
     
    420468static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
    421469{
     470        assert(call);
     471       
    422472        futex_down(&async_futex);
    423473       
     
    458508ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
    459509{
    460         assert(FIBRIL_connection);
     510        assert(call);
     511        assert(fibril_connection);
    461512       
    462513        /* Why doing this?
    463          * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
     514         * GCC 4.1.0 coughs on fibril_connection-> dereference.
    464515         * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
    465516         *           I would never expect to find so many errors in
    466517         *           a compiler.
    467518         */
    468         connection_t *conn = FIBRIL_connection;
     519        connection_t *conn = fibril_connection;
    469520       
    470521        futex_down(&async_futex);
     
    518569        }
    519570       
    520         msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
     571        msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link);
    521572        list_remove(&msg->link);
    522573       
     
    541592static int connection_fibril(void *arg)
    542593{
     594        assert(arg);
     595       
    543596        /*
    544597         * Setup fibril-local connection pointer.
    545598         */
    546         FIBRIL_connection = (connection_t *) arg;
     599        fibril_connection = (connection_t *) arg;
    547600       
    548601        futex_down(&async_futex);
     
    554607         */
    555608       
    556         unsigned long key = FIBRIL_connection->in_task_hash;
     609        unsigned long key = fibril_connection->in_task_hash;
    557610        link_t *lnk = hash_table_find(&client_hash_table, &key);
    558611       
     
    561614        if (lnk) {
    562615                client = hash_table_get_instance(lnk, client_t, link);
    563                 client->refcnt++;
     616                atomic_inc(&client->refcnt);
    564617        } else {
    565618                client = malloc(sizeof(client_t));
    566619                if (!client) {
    567                         ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
     620                        ipc_answer_0(fibril_connection->callid, ENOMEM);
    568621                        futex_up(&async_futex);
    569622                        return 0;
    570623                }
    571624               
    572                 client->in_task_hash = FIBRIL_connection->in_task_hash;
    573                
    574                 async_serialize_start();
     625                client->in_task_hash = fibril_connection->in_task_hash;
    575626                client->data = async_client_data_create();
    576                 async_serialize_end();
    577                
    578                 client->refcnt = 1;
     627               
     628                atomic_set(&client->refcnt, 1);
    579629                hash_table_insert(&client_hash_table, &key, &client->link);
    580630        }
     
    582632        futex_up(&async_futex);
    583633       
    584         FIBRIL_connection->client = client;
     634        fibril_connection->client = client;
    585635       
    586636        /*
    587637         * Call the connection handler function.
    588638         */
    589         FIBRIL_connection->cfibril(FIBRIL_connection->callid,
    590             &FIBRIL_connection->call);
     639        fibril_connection->cfibril(fibril_connection->callid,
     640            &fibril_connection->call, fibril_connection->carg);
    591641       
    592642        /*
     
    597647        futex_down(&async_futex);
    598648       
    599         if (--client->refcnt == 0) {
     649        if (atomic_predec(&client->refcnt) == 0) {
    600650                hash_table_remove(&client_hash_table, &key, 1);
    601651                destroy = true;
     
    616666         */
    617667        futex_down(&async_futex);
    618         key = FIBRIL_connection->in_phone_hash;
     668        key = fibril_connection->in_phone_hash;
    619669        hash_table_remove(&conn_hash_table, &key, 1);
    620670        futex_up(&async_futex);
     
    623673         * Answer all remaining messages with EHANGUP.
    624674         */
    625         while (!list_empty(&FIBRIL_connection->msg_queue)) {
     675        while (!list_empty(&fibril_connection->msg_queue)) {
    626676                msg_t *msg =
    627                     list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
    628                     link);
     677                    list_get_instance(list_first(&fibril_connection->msg_queue),
     678                    msg_t, link);
    629679               
    630680                list_remove(&msg->link);
     
    637687         * i.e. IPC_M_PHONE_HUNGUP.
    638688         */
    639         if (FIBRIL_connection->close_callid)
    640                 ipc_answer_0(FIBRIL_connection->close_callid, EOK);
    641        
    642         free(FIBRIL_connection);
     689        if (fibril_connection->close_callid)
     690                ipc_answer_0(fibril_connection->close_callid, EOK);
     691       
     692        free(fibril_connection);
    643693        return 0;
    644694}
     
    646696/** Create a new fibril for a new connection.
    647697 *
    648  * Create new fibril for connection, fill in connection structures and inserts
     698 * Create new fibril for connection, fill in connection structures and insert
    649699 * it into the hash table, so that later we can easily do routing of messages to
    650700 * particular fibrils.
     
    659709 * @param cfibril       Fibril function that should be called upon opening the
    660710 *                      connection.
     711 * @param carg          Extra argument to pass to the connection fibril
    661712 *
    662713 * @return New fibril id or NULL on failure.
     
    665716fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
    666717    ipc_callid_t callid, ipc_call_t *call,
    667     void (*cfibril)(ipc_callid_t, ipc_call_t *))
     718    async_client_conn_t cfibril, void *carg)
    668719{
    669720        connection_t *conn = malloc(sizeof(*conn));
     
    680731        conn->callid = callid;
    681732        conn->close_callid = 0;
     733        conn->carg = carg;
    682734       
    683735        if (call)
     
    721773static void handle_call(ipc_callid_t callid, ipc_call_t *call)
    722774{
     775        assert(call);
     776       
    723777        /* Unrouted call - take some default action */
    724778        if ((callid & IPC_CALLID_NOTIFICATION)) {
     
    732786                /* Open new connection with fibril, etc. */
    733787                async_new_connection(call->in_task_hash, IPC_GET_ARG5(*call),
    734                     callid, call, client_connection);
     788                    callid, call, client_connection, NULL);
    735789                return;
    736790        }
     
    752806        futex_down(&async_futex);
    753807       
    754         link_t *cur = timeout_list.next;
    755         while (cur != &timeout_list) {
     808        link_t *cur = list_first(&timeout_list);
     809        while (cur != NULL) {
    756810                awaiter_t *waiter =
    757811                    list_get_instance(cur, awaiter_t, to_event.link);
     
    759813                if (tv_gt(&waiter->to_event.expires, &tv))
    760814                        break;
    761                
    762                 cur = cur->next;
    763815               
    764816                list_remove(&waiter->to_event.link);
     
    774826                        fibril_add_ready(waiter->fid);
    775827                }
     828               
     829                cur = list_first(&timeout_list);
    776830        }
    777831       
     
    800854                suseconds_t timeout;
    801855                if (!list_empty(&timeout_list)) {
    802                         awaiter_t *waiter = list_get_instance(timeout_list.next,
    803                             awaiter_t, to_event.link);
     856                        awaiter_t *waiter = list_get_instance(
     857                            list_first(&timeout_list), awaiter_t, to_event.link);
    804858                       
    805859                        struct timeval tv;
     
    878932void __async_init(void)
    879933{
    880         if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
    881             &client_hash_table_ops))
     934        if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS,
     935            1, &client_hash_table_ops))
    882936                abort();
    883937       
    884         if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1,
    885             &conn_hash_table_ops))
     938        if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS,
     939            1, &conn_hash_table_ops))
    886940                abort();
     941       
     942        session_ns = (async_sess_t *) malloc(sizeof(async_sess_t));
     943        if (session_ns == NULL)
     944                abort();
     945       
     946        session_ns->mgmt = EXCHANGE_ATOMIC;
     947        session_ns->phone = PHONE_NS;
     948        session_ns->arg1 = 0;
     949        session_ns->arg2 = 0;
     950        session_ns->arg3 = 0;
     951       
     952        list_initialize(&session_ns->exch_list);
     953        fibril_mutex_initialize(&session_ns->mutex);
     954        atomic_set(&session_ns->refcnt, 0);
    887955}
    888956
     
    899967 *
    900968 */
    901 static void reply_received(void *arg, int retval, ipc_call_t *data)
    902 {
     969void reply_received(void *arg, int retval, ipc_call_t *data)
     970{
     971        assert(arg);
     972       
    903973        futex_down(&async_futex);
    904974       
     
    9301000 * completion.
    9311001 *
    932  * @param phoneid Handle of the phone that will be used for the send.
    933  * @param method  Service-defined method.
     1002 * @param exch    Exchange for sending the message.
     1003 * @param imethod Service-defined interface and method.
    9341004 * @param arg1    Service-defined payload argument.
    9351005 * @param arg2    Service-defined payload argument.
     
    9421012 *
    9431013 */
    944 aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
     1014aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    9451015    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    9461016{
     1017        if (exch == NULL)
     1018                return 0;
     1019       
    9471020        amsg_t *msg = malloc(sizeof(amsg_t));
    948        
    949         if (!msg)
     1021        if (msg == NULL)
    9501022                return 0;
    9511023       
     
    9611033        msg->wdata.active = true;
    9621034       
    963         ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
     1035        ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
    9641036            reply_received, true);
    9651037       
     
    9721044 * completion.
    9731045 *
    974  * @param phoneid Handle of the phone that will be used for the send.
    975  * @param method  Service-defined method.
     1046 * @param exch    Exchange for sending the message.
     1047 * @param imethod Service-defined interface and method.
    9761048 * @param arg1    Service-defined payload argument.
    9771049 * @param arg2    Service-defined payload argument.
     
    9851057 *
    9861058 */
    987 aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
     1059aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    9881060    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    9891061    ipc_call_t *dataptr)
    9901062{
     1063        if (exch == NULL)
     1064                return 0;
     1065       
    9911066        amsg_t *msg = malloc(sizeof(amsg_t));
    9921067       
    993         if (!msg)
     1068        if (msg == NULL)
    9941069                return 0;
    9951070       
     
    10051080        msg->wdata.active = true;
    10061081       
    1007         ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
    1008             reply_received, true);
     1082        ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
     1083            msg, reply_received, true);
    10091084       
    10101085        return (aid_t) msg;
     
    10201095void async_wait_for(aid_t amsgid, sysarg_t *retval)
    10211096{
     1097        assert(amsgid);
     1098       
    10221099        amsg_t *msg = (amsg_t *) amsgid;
    10231100       
     
    10561133int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout)
    10571134{
     1135        assert(amsgid);
     1136       
    10581137        amsg_t *msg = (amsg_t *) amsgid;
    10591138       
     
    11241203}
    11251204
    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 
    11461205/** Pseudo-synchronous message sending - fast version.
    11471206 *
     
    11511210 * transferring more arguments, see the slower async_req_slow().
    11521211 *
    1153  * @param phoneid Hash of the phone through which to make the call.
    1154  * @param method  Method of the call.
     1212 * @param exch    Exchange for sending the message.
     1213 * @param imethod Interface and method of the call.
    11551214 * @param arg1    Service-defined payload argument.
    11561215 * @param arg2    Service-defined payload argument.
     
    11661225 *
    11671226 */
    1168 sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
     1227sysarg_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    11691228    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
    11701229    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    11711230{
     1231        if (exch == NULL)
     1232                return ENOENT;
     1233       
    11721234        ipc_call_t result;
    1173         aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
     1235        aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
    11741236            &result);
    11751237       
    11761238        sysarg_t rc;
    1177         async_wait_for(eid, &rc);
     1239        async_wait_for(aid, &rc);
    11781240       
    11791241        if (r1)
     
    11991261 * Send message asynchronously and return only after the reply arrives.
    12001262 *
    1201  * @param phoneid Hash of the phone through which to make the call.
    1202  * @param method  Method of the call.
     1263 * @param exch    Exchange for sending the message.
     1264 * @param imethod Interface and method of the call.
    12031265 * @param arg1    Service-defined payload argument.
    12041266 * @param arg2    Service-defined payload argument.
     
    12151277 *
    12161278 */
    1217 sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
     1279sysarg_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    12181280    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
    12191281    sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    12201282{
     1283        if (exch == NULL)
     1284                return ENOENT;
     1285       
    12211286        ipc_call_t result;
    1222         aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
     1287        aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
    12231288            &result);
    12241289       
    12251290        sysarg_t rc;
    1226         async_wait_for(eid, &rc);
     1291        async_wait_for(aid, &rc);
    12271292       
    12281293        if (r1)
     
    12441309}
    12451310
    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);
     1311void async_msg_0(async_exch_t *exch, sysarg_t imethod)
     1312{
     1313        if (exch != NULL)
     1314                ipc_call_async_0(exch->phone, imethod, NULL, NULL, true);
     1315}
     1316
     1317void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
     1318{
     1319        if (exch != NULL)
     1320                ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL, true);
     1321}
     1322
     1323void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1324    sysarg_t arg2)
     1325{
     1326        if (exch != NULL)
     1327                ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL,
     1328                    true);
     1329}
     1330
     1331void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1332    sysarg_t arg2, sysarg_t arg3)
     1333{
     1334        if (exch != NULL)
     1335                ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
     1336                    NULL, true);
     1337}
     1338
     1339void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1340    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
     1341{
     1342        if (exch != NULL)
     1343                ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
     1344                    NULL, NULL, true);
     1345}
     1346
     1347void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1348    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
     1349{
     1350        if (exch != NULL)
     1351                ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
     1352                    arg5, NULL, NULL, true);
    12791353}
    12801354
     
    13131387}
    13141388
    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);
     1389int async_forward_fast(ipc_callid_t callid, async_exch_t *exch,
     1390    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
     1391{
     1392        if (exch == NULL)
     1393                return ENOENT;
     1394       
     1395        return ipc_forward_fast(callid, exch->phone, imethod, arg1, arg2, mode);
     1396}
     1397
     1398int async_forward_slow(ipc_callid_t callid, async_exch_t *exch,
     1399    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
     1400    sysarg_t arg4, sysarg_t arg5, unsigned int mode)
     1401{
     1402        if (exch == NULL)
     1403                return ENOENT;
     1404       
     1405        return ipc_forward_slow(callid, exch->phone, imethod, arg1, arg2, arg3,
     1406            arg4, arg5, mode);
    13271407}
    13281408
     
    13311411 * Ask through phone for a new connection to some service.
    13321412 *
    1333  * @param phone           Phone handle used for contacting the other side.
     1413 * @param exch            Exchange for sending the message.
    13341414 * @param arg1            User defined argument.
    13351415 * @param arg2            User defined argument.
     
    13371417 * @param client_receiver Connection handing routine.
    13381418 *
    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,
    1343     sysarg_t arg3, async_client_conn_t client_receiver)
    1344 {
     1419 * @return Zero on success or a negative error code.
     1420 *
     1421 */
     1422int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
     1423    sysarg_t arg3, async_client_conn_t client_receiver, void *carg)
     1424{
     1425        if (exch == NULL)
     1426                return ENOENT;
     1427       
    13451428        sysarg_t task_hash;
    13461429        sysarg_t phone_hash;
    1347         int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     1430        int rc = async_req_3_5(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
    13481431            NULL, NULL, NULL, &task_hash, &phone_hash);
    13491432        if (rc != EOK)
     
    13521435        if (client_receiver != NULL)
    13531436                async_new_connection(task_hash, phone_hash, 0, NULL,
    1354                     client_receiver);
     1437                    client_receiver, carg);
    13551438       
    13561439        return EOK;
    13571440}
    13581441
    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);
     1442/** Wrapper for making IPC_M_CONNECT_ME calls using the async framework.
     1443 *
     1444 * Ask through for a cloned connection to some service.
     1445 *
     1446 * @param mgmt Exchange management style.
     1447 * @param exch Exchange for sending the message.
     1448 *
     1449 * @return New session on success or NULL on error.
     1450 *
     1451 */
     1452async_sess_t *async_connect_me(exch_mgmt_t mgmt, async_exch_t *exch)
     1453{
     1454        if (exch == NULL) {
     1455                errno = ENOENT;
     1456                return NULL;
     1457        }
     1458       
     1459        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1460        if (sess == NULL) {
     1461                errno = ENOMEM;
     1462                return NULL;
     1463        }
     1464       
     1465        ipc_call_t result;
     1466       
     1467        amsg_t *msg = malloc(sizeof(amsg_t));
     1468        if (msg == NULL) {
     1469                free(sess);
     1470                errno = ENOMEM;
     1471                return NULL;
     1472        }
     1473       
     1474        msg->done = false;
     1475        msg->dataptr = &result;
     1476       
     1477        msg->wdata.to_event.inlist = false;
     1478       
     1479        /*
     1480         * We may sleep in the next method,
     1481         * but it will use its own means
     1482         */
     1483        msg->wdata.active = true;
     1484       
     1485        ipc_call_async_0(exch->phone, IPC_M_CONNECT_ME, msg,
     1486            reply_received, true);
     1487       
     1488        sysarg_t rc;
     1489        async_wait_for((aid_t) msg, &rc);
     1490       
     1491        if (rc != EOK) {
     1492                errno = rc;
     1493                free(sess);
     1494                return NULL;
     1495        }
     1496       
     1497        int phone = (int) IPC_GET_ARG5(result);
     1498       
     1499        if (phone < 0) {
     1500                errno = phone;
     1501                free(sess);
     1502                return NULL;
     1503        }
     1504       
     1505        sess->mgmt = mgmt;
     1506        sess->phone = phone;
     1507        sess->arg1 = 0;
     1508        sess->arg2 = 0;
     1509        sess->arg3 = 0;
     1510       
     1511        list_initialize(&sess->exch_list);
     1512        fibril_mutex_initialize(&sess->mutex);
     1513        atomic_set(&sess->refcnt, 0);
     1514       
     1515        return sess;
     1516}
     1517
     1518static int async_connect_me_to_internal(int phone, sysarg_t arg1, sysarg_t arg2,
     1519    sysarg_t arg3, sysarg_t arg4)
     1520{
     1521        ipc_call_t result;
     1522       
     1523        amsg_t *msg = malloc(sizeof(amsg_t));
     1524        if (msg == NULL)
     1525                return ENOENT;
     1526       
     1527        msg->done = false;
     1528        msg->dataptr = &result;
     1529       
     1530        msg->wdata.to_event.inlist = false;
     1531       
     1532        /*
     1533         * We may sleep in the next method,
     1534         * but it will use its own means
     1535         */
     1536        msg->wdata.active = true;
     1537       
     1538        ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
     1539            msg, reply_received, true);
     1540       
     1541        sysarg_t rc;
     1542        async_wait_for((aid_t) msg, &rc);
    13771543       
    13781544        if (rc != EOK)
    13791545                return rc;
    13801546       
    1381         return newphid;
     1547        return (int) IPC_GET_ARG5(result);
     1548}
     1549
     1550/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
     1551 *
     1552 * Ask through for a new connection to some service.
     1553 *
     1554 * @param mgmt Exchange management style.
     1555 * @param exch Exchange for sending the message.
     1556 * @param arg1 User defined argument.
     1557 * @param arg2 User defined argument.
     1558 * @param arg3 User defined argument.
     1559 *
     1560 * @return New session on success or NULL on error.
     1561 *
     1562 */
     1563async_sess_t *async_connect_me_to(exch_mgmt_t mgmt, async_exch_t *exch,
     1564    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
     1565{
     1566        if (exch == NULL) {
     1567                errno = ENOENT;
     1568                return NULL;
     1569        }
     1570       
     1571        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1572        if (sess == NULL) {
     1573                errno = ENOMEM;
     1574                return NULL;
     1575        }
     1576       
     1577        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
     1578            0);
     1579       
     1580        if (phone < 0) {
     1581                errno = phone;
     1582                free(sess);
     1583                return NULL;
     1584        }
     1585       
     1586        sess->mgmt = mgmt;
     1587        sess->phone = phone;
     1588        sess->arg1 = arg1;
     1589        sess->arg2 = arg2;
     1590        sess->arg3 = arg3;
     1591       
     1592        list_initialize(&sess->exch_list);
     1593        fibril_mutex_initialize(&sess->mutex);
     1594        atomic_set(&sess->refcnt, 0);
     1595       
     1596        return sess;
    13821597}
    13831598
     
    13871602 * success.
    13881603 *
    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;
     1604 * @param mgmt Exchange management style.
     1605 * @param exch Exchange for sending the message.
     1606 * @param arg1 User defined argument.
     1607 * @param arg2 User defined argument.
     1608 * @param arg3 User defined argument.
     1609 *
     1610 * @return New session on success or NULL on error.
     1611 *
     1612 */
     1613async_sess_t *async_connect_me_to_blocking(exch_mgmt_t mgmt, async_exch_t *exch,
     1614    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
     1615{
     1616        if (exch == NULL) {
     1617                errno = ENOENT;
     1618                return NULL;
     1619        }
     1620       
     1621        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1622        if (sess == NULL) {
     1623                errno = ENOMEM;
     1624                return NULL;
     1625        }
     1626       
     1627        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
     1628            IPC_FLAG_BLOCKING);
     1629       
     1630        if (phone < 0) {
     1631                errno = phone;
     1632                free(sess);
     1633                return NULL;
     1634        }
     1635       
     1636        sess->mgmt = mgmt;
     1637        sess->phone = phone;
     1638        sess->arg1 = arg1;
     1639        sess->arg2 = arg2;
     1640        sess->arg3 = arg3;
     1641       
     1642        list_initialize(&sess->exch_list);
     1643        fibril_mutex_initialize(&sess->mutex);
     1644        atomic_set(&sess->refcnt, 0);
     1645       
     1646        return sess;
    14081647}
    14091648
     
    14111650 *
    14121651 */
    1413 int async_connect_kbox(task_id_t id)
    1414 {
    1415         return ipc_connect_kbox(id);
     1652async_sess_t *async_connect_kbox(task_id_t id)
     1653{
     1654        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1655        if (sess == NULL) {
     1656                errno = ENOMEM;
     1657                return NULL;
     1658        }
     1659       
     1660        int phone = ipc_connect_kbox(id);
     1661        if (phone < 0) {
     1662                errno = phone;
     1663                free(sess);
     1664                return NULL;
     1665        }
     1666       
     1667        sess->mgmt = EXCHANGE_ATOMIC;
     1668        sess->phone = phone;
     1669        sess->arg1 = 0;
     1670        sess->arg2 = 0;
     1671        sess->arg3 = 0;
     1672       
     1673        list_initialize(&sess->exch_list);
     1674        fibril_mutex_initialize(&sess->mutex);
     1675        atomic_set(&sess->refcnt, 0);
     1676       
     1677        return sess;
     1678}
     1679
     1680static int async_hangup_internal(int phone)
     1681{
     1682        return ipc_hangup(phone);
    14161683}
    14171684
    14181685/** Wrapper for ipc_hangup.
    14191686 *
    1420  * @param phone Phone handle to hung up.
     1687 * @param sess Session to hung up.
    14211688 *
    14221689 * @return Zero on success or a negative error code.
    14231690 *
    14241691 */
    1425 int async_hangup(int phone)
    1426 {
    1427         return ipc_hangup(phone);
     1692int async_hangup(async_sess_t *sess)
     1693{
     1694        assert(sess);
     1695       
     1696        if (atomic_get(&sess->refcnt) > 0)
     1697                return EBUSY;
     1698       
     1699        int rc = async_hangup_internal(sess->phone);
     1700        if (rc == EOK)
     1701                free(sess);
     1702       
     1703        return rc;
    14281704}
    14291705
     
    14341710}
    14351711
     1712/** Start new exchange in a session.
     1713 *
     1714 * @param session Session.
     1715 *
     1716 * @return New exchange or NULL on error.
     1717 *
     1718 */
     1719async_exch_t *async_exchange_begin(async_sess_t *sess)
     1720{
     1721        if (sess == NULL)
     1722                return NULL;
     1723       
     1724        async_exch_t *exch;
     1725       
     1726        fibril_mutex_lock(&async_sess_mutex);
     1727       
     1728        if (!list_empty(&sess->exch_list)) {
     1729                /*
     1730                 * There are inactive exchanges in the session.
     1731                 */
     1732                exch = (async_exch_t *)
     1733                    list_get_instance(list_first(&sess->exch_list),
     1734                    async_exch_t, sess_link);
     1735               
     1736                list_remove(&exch->sess_link);
     1737                list_remove(&exch->global_link);
     1738        } else {
     1739                /*
     1740                 * There are no available exchanges in the session.
     1741                 */
     1742               
     1743                if ((sess->mgmt == EXCHANGE_ATOMIC) ||
     1744                    (sess->mgmt == EXCHANGE_SERIALIZE)) {
     1745                        exch = (async_exch_t *) malloc(sizeof(async_exch_t));
     1746                        if (exch != NULL) {
     1747                                link_initialize(&exch->sess_link);
     1748                                link_initialize(&exch->global_link);
     1749                                exch->sess = sess;
     1750                                exch->phone = sess->phone;
     1751                        }
     1752                } else {  /* EXCHANGE_PARALLEL */
     1753                        /*
     1754                         * Make a one-time attempt to connect a new data phone.
     1755                         */
     1756                       
     1757                        int phone;
     1758                       
     1759retry:
     1760                        phone = async_connect_me_to_internal(sess->phone, sess->arg1,
     1761                            sess->arg2, sess->arg3, 0);
     1762                        if (phone >= 0) {
     1763                                exch = (async_exch_t *) malloc(sizeof(async_exch_t));
     1764                                if (exch != NULL) {
     1765                                        link_initialize(&exch->sess_link);
     1766                                        link_initialize(&exch->global_link);
     1767                                        exch->sess = sess;
     1768                                        exch->phone = phone;
     1769                                } else
     1770                                        async_hangup_internal(phone);
     1771                        } else if (!list_empty(&inactive_exch_list)) {
     1772                                /*
     1773                                 * We did not manage to connect a new phone. But we
     1774                                 * can try to close some of the currently inactive
     1775                                 * connections in other sessions and try again.
     1776                                 */
     1777                                exch = (async_exch_t *)
     1778                                    list_get_instance(list_first(&inactive_exch_list),
     1779                                    async_exch_t, global_link);
     1780                               
     1781                                list_remove(&exch->sess_link);
     1782                                list_remove(&exch->global_link);
     1783                                async_hangup_internal(exch->phone);
     1784                                free(exch);
     1785                                goto retry;
     1786                        } else {
     1787                                /*
     1788                                 * Wait for a phone to become available.
     1789                                 */
     1790                                fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
     1791                                goto retry;
     1792                        }
     1793                }
     1794        }
     1795       
     1796        fibril_mutex_unlock(&async_sess_mutex);
     1797       
     1798        if (exch != NULL) {
     1799                atomic_inc(&sess->refcnt);
     1800               
     1801                if (sess->mgmt == EXCHANGE_SERIALIZE)
     1802                        fibril_mutex_lock(&sess->mutex);
     1803        }
     1804       
     1805        return exch;
     1806}
     1807
     1808/** Finish an exchange.
     1809 *
     1810 * @param exch Exchange to finish.
     1811 *
     1812 */
     1813void async_exchange_end(async_exch_t *exch)
     1814{
     1815        if (exch == NULL)
     1816                return;
     1817       
     1818        async_sess_t *sess = exch->sess;
     1819       
     1820        atomic_dec(&sess->refcnt);
     1821       
     1822        if (sess->mgmt == EXCHANGE_SERIALIZE)
     1823                fibril_mutex_unlock(&sess->mutex);
     1824       
     1825        fibril_mutex_lock(&async_sess_mutex);
     1826       
     1827        list_append(&exch->sess_link, &sess->exch_list);
     1828        list_append(&exch->global_link, &inactive_exch_list);
     1829        fibril_condvar_signal(&avail_phone_cv);
     1830       
     1831        fibril_mutex_unlock(&async_sess_mutex);
     1832}
     1833
    14361834/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
    14371835 *
    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.
     1836 * @param exch  Exchange for sending the message.
     1837 * @param dst   Destination address space area base.
     1838 * @param size  Size of the destination address space area.
     1839 * @param arg   User defined argument.
     1840 * @param flags Storage for the received flags. Can be NULL.
    14431841 *
    14441842 * @return Zero on success or a negative error code from errno.h.
    14451843 *
    14461844 */
    1447 int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
    1448     unsigned int *flags)
    1449 {
     1845int async_share_in_start(async_exch_t *exch, void *dst, size_t size,
     1846    sysarg_t arg, unsigned int *flags)
     1847{
     1848        if (exch == NULL)
     1849                return ENOENT;
     1850       
    14501851        sysarg_t tmp_flags;
    1451         int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
     1852        int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
    14521853            (sysarg_t) size, arg, NULL, &tmp_flags);
    14531854       
     
    15071908/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
    15081909 *
    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.
     1910 * @param exch  Exchange for sending the message.
     1911 * @param src   Source address space area base address.
     1912 * @param flags Flags to be used for sharing. Bits can be only cleared.
    15121913 *
    15131914 * @return Zero on success or a negative error code from errno.h.
    15141915 *
    15151916 */
    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,
     1917int async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
     1918{
     1919        if (exch == NULL)
     1920                return ENOENT;
     1921       
     1922        return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
    15191923            (sysarg_t) flags);
    15201924}
     
    15691973}
    15701974
     1975/** Start IPC_M_DATA_READ using the async framework.
     1976 *
     1977 * @param exch    Exchange for sending the message.
     1978 * @param dst     Address of the beginning of the destination buffer.
     1979 * @param size    Size of the destination buffer (in bytes).
     1980 * @param dataptr Storage of call data (arg 2 holds actual data size).
     1981 *
     1982 * @return Hash of the sent message or 0 on error.
     1983 *
     1984 */
     1985aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
     1986    ipc_call_t *dataptr)
     1987{
     1988        return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
     1989            (sysarg_t) size, dataptr);
     1990}
     1991
    15711992/** Wrapper for IPC_M_DATA_READ calls using the async framework.
    15721993 *
    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.
     1994 * @param exch Exchange for sending the message.
     1995 * @param dst  Address of the beginning of the destination buffer.
     1996 * @param size Size of the destination buffer.
    15771997 *
    15781998 * @return Zero on success or a negative error code from errno.h.
    15791999 *
    15802000 */
    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);
     2001int async_data_read_start(async_exch_t *exch, void *dst, size_t size)
     2002{
     2003        if (exch == NULL)
     2004                return ENOENT;
     2005       
     2006        return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
     2007            (sysarg_t) size);
    15862008}
    15872009
     
    16382060 *
    16392061 */
    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 {
     2062int async_data_read_forward_fast(async_exch_t *exch, sysarg_t imethod,
     2063    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
     2064    ipc_call_t *dataptr)
     2065{
     2066        if (exch == NULL)
     2067                return ENOENT;
     2068       
    16432069        ipc_callid_t callid;
    16442070        if (!async_data_read_receive(&callid, NULL)) {
     
    16472073        }
    16482074       
    1649         aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
     2075        aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
    16502076            dataptr);
    16512077        if (msg == 0) {
     
    16542080        }
    16552081       
    1656         int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
     2082        int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
    16572083            IPC_FF_ROUTE_FROM_ME);
    16582084        if (retval != EOK) {
     
    16702096/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
    16712097 *
    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.
     2098 * @param exch Exchange for sending the message.
     2099 * @param src  Address of the beginning of the source buffer.
     2100 * @param size Size of the source buffer.
    16762101 *
    16772102 * @return Zero on success or a negative error code from errno.h.
    16782103 *
    16792104 */
    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);
     2105int async_data_write_start(async_exch_t *exch, const void *src, size_t size)
     2106{
     2107        if (exch == NULL)
     2108                return ENOENT;
     2109       
     2110        return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
     2111            (sysarg_t) size);
    16862112}
    16872113
     
    17592185    size_t *received)
    17602186{
     2187        assert(data);
     2188       
    17612189        ipc_callid_t callid;
    17622190        size_t size;
     
    18262254 *
    18272255 */
    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 {
     2256int async_data_write_forward_fast(async_exch_t *exch, sysarg_t imethod,
     2257    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
     2258    ipc_call_t *dataptr)
     2259{
     2260        if (exch == NULL)
     2261                return ENOENT;
     2262       
    18312263        ipc_callid_t callid;
    18322264        if (!async_data_write_receive(&callid, NULL)) {
     
    18352267        }
    18362268       
    1837         aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
     2269        aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
    18382270            dataptr);
    18392271        if (msg == 0) {
     
    18422274        }
    18432275       
    1844         int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
     2276        int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
    18452277            IPC_FF_ROUTE_FROM_ME);
    18462278        if (retval != EOK) {
     
    18562288}
    18572289
     2290/** Wrapper for sending an exchange over different exchange for cloning
     2291 *
     2292 * @param exch       Exchange to be used for sending.
     2293 * @param clone_exch Exchange to be cloned.
     2294 *
     2295 */
     2296int async_exchange_clone(async_exch_t *exch, async_exch_t *clone_exch)
     2297{
     2298        return async_req_1_0(exch, IPC_M_CONNECTION_CLONE, clone_exch->phone);
     2299}
     2300
     2301/** Wrapper for receiving the IPC_M_CONNECTION_CLONE calls.
     2302 *
     2303 * If the current call is IPC_M_CONNECTION_CLONE then a new
     2304 * async session is created for the accepted phone.
     2305 *
     2306 * @param mgmt Exchange management style.
     2307 *
     2308 * @return New async session or NULL on failure.
     2309 *
     2310 */
     2311async_sess_t *async_clone_receive(exch_mgmt_t mgmt)
     2312{
     2313        /* Accept the phone */
     2314        ipc_call_t call;
     2315        ipc_callid_t callid = async_get_call(&call);
     2316        int phone = (int) IPC_GET_ARG1(call);
     2317       
     2318        if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECTION_CLONE) ||
     2319            (phone < 0)) {
     2320                async_answer_0(callid, EINVAL);
     2321                return NULL;
     2322        }
     2323       
     2324        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2325        if (sess == NULL) {
     2326                async_answer_0(callid, ENOMEM);
     2327                return NULL;
     2328        }
     2329       
     2330        sess->mgmt = mgmt;
     2331        sess->phone = phone;
     2332        sess->arg1 = 0;
     2333        sess->arg2 = 0;
     2334        sess->arg3 = 0;
     2335       
     2336        list_initialize(&sess->exch_list);
     2337        fibril_mutex_initialize(&sess->mutex);
     2338        atomic_set(&sess->refcnt, 0);
     2339       
     2340        /* Acknowledge the cloned phone */
     2341        async_answer_0(callid, EOK);
     2342       
     2343        return sess;
     2344}
     2345
     2346/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
     2347 *
     2348 * If the current call is IPC_M_CONNECT_TO_ME then a new
     2349 * async session is created for the accepted phone.
     2350 *
     2351 * @param mgmt Exchange management style.
     2352 *
     2353 * @return New async session.
     2354 * @return NULL on failure.
     2355 *
     2356 */
     2357async_sess_t *async_callback_receive(exch_mgmt_t mgmt)
     2358{
     2359        /* Accept the phone */
     2360        ipc_call_t call;
     2361        ipc_callid_t callid = async_get_call(&call);
     2362        int phone = (int) IPC_GET_ARG5(call);
     2363       
     2364        if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) ||
     2365            (phone < 0)) {
     2366                async_answer_0(callid, EINVAL);
     2367                return NULL;
     2368        }
     2369       
     2370        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2371        if (sess == NULL) {
     2372                async_answer_0(callid, ENOMEM);
     2373                return NULL;
     2374        }
     2375       
     2376        sess->mgmt = mgmt;
     2377        sess->phone = phone;
     2378        sess->arg1 = 0;
     2379        sess->arg2 = 0;
     2380        sess->arg3 = 0;
     2381       
     2382        list_initialize(&sess->exch_list);
     2383        fibril_mutex_initialize(&sess->mutex);
     2384        atomic_set(&sess->refcnt, 0);
     2385       
     2386        /* Acknowledge the connected phone */
     2387        async_answer_0(callid, EOK);
     2388       
     2389        return sess;
     2390}
     2391
     2392/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
     2393 *
     2394 * If the call is IPC_M_CONNECT_TO_ME then a new
     2395 * async session is created. However, the phone is
     2396 * not accepted automatically.
     2397 *
     2398 * @param mgmt   Exchange management style.
     2399 * @param call   Call data.
     2400 *
     2401 * @return New async session.
     2402 * @return NULL on failure.
     2403 * @return NULL if the call is not IPC_M_CONNECT_TO_ME.
     2404 *
     2405 */
     2406async_sess_t *async_callback_receive_start(exch_mgmt_t mgmt, ipc_call_t *call)
     2407{
     2408        int phone = (int) IPC_GET_ARG5(*call);
     2409       
     2410        if ((IPC_GET_IMETHOD(*call) != IPC_M_CONNECT_TO_ME) ||
     2411            (phone < 0))
     2412                return NULL;
     2413       
     2414        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2415        if (sess == NULL)
     2416                return NULL;
     2417       
     2418        sess->mgmt = mgmt;
     2419        sess->phone = phone;
     2420        sess->arg1 = 0;
     2421        sess->arg2 = 0;
     2422        sess->arg3 = 0;
     2423       
     2424        list_initialize(&sess->exch_list);
     2425        fibril_mutex_initialize(&sess->mutex);
     2426        atomic_set(&sess->refcnt, 0);
     2427       
     2428        return sess;
     2429}
     2430
    18582431/** @}
    18592432 */
Note: See TracChangeset for help on using the changeset viewer.