Ignore:
File:
1 edited

Legend:

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

    r9c31643 r58cbf8d5  
    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);
     
    9098#include <ipc/ipc.h>
    9199#include <async.h>
     100#include "private/async.h"
    92101#undef LIBC_ASYNC_C_
    93102
    94103#include <futex.h>
    95104#include <fibril.h>
    96 #include <stdio.h>
    97105#include <adt/hash_table.h>
    98106#include <adt/list.h>
     
    100108#include <errno.h>
    101109#include <sys/time.h>
    102 #include <arch/barrier.h>
     110#include <libarch/barrier.h>
    103111#include <bool.h>
    104 #include "private/async.h"
    105 
     112#include <malloc.h>
     113#include <mem.h>
     114#include <stdlib.h>
     115#include <macros.h>
     116
     117#define CLIENT_HASH_TABLE_BUCKETS  32
     118#define CONN_HASH_TABLE_BUCKETS    32
     119
     120/** Async framework global futex */
    106121atomic_t async_futex = FUTEX_INITIALIZER;
    107122
     
    109124atomic_t threads_in_ipc_wait = { 0 };
    110125
    111 typedef struct {
    112         awaiter_t wdata;
    113        
    114         /** If reply was received. */
    115         bool done;
    116        
    117         /** Pointer to where the answer data is stored. */
    118         ipc_call_t *dataptr;
    119        
    120         sysarg_t retval;
    121 } amsg_t;
    122 
    123 /**
    124  * Structures of this type are used to group information about
    125  * a call and about a message queue link.
    126  */
     126/** Naming service session */
     127async_sess_t *session_ns;
     128
     129/** Call data */
    127130typedef struct {
    128131        link_t link;
     132       
    129133        ipc_callid_t callid;
    130134        ipc_call_t call;
    131135} msg_t;
    132136
     137/* Client connection data */
    133138typedef struct {
    134         sysarg_t in_task_hash;
    135139        link_t link;
    136         int refcnt;
     140       
     141        task_id_t in_task_id;
     142        atomic_t refcnt;
    137143        void *data;
    138144} client_t;
    139145
     146/* Server connection data */
    140147typedef struct {
    141148        awaiter_t wdata;
     
    144151        link_t link;
    145152       
    146         /** Incoming client task hash. */
    147         sysarg_t in_task_hash;
     153        /** Incoming client task ID. */
     154        task_id_t in_task_id;
     155       
    148156        /** Incoming phone hash. */
    149157        sysarg_t in_phone_hash;
     
    153161       
    154162        /** Messages that should be delivered to this fibril. */
    155         link_t msg_queue;
     163        list_t msg_queue;
    156164       
    157165        /** Identification of the opening call. */
     
    159167        /** Call data of the opening call. */
    160168        ipc_call_t call;
     169        /** Local argument or NULL if none. */
     170        void *carg;
    161171       
    162172        /** Identification of the closing call. */
     
    164174       
    165175        /** Fibril function that will be used to handle the connection. */
    166         void (*cfibril)(ipc_callid_t, ipc_call_t *);
     176        async_client_conn_t cfibril;
    167177} connection_t;
    168178
    169179/** Identifier of the incoming connection handled by the current fibril. */
    170 static fibril_local connection_t *FIBRIL_connection;
     180static fibril_local connection_t *fibril_connection;
    171181
    172182static void *default_client_data_constructor(void)
     
    194204}
    195205
    196 void *async_client_data_get(void)
    197 {
    198         assert(FIBRIL_connection);
    199         return FIBRIL_connection->client->data;
    200 }
    201 
    202206/** Default fibril function that gets called to handle new connection.
    203207 *
     
    206210 * @param callid Hash of the incoming call.
    207211 * @param call   Data of the incoming call.
    208  *
    209  */
    210 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
     212 * @param arg    Local argument
     213 *
     214 */
     215static void default_client_connection(ipc_callid_t callid, ipc_call_t *call,
     216    void *arg)
    211217{
    212218        ipc_answer_0(callid, ENOENT);
    213219}
    214 
    215 /**
    216  * Pointer to a fibril function that will be used to handle connections.
    217  */
    218 static async_client_conn_t client_connection = default_client_connection;
    219220
    220221/** Default fibril function that gets called to handle interrupt notifications.
     
    224225 * @param callid Hash of the incoming call.
    225226 * @param call   Data of the incoming call.
     227 * @param arg    Local argument.
    226228 *
    227229 */
     
    230232}
    231233
    232 /**
    233  * Pointer to a fibril function that will be used to handle interrupt
    234  * notifications.
    235  */
    236 static async_client_conn_t interrupt_received = default_interrupt_received;
     234static async_client_conn_t client_connection = default_client_connection;
     235static async_interrupt_handler_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_interrupt_handler_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);
    237271
    238272static hash_table_t client_hash_table;
     
    240274static LIST_INITIALIZE(timeout_list);
    241275
    242 #define CLIENT_HASH_TABLE_BUCKETS  32
    243 #define CONN_HASH_TABLE_BUCKETS    32
    244 
    245276static hash_index_t client_hash(unsigned long key[])
    246277{
    247278        assert(key);
     279       
    248280        return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
    249281}
     
    251283static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
    252284{
     285        assert(key);
     286        assert(keys == 2);
     287        assert(item);
     288       
    253289        client_t *client = hash_table_get_instance(item, client_t, link);
    254         return (key[0] == client->in_task_hash);
     290        return (key[0] == LOWER32(client->in_task_id) &&
     291            (key[1] == UPPER32(client->in_task_id)));
    255292}
    256293
     
    276313{
    277314        assert(key);
     315       
    278316        return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
    279317}
     
    290328static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
    291329{
     330        assert(key);
     331        assert(item);
     332       
    292333        connection_t *conn = hash_table_get_instance(item, connection_t, link);
    293334        return (key[0] == conn->in_phone_hash);
     
    312353void async_insert_timeout(awaiter_t *wd)
    313354{
     355        assert(wd);
     356       
    314357        wd->to_event.occurred = false;
    315358        wd->to_event.inlist = true;
    316359       
    317         link_t *tmp = timeout_list.next;
    318         while (tmp != &timeout_list) {
     360        link_t *tmp = timeout_list.head.next;
     361        while (tmp != &timeout_list.head) {
    319362                awaiter_t *cur
    320363                    = list_get_instance(tmp, awaiter_t, to_event.link);
     
    326369        }
    327370       
    328         list_append(&wd->to_event.link, tmp);
     371        list_insert_before(&wd->to_event.link, tmp);
    329372}
    330373
     
    344387static bool route_call(ipc_callid_t callid, ipc_call_t *call)
    345388{
     389        assert(call);
     390       
    346391        futex_down(&async_futex);
    347392       
     
    398443static int notification_fibril(void *arg)
    399444{
     445        assert(arg);
     446       
    400447        msg_t *msg = (msg_t *) arg;
    401448        interrupt_received(msg->callid, &msg->call);
     
    418465static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
    419466{
     467        assert(call);
     468       
    420469        futex_down(&async_futex);
    421470       
     
    430479       
    431480        fid_t fid = fibril_create(notification_fibril, msg);
     481        if (fid == 0) {
     482                free(msg);
     483                futex_up(&async_futex);
     484                return false;
     485        }
     486       
    432487        fibril_add_ready(fid);
    433488       
     
    450505ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
    451506{
    452         assert(FIBRIL_connection);
     507        assert(call);
     508        assert(fibril_connection);
    453509       
    454510        /* Why doing this?
    455          * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
     511         * GCC 4.1.0 coughs on fibril_connection-> dereference.
    456512         * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
    457513         *           I would never expect to find so many errors in
    458514         *           a compiler.
    459515         */
    460         connection_t *conn = FIBRIL_connection;
     516        connection_t *conn = fibril_connection;
    461517       
    462518        futex_down(&async_futex);
     
    510566        }
    511567       
    512         msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
     568        msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link);
    513569        list_remove(&msg->link);
    514570       
     
    521577}
    522578
     579static client_t *async_client_get(task_id_t client_id, bool create)
     580{
     581        unsigned long key[2] = {
     582                LOWER32(client_id),
     583                UPPER32(client_id),
     584        };
     585        client_t *client = NULL;
     586
     587        futex_down(&async_futex);
     588        link_t *lnk = hash_table_find(&client_hash_table, key);
     589        if (lnk) {
     590                client = hash_table_get_instance(lnk, client_t, link);
     591                atomic_inc(&client->refcnt);
     592        } else if (create) {
     593                client = malloc(sizeof(client_t));
     594                if (client) {
     595                        client->in_task_id = client_id;
     596                        client->data = async_client_data_create();
     597               
     598                        atomic_set(&client->refcnt, 1);
     599                        hash_table_insert(&client_hash_table, key, &client->link);
     600                }
     601        }
     602
     603        futex_up(&async_futex);
     604        return client;
     605}
     606
     607static void async_client_put(client_t *client)
     608{
     609        bool destroy;
     610        unsigned long key[2] = {
     611                LOWER32(client->in_task_id),
     612                UPPER32(client->in_task_id)
     613        };
     614       
     615        futex_down(&async_futex);
     616       
     617        if (atomic_predec(&client->refcnt) == 0) {
     618                hash_table_remove(&client_hash_table, key, 2);
     619                destroy = true;
     620        } else
     621                destroy = false;
     622       
     623        futex_up(&async_futex);
     624       
     625        if (destroy) {
     626                if (client->data)
     627                        async_client_data_destroy(client->data);
     628               
     629                free(client);
     630        }
     631}
     632
     633void *async_get_client_data(void)
     634{
     635        assert(fibril_connection);
     636        return fibril_connection->client->data;
     637}
     638
     639void *async_get_client_data_by_id(task_id_t client_id)
     640{
     641        client_t *client = async_client_get(client_id, false);
     642        if (!client)
     643                return NULL;
     644        if (!client->data) {
     645                async_client_put(client);
     646                return NULL;
     647        }
     648
     649        return client->data;
     650}
     651
     652void async_put_client_data_by_id(task_id_t client_id)
     653{
     654        client_t *client = async_client_get(client_id, false);
     655
     656        assert(client);
     657        assert(client->data);
     658
     659        /* Drop the reference we got in async_get_client_data_by_hash(). */
     660        async_client_put(client);
     661
     662        /* Drop our own reference we got at the beginning of this function. */
     663        async_client_put(client);
     664}
     665
    523666/** Wrapper for client connection fibril.
    524667 *
     
    533676static int connection_fibril(void *arg)
    534677{
     678        assert(arg);
     679       
    535680        /*
    536681         * Setup fibril-local connection pointer.
    537682         */
    538         FIBRIL_connection = (connection_t *) arg;
    539        
    540         futex_down(&async_futex);
     683        fibril_connection = (connection_t *) arg;
    541684       
    542685        /*
     
    545688         * hash in a new tracking structure.
    546689         */
    547        
    548         unsigned long key = FIBRIL_connection->in_task_hash;
    549         link_t *lnk = hash_table_find(&client_hash_table, &key);
    550        
    551         client_t *client;
    552        
    553         if (lnk) {
    554                 client = hash_table_get_instance(lnk, client_t, link);
    555                 client->refcnt++;
    556         } else {
    557                 client = malloc(sizeof(client_t));
    558                 if (!client) {
    559                         ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
    560                         futex_up(&async_futex);
    561                         return 0;
    562                 }
    563                
    564                 client->in_task_hash = FIBRIL_connection->in_task_hash;
    565                
    566                 async_serialize_start();
    567                 client->data = async_client_data_create();
    568                 async_serialize_end();
    569                
    570                 client->refcnt = 1;
    571                 hash_table_insert(&client_hash_table, &key, &client->link);
    572         }
    573        
    574         futex_up(&async_futex);
    575        
    576         FIBRIL_connection->client = client;
     690
     691        client_t *client = async_client_get(fibril_connection->in_task_id, true);
     692        if (!client) {
     693                ipc_answer_0(fibril_connection->callid, ENOMEM);
     694                return 0;
     695        }
     696
     697        fibril_connection->client = client;
    577698       
    578699        /*
    579700         * Call the connection handler function.
    580701         */
    581         FIBRIL_connection->cfibril(FIBRIL_connection->callid,
    582             &FIBRIL_connection->call);
     702        fibril_connection->cfibril(fibril_connection->callid,
     703            &fibril_connection->call, fibril_connection->carg);
    583704       
    584705        /*
    585706         * Remove the reference for this client task connection.
    586707         */
    587         bool destroy;
    588        
    589         futex_down(&async_futex);
    590        
    591         if (--client->refcnt == 0) {
    592                 hash_table_remove(&client_hash_table, &key, 1);
    593                 destroy = true;
    594         } else
    595                 destroy = false;
    596        
    597         futex_up(&async_futex);
    598        
    599         if (destroy) {
    600                 if (client->data)
    601                         async_client_data_destroy(client->data);
    602                
    603                 free(client);
    604         }
     708        async_client_put(client);
    605709       
    606710        /*
     
    608712         */
    609713        futex_down(&async_futex);
    610         key = FIBRIL_connection->in_phone_hash;
     714        unsigned long key = fibril_connection->in_phone_hash;
    611715        hash_table_remove(&conn_hash_table, &key, 1);
    612716        futex_up(&async_futex);
     
    615719         * Answer all remaining messages with EHANGUP.
    616720         */
    617         while (!list_empty(&FIBRIL_connection->msg_queue)) {
     721        while (!list_empty(&fibril_connection->msg_queue)) {
    618722                msg_t *msg =
    619                     list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
    620                     link);
     723                    list_get_instance(list_first(&fibril_connection->msg_queue),
     724                    msg_t, link);
    621725               
    622726                list_remove(&msg->link);
     
    629733         * i.e. IPC_M_PHONE_HUNGUP.
    630734         */
    631         if (FIBRIL_connection->close_callid)
    632                 ipc_answer_0(FIBRIL_connection->close_callid, EOK);
    633        
    634         free(FIBRIL_connection);
     735        if (fibril_connection->close_callid)
     736                ipc_answer_0(fibril_connection->close_callid, EOK);
     737       
     738        free(fibril_connection);
    635739        return 0;
    636740}
     
    638742/** Create a new fibril for a new connection.
    639743 *
    640  * Create new fibril for connection, fill in connection structures and inserts
     744 * Create new fibril for connection, fill in connection structures and insert
    641745 * it into the hash table, so that later we can easily do routing of messages to
    642746 * particular fibrils.
    643747 *
    644  * @param in_task_hash  Identification of the incoming connection.
     748 * @param in_task_id    Identification of the incoming connection.
    645749 * @param in_phone_hash Identification of the incoming connection.
    646750 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
     
    651755 * @param cfibril       Fibril function that should be called upon opening the
    652756 *                      connection.
     757 * @param carg          Extra argument to pass to the connection fibril
    653758 *
    654759 * @return New fibril id or NULL on failure.
    655760 *
    656761 */
    657 fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
     762fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
    658763    ipc_callid_t callid, ipc_call_t *call,
    659     void (*cfibril)(ipc_callid_t, ipc_call_t *))
     764    async_client_conn_t cfibril, void *carg)
    660765{
    661766        connection_t *conn = malloc(sizeof(*conn));
     
    667772        }
    668773       
    669         conn->in_task_hash = in_task_hash;
     774        conn->in_task_id = in_task_id;
    670775        conn->in_phone_hash = in_phone_hash;
    671776        list_initialize(&conn->msg_queue);
    672777        conn->callid = callid;
    673778        conn->close_callid = 0;
     779        conn->carg = carg;
    674780       
    675781        if (call)
     
    681787        conn->wdata.fid = fibril_create(connection_fibril, conn);
    682788       
    683         if (!conn->wdata.fid) {
     789        if (conn->wdata.fid == 0) {
    684790                free(conn);
     791               
    685792                if (callid)
    686793                        ipc_answer_0(callid, ENOMEM);
     794               
    687795                return (uintptr_t) NULL;
    688796        }
     
    711819static void handle_call(ipc_callid_t callid, ipc_call_t *call)
    712820{
     821        assert(call);
     822       
    713823        /* Unrouted call - take some default action */
    714824        if ((callid & IPC_CALLID_NOTIFICATION)) {
     
    721831        case IPC_M_CONNECT_ME_TO:
    722832                /* Open new connection with fibril, etc. */
    723                 async_new_connection(call->in_task_hash, IPC_GET_ARG5(*call),
    724                     callid, call, client_connection);
     833                async_new_connection(call->in_task_id, IPC_GET_ARG5(*call),
     834                    callid, call, client_connection, NULL);
    725835                return;
    726836        }
     
    742852        futex_down(&async_futex);
    743853       
    744         link_t *cur = timeout_list.next;
    745         while (cur != &timeout_list) {
     854        link_t *cur = list_first(&timeout_list);
     855        while (cur != NULL) {
    746856                awaiter_t *waiter =
    747857                    list_get_instance(cur, awaiter_t, to_event.link);
     
    749859                if (tv_gt(&waiter->to_event.expires, &tv))
    750860                        break;
    751                
    752                 cur = cur->next;
    753861               
    754862                list_remove(&waiter->to_event.link);
     
    764872                        fibril_add_ready(waiter->fid);
    765873                }
     874               
     875                cur = list_first(&timeout_list);
    766876        }
    767877       
     
    790900                suseconds_t timeout;
    791901                if (!list_empty(&timeout_list)) {
    792                         awaiter_t *waiter = list_get_instance(timeout_list.next,
    793                             awaiter_t, to_event.link);
     902                        awaiter_t *waiter = list_get_instance(
     903                            list_first(&timeout_list), awaiter_t, to_event.link);
    794904                       
    795905                        struct timeval tv;
     
    853963{
    854964        fid_t fid = fibril_create(async_manager_fibril, NULL);
    855         fibril_add_manager(fid);
     965        if (fid != 0)
     966                fibril_add_manager(fid);
    856967}
    857968
     
    867978void __async_init(void)
    868979{
    869         if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
    870             &client_hash_table_ops))
     980        if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS,
     981            2, &client_hash_table_ops))
    871982                abort();
    872983       
    873         if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1,
    874             &conn_hash_table_ops))
     984        if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS,
     985            1, &conn_hash_table_ops))
    875986                abort();
     987       
     988        session_ns = (async_sess_t *) malloc(sizeof(async_sess_t));
     989        if (session_ns == NULL)
     990                abort();
     991       
     992        session_ns->mgmt = EXCHANGE_ATOMIC;
     993        session_ns->phone = PHONE_NS;
     994        session_ns->arg1 = 0;
     995        session_ns->arg2 = 0;
     996        session_ns->arg3 = 0;
     997       
     998        fibril_mutex_initialize(&session_ns->remote_state_mtx);
     999        session_ns->remote_state_data = NULL;
     1000       
     1001        list_initialize(&session_ns->exch_list);
     1002        fibril_mutex_initialize(&session_ns->mutex);
     1003        atomic_set(&session_ns->refcnt, 0);
    8761004}
    8771005
     
    8881016 *
    8891017 */
    890 static void reply_received(void *arg, int retval, ipc_call_t *data)
    891 {
     1018void reply_received(void *arg, int retval, ipc_call_t *data)
     1019{
     1020        assert(arg);
     1021       
    8921022        futex_down(&async_futex);
    8931023       
     
    9191049 * completion.
    9201050 *
    921  * @param phoneid Handle of the phone that will be used for the send.
    922  * @param method  Service-defined method.
     1051 * @param exch    Exchange for sending the message.
     1052 * @param imethod Service-defined interface and method.
    9231053 * @param arg1    Service-defined payload argument.
    9241054 * @param arg2    Service-defined payload argument.
     
    9311061 *
    9321062 */
    933 aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
     1063aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    9341064    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    9351065{
     1066        if (exch == NULL)
     1067                return 0;
     1068       
    9361069        amsg_t *msg = malloc(sizeof(amsg_t));
    937        
    938         if (!msg)
     1070        if (msg == NULL)
    9391071                return 0;
    9401072       
     
    9501082        msg->wdata.active = true;
    9511083       
    952         ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
     1084        ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
    9531085            reply_received, true);
    9541086       
     
    9611093 * completion.
    9621094 *
    963  * @param phoneid Handle of the phone that will be used for the send.
    964  * @param method  Service-defined method.
     1095 * @param exch    Exchange for sending the message.
     1096 * @param imethod Service-defined interface and method.
    9651097 * @param arg1    Service-defined payload argument.
    9661098 * @param arg2    Service-defined payload argument.
     
    9741106 *
    9751107 */
    976 aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
     1108aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    9771109    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    9781110    ipc_call_t *dataptr)
    9791111{
     1112        if (exch == NULL)
     1113                return 0;
     1114       
    9801115        amsg_t *msg = malloc(sizeof(amsg_t));
    9811116       
    982         if (!msg)
     1117        if (msg == NULL)
    9831118                return 0;
    9841119       
     
    9941129        msg->wdata.active = true;
    9951130       
    996         ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
    997             reply_received, true);
     1131        ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
     1132            msg, reply_received, true);
    9981133       
    9991134        return (aid_t) msg;
     
    10091144void async_wait_for(aid_t amsgid, sysarg_t *retval)
    10101145{
     1146        assert(amsgid);
     1147       
    10111148        amsg_t *msg = (amsg_t *) amsgid;
    10121149       
     
    10451182int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout)
    10461183{
     1184        assert(amsgid);
     1185       
    10471186        amsg_t *msg = (amsg_t *) amsgid;
    10481187       
     
    11131252}
    11141253
    1115 /** Setter for client_connection function pointer.
    1116  *
    1117  * @param conn Function that will implement a new connection fibril.
    1118  *
    1119  */
    1120 void async_set_client_connection(async_client_conn_t conn)
    1121 {
    1122         client_connection = conn;
    1123 }
    1124 
    1125 /** Setter for interrupt_received function pointer.
    1126  *
    1127  * @param intr Function that will implement a new interrupt
    1128  *             notification fibril.
    1129  */
    1130 void async_set_interrupt_received(async_client_conn_t intr)
    1131 {
    1132         interrupt_received = intr;
    1133 }
    1134 
    11351254/** Pseudo-synchronous message sending - fast version.
    11361255 *
     
    11401259 * transferring more arguments, see the slower async_req_slow().
    11411260 *
    1142  * @param phoneid Hash of the phone through which to make the call.
    1143  * @param method  Method of the call.
     1261 * @param exch    Exchange for sending the message.
     1262 * @param imethod Interface and method of the call.
    11441263 * @param arg1    Service-defined payload argument.
    11451264 * @param arg2    Service-defined payload argument.
     
    11551274 *
    11561275 */
    1157 sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
     1276sysarg_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    11581277    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
    11591278    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    11601279{
     1280        if (exch == NULL)
     1281                return ENOENT;
     1282       
    11611283        ipc_call_t result;
    1162         aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
     1284        aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
    11631285            &result);
    11641286       
    11651287        sysarg_t rc;
    1166         async_wait_for(eid, &rc);
     1288        async_wait_for(aid, &rc);
    11671289       
    11681290        if (r1)
     
    11881310 * Send message asynchronously and return only after the reply arrives.
    11891311 *
    1190  * @param phoneid Hash of the phone through which to make the call.
    1191  * @param method  Method of the call.
     1312 * @param exch    Exchange for sending the message.
     1313 * @param imethod Interface and method of the call.
    11921314 * @param arg1    Service-defined payload argument.
    11931315 * @param arg2    Service-defined payload argument.
     
    12041326 *
    12051327 */
    1206 sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
     1328sysarg_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
    12071329    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
    12081330    sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    12091331{
     1332        if (exch == NULL)
     1333                return ENOENT;
     1334       
    12101335        ipc_call_t result;
    1211         aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
     1336        aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
    12121337            &result);
    12131338       
    12141339        sysarg_t rc;
    1215         async_wait_for(eid, &rc);
     1340        async_wait_for(aid, &rc);
    12161341       
    12171342        if (r1)
     
    12331358}
    12341359
    1235 void async_msg_0(int phone, sysarg_t imethod)
    1236 {
    1237         ipc_call_async_0(phone, imethod, NULL, NULL, true);
    1238 }
    1239 
    1240 void async_msg_1(int phone, sysarg_t imethod, sysarg_t arg1)
    1241 {
    1242         ipc_call_async_1(phone, imethod, arg1, NULL, NULL, true);
    1243 }
    1244 
    1245 void async_msg_2(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
    1246 {
    1247         ipc_call_async_2(phone, imethod, arg1, arg2, NULL, NULL, true);
    1248 }
    1249 
    1250 void async_msg_3(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
    1251     sysarg_t arg3)
    1252 {
    1253         ipc_call_async_3(phone, imethod, arg1, arg2, arg3, NULL, NULL, true);
    1254 }
    1255 
    1256 void async_msg_4(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
    1257     sysarg_t arg3, sysarg_t arg4)
    1258 {
    1259         ipc_call_async_4(phone, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
    1260             true);
    1261 }
    1262 
    1263 void async_msg_5(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
    1264     sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
    1265 {
    1266         ipc_call_async_5(phone, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
    1267             NULL, true);
     1360void async_msg_0(async_exch_t *exch, sysarg_t imethod)
     1361{
     1362        if (exch != NULL)
     1363                ipc_call_async_0(exch->phone, imethod, NULL, NULL, true);
     1364}
     1365
     1366void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
     1367{
     1368        if (exch != NULL)
     1369                ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL, true);
     1370}
     1371
     1372void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1373    sysarg_t arg2)
     1374{
     1375        if (exch != NULL)
     1376                ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL,
     1377                    true);
     1378}
     1379
     1380void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1381    sysarg_t arg2, sysarg_t arg3)
     1382{
     1383        if (exch != NULL)
     1384                ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
     1385                    NULL, true);
     1386}
     1387
     1388void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1389    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
     1390{
     1391        if (exch != NULL)
     1392                ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
     1393                    NULL, NULL, true);
     1394}
     1395
     1396void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1397    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
     1398{
     1399        if (exch != NULL)
     1400                ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
     1401                    arg5, NULL, NULL, true);
    12681402}
    12691403
     
    13021436}
    13031437
    1304 int async_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
    1305     sysarg_t arg1, sysarg_t arg2, unsigned int mode)
    1306 {
    1307         return ipc_forward_fast(callid, phoneid, imethod, arg1, arg2, mode);
    1308 }
    1309 
    1310 int async_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
    1311     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    1312     unsigned int mode)
    1313 {
    1314         return ipc_forward_slow(callid, phoneid, imethod, arg1, arg2, arg3, arg4,
    1315             arg5, mode);
     1438int async_forward_fast(ipc_callid_t callid, async_exch_t *exch,
     1439    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
     1440{
     1441        if (exch == NULL)
     1442                return ENOENT;
     1443       
     1444        return ipc_forward_fast(callid, exch->phone, imethod, arg1, arg2, mode);
     1445}
     1446
     1447int async_forward_slow(ipc_callid_t callid, async_exch_t *exch,
     1448    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
     1449    sysarg_t arg4, sysarg_t arg5, unsigned int mode)
     1450{
     1451        if (exch == NULL)
     1452                return ENOENT;
     1453       
     1454        return ipc_forward_slow(callid, exch->phone, imethod, arg1, arg2, arg3,
     1455            arg4, arg5, mode);
    13161456}
    13171457
     
    13201460 * Ask through phone for a new connection to some service.
    13211461 *
    1322  * @param phone           Phone handle used for contacting the other side.
     1462 * @param exch            Exchange for sending the message.
    13231463 * @param arg1            User defined argument.
    13241464 * @param arg2            User defined argument.
     
    13261466 * @param client_receiver Connection handing routine.
    13271467 *
    1328  * @return New phone handle on success or a negative error code.
    1329  *
    1330  */
    1331 int async_connect_to_me(int phone, sysarg_t arg1, sysarg_t arg2,
    1332     sysarg_t arg3, async_client_conn_t client_receiver)
    1333 {
    1334         sysarg_t task_hash;
     1468 * @return Zero on success or a negative error code.
     1469 *
     1470 */
     1471int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
     1472    sysarg_t arg3, async_client_conn_t client_receiver, void *carg)
     1473{
     1474        if (exch == NULL)
     1475                return ENOENT;
     1476       
    13351477        sysarg_t phone_hash;
    1336         int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
    1337             NULL, NULL, NULL, &task_hash, &phone_hash);
     1478        sysarg_t rc;
     1479
     1480        aid_t req;
     1481        ipc_call_t answer;
     1482        req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     1483            &answer);
     1484        async_wait_for(req, &rc);
     1485        if (rc != EOK)
     1486                return (int) rc;
     1487
     1488        phone_hash = IPC_GET_ARG5(answer);
     1489
     1490        if (client_receiver != NULL)
     1491                async_new_connection(answer.in_task_id, phone_hash, 0, NULL,
     1492                    client_receiver, carg);
     1493       
     1494        return EOK;
     1495}
     1496
     1497/** Wrapper for making IPC_M_CONNECT_ME calls using the async framework.
     1498 *
     1499 * Ask through for a cloned connection to some service.
     1500 *
     1501 * @param mgmt Exchange management style.
     1502 * @param exch Exchange for sending the message.
     1503 *
     1504 * @return New session on success or NULL on error.
     1505 *
     1506 */
     1507async_sess_t *async_connect_me(exch_mgmt_t mgmt, async_exch_t *exch)
     1508{
     1509        if (exch == NULL) {
     1510                errno = ENOENT;
     1511                return NULL;
     1512        }
     1513       
     1514        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1515        if (sess == NULL) {
     1516                errno = ENOMEM;
     1517                return NULL;
     1518        }
     1519       
     1520        ipc_call_t result;
     1521       
     1522        amsg_t *msg = malloc(sizeof(amsg_t));
     1523        if (msg == NULL) {
     1524                free(sess);
     1525                errno = ENOMEM;
     1526                return NULL;
     1527        }
     1528       
     1529        msg->done = false;
     1530        msg->dataptr = &result;
     1531       
     1532        msg->wdata.to_event.inlist = false;
     1533       
     1534        /*
     1535         * We may sleep in the next method,
     1536         * but it will use its own means
     1537         */
     1538        msg->wdata.active = true;
     1539       
     1540        ipc_call_async_0(exch->phone, IPC_M_CONNECT_ME, msg,
     1541            reply_received, true);
     1542       
     1543        sysarg_t rc;
     1544        async_wait_for((aid_t) msg, &rc);
     1545       
     1546        if (rc != EOK) {
     1547                errno = rc;
     1548                free(sess);
     1549                return NULL;
     1550        }
     1551       
     1552        int phone = (int) IPC_GET_ARG5(result);
     1553       
     1554        if (phone < 0) {
     1555                errno = phone;
     1556                free(sess);
     1557                return NULL;
     1558        }
     1559       
     1560        sess->mgmt = mgmt;
     1561        sess->phone = phone;
     1562        sess->arg1 = 0;
     1563        sess->arg2 = 0;
     1564        sess->arg3 = 0;
     1565       
     1566        fibril_mutex_initialize(&sess->remote_state_mtx);
     1567        sess->remote_state_data = NULL;
     1568       
     1569        list_initialize(&sess->exch_list);
     1570        fibril_mutex_initialize(&sess->mutex);
     1571        atomic_set(&sess->refcnt, 0);
     1572       
     1573        return sess;
     1574}
     1575
     1576static int async_connect_me_to_internal(int phone, sysarg_t arg1, sysarg_t arg2,
     1577    sysarg_t arg3, sysarg_t arg4)
     1578{
     1579        ipc_call_t result;
     1580       
     1581        amsg_t *msg = malloc(sizeof(amsg_t));
     1582        if (msg == NULL)
     1583                return ENOENT;
     1584       
     1585        msg->done = false;
     1586        msg->dataptr = &result;
     1587       
     1588        msg->wdata.to_event.inlist = false;
     1589       
     1590        /*
     1591         * We may sleep in the next method,
     1592         * but it will use its own means
     1593         */
     1594        msg->wdata.active = true;
     1595       
     1596        ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
     1597            msg, reply_received, true);
     1598       
     1599        sysarg_t rc;
     1600        async_wait_for((aid_t) msg, &rc);
     1601       
    13381602        if (rc != EOK)
    13391603                return rc;
    13401604       
    1341         if (client_receiver != NULL)
    1342                 async_new_connection(task_hash, phone_hash, 0, NULL,
    1343                     client_receiver);
    1344        
    1345         return EOK;
     1605        return (int) IPC_GET_ARG5(result);
    13461606}
    13471607
    13481608/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    13491609 *
    1350  * Ask through phone for a new connection to some service.
    1351  *
    1352  * @param phone Phone handle used for contacting the other side.
    1353  * @param arg1  User defined argument.
    1354  * @param arg2  User defined argument.
    1355  * @param arg3  User defined argument.
    1356  *
    1357  * @return New phone handle on success or a negative error code.
    1358  *
    1359  */
    1360 int async_connect_me_to(int phone, sysarg_t arg1, sysarg_t arg2,
    1361     sysarg_t arg3)
    1362 {
    1363         sysarg_t newphid;
    1364         int rc = async_req_3_5(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
    1365             NULL, NULL, NULL, NULL, &newphid);
    1366        
    1367         if (rc != EOK)
    1368                 return rc;
    1369        
    1370         return newphid;
     1610 * Ask through for a new connection to some service.
     1611 *
     1612 * @param mgmt Exchange management style.
     1613 * @param exch Exchange for sending the message.
     1614 * @param arg1 User defined argument.
     1615 * @param arg2 User defined argument.
     1616 * @param arg3 User defined argument.
     1617 *
     1618 * @return New session on success or NULL on error.
     1619 *
     1620 */
     1621async_sess_t *async_connect_me_to(exch_mgmt_t mgmt, async_exch_t *exch,
     1622    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
     1623{
     1624        if (exch == NULL) {
     1625                errno = ENOENT;
     1626                return NULL;
     1627        }
     1628       
     1629        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1630        if (sess == NULL) {
     1631                errno = ENOMEM;
     1632                return NULL;
     1633        }
     1634       
     1635        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
     1636            0);
     1637       
     1638        if (phone < 0) {
     1639                errno = phone;
     1640                free(sess);
     1641                return NULL;
     1642        }
     1643       
     1644        sess->mgmt = mgmt;
     1645        sess->phone = phone;
     1646        sess->arg1 = arg1;
     1647        sess->arg2 = arg2;
     1648        sess->arg3 = arg3;
     1649       
     1650        fibril_mutex_initialize(&sess->remote_state_mtx);
     1651        sess->remote_state_data = NULL;
     1652       
     1653        list_initialize(&sess->exch_list);
     1654        fibril_mutex_initialize(&sess->mutex);
     1655        atomic_set(&sess->refcnt, 0);
     1656       
     1657        return sess;
    13711658}
    13721659
     
    13761663 * success.
    13771664 *
    1378  * @param phoneid Phone handle used for contacting the other side.
    1379  * @param arg1    User defined argument.
    1380  * @param arg2    User defined argument.
    1381  * @param arg3    User defined argument.
    1382  *
    1383  * @return New phone handle on success or a negative error code.
    1384  *
    1385  */
    1386 int async_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
    1387     sysarg_t arg3)
    1388 {
    1389         sysarg_t newphid;
    1390         int rc = async_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
    1391             IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
    1392        
    1393         if (rc != EOK)
    1394                 return rc;
    1395        
    1396         return newphid;
     1665 * @param mgmt Exchange management style.
     1666 * @param exch Exchange for sending the message.
     1667 * @param arg1 User defined argument.
     1668 * @param arg2 User defined argument.
     1669 * @param arg3 User defined argument.
     1670 *
     1671 * @return New session on success or NULL on error.
     1672 *
     1673 */
     1674async_sess_t *async_connect_me_to_blocking(exch_mgmt_t mgmt, async_exch_t *exch,
     1675    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
     1676{
     1677        if (exch == NULL) {
     1678                errno = ENOENT;
     1679                return NULL;
     1680        }
     1681       
     1682        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1683        if (sess == NULL) {
     1684                errno = ENOMEM;
     1685                return NULL;
     1686        }
     1687       
     1688        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
     1689            IPC_FLAG_BLOCKING);
     1690       
     1691        if (phone < 0) {
     1692                errno = phone;
     1693                free(sess);
     1694                return NULL;
     1695        }
     1696       
     1697        sess->mgmt = mgmt;
     1698        sess->phone = phone;
     1699        sess->arg1 = arg1;
     1700        sess->arg2 = arg2;
     1701        sess->arg3 = arg3;
     1702       
     1703        fibril_mutex_initialize(&sess->remote_state_mtx);
     1704        sess->remote_state_data = NULL;
     1705       
     1706        list_initialize(&sess->exch_list);
     1707        fibril_mutex_initialize(&sess->mutex);
     1708        atomic_set(&sess->refcnt, 0);
     1709       
     1710        return sess;
    13971711}
    13981712
     
    14001714 *
    14011715 */
    1402 int async_connect_kbox(task_id_t id)
    1403 {
    1404         return ipc_connect_kbox(id);
     1716async_sess_t *async_connect_kbox(task_id_t id)
     1717{
     1718        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     1719        if (sess == NULL) {
     1720                errno = ENOMEM;
     1721                return NULL;
     1722        }
     1723       
     1724        int phone = ipc_connect_kbox(id);
     1725        if (phone < 0) {
     1726                errno = phone;
     1727                free(sess);
     1728                return NULL;
     1729        }
     1730       
     1731        sess->mgmt = EXCHANGE_ATOMIC;
     1732        sess->phone = phone;
     1733        sess->arg1 = 0;
     1734        sess->arg2 = 0;
     1735        sess->arg3 = 0;
     1736       
     1737        fibril_mutex_initialize(&sess->remote_state_mtx);
     1738        sess->remote_state_data = NULL;
     1739       
     1740        list_initialize(&sess->exch_list);
     1741        fibril_mutex_initialize(&sess->mutex);
     1742        atomic_set(&sess->refcnt, 0);
     1743       
     1744        return sess;
     1745}
     1746
     1747static int async_hangup_internal(int phone)
     1748{
     1749        return ipc_hangup(phone);
    14051750}
    14061751
    14071752/** Wrapper for ipc_hangup.
    14081753 *
    1409  * @param phone Phone handle to hung up.
     1754 * @param sess Session to hung up.
    14101755 *
    14111756 * @return Zero on success or a negative error code.
    14121757 *
    14131758 */
    1414 int async_hangup(int phone)
    1415 {
    1416         return ipc_hangup(phone);
     1759int async_hangup(async_sess_t *sess)
     1760{
     1761        assert(sess);
     1762       
     1763        if (atomic_get(&sess->refcnt) > 0)
     1764                return EBUSY;
     1765       
     1766        int rc = async_hangup_internal(sess->phone);
     1767        if (rc == EOK)
     1768                free(sess);
     1769       
     1770        return rc;
    14171771}
    14181772
     
    14231777}
    14241778
     1779/** Start new exchange in a session.
     1780 *
     1781 * @param session Session.
     1782 *
     1783 * @return New exchange or NULL on error.
     1784 *
     1785 */
     1786async_exch_t *async_exchange_begin(async_sess_t *sess)
     1787{
     1788        if (sess == NULL)
     1789                return NULL;
     1790       
     1791        async_exch_t *exch;
     1792       
     1793        fibril_mutex_lock(&async_sess_mutex);
     1794       
     1795        if (!list_empty(&sess->exch_list)) {
     1796                /*
     1797                 * There are inactive exchanges in the session.
     1798                 */
     1799                exch = (async_exch_t *)
     1800                    list_get_instance(list_first(&sess->exch_list),
     1801                    async_exch_t, sess_link);
     1802               
     1803                list_remove(&exch->sess_link);
     1804                list_remove(&exch->global_link);
     1805        } else {
     1806                /*
     1807                 * There are no available exchanges in the session.
     1808                 */
     1809               
     1810                if ((sess->mgmt == EXCHANGE_ATOMIC) ||
     1811                    (sess->mgmt == EXCHANGE_SERIALIZE)) {
     1812                        exch = (async_exch_t *) malloc(sizeof(async_exch_t));
     1813                        if (exch != NULL) {
     1814                                link_initialize(&exch->sess_link);
     1815                                link_initialize(&exch->global_link);
     1816                                exch->sess = sess;
     1817                                exch->phone = sess->phone;
     1818                        }
     1819                } else {  /* EXCHANGE_PARALLEL */
     1820                        /*
     1821                         * Make a one-time attempt to connect a new data phone.
     1822                         */
     1823                       
     1824                        int phone;
     1825                       
     1826retry:
     1827                        phone = async_connect_me_to_internal(sess->phone, sess->arg1,
     1828                            sess->arg2, sess->arg3, 0);
     1829                        if (phone >= 0) {
     1830                                exch = (async_exch_t *) malloc(sizeof(async_exch_t));
     1831                                if (exch != NULL) {
     1832                                        link_initialize(&exch->sess_link);
     1833                                        link_initialize(&exch->global_link);
     1834                                        exch->sess = sess;
     1835                                        exch->phone = phone;
     1836                                } else
     1837                                        async_hangup_internal(phone);
     1838                        } else if (!list_empty(&inactive_exch_list)) {
     1839                                /*
     1840                                 * We did not manage to connect a new phone. But we
     1841                                 * can try to close some of the currently inactive
     1842                                 * connections in other sessions and try again.
     1843                                 */
     1844                                exch = (async_exch_t *)
     1845                                    list_get_instance(list_first(&inactive_exch_list),
     1846                                    async_exch_t, global_link);
     1847                               
     1848                                list_remove(&exch->sess_link);
     1849                                list_remove(&exch->global_link);
     1850                                async_hangup_internal(exch->phone);
     1851                                free(exch);
     1852                                goto retry;
     1853                        } else {
     1854                                /*
     1855                                 * Wait for a phone to become available.
     1856                                 */
     1857                                fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
     1858                                goto retry;
     1859                        }
     1860                }
     1861        }
     1862       
     1863        fibril_mutex_unlock(&async_sess_mutex);
     1864       
     1865        if (exch != NULL) {
     1866                atomic_inc(&sess->refcnt);
     1867               
     1868                if (sess->mgmt == EXCHANGE_SERIALIZE)
     1869                        fibril_mutex_lock(&sess->mutex);
     1870        }
     1871       
     1872        return exch;
     1873}
     1874
     1875/** Finish an exchange.
     1876 *
     1877 * @param exch Exchange to finish.
     1878 *
     1879 */
     1880void async_exchange_end(async_exch_t *exch)
     1881{
     1882        if (exch == NULL)
     1883                return;
     1884       
     1885        async_sess_t *sess = exch->sess;
     1886       
     1887        atomic_dec(&sess->refcnt);
     1888       
     1889        if (sess->mgmt == EXCHANGE_SERIALIZE)
     1890                fibril_mutex_unlock(&sess->mutex);
     1891       
     1892        fibril_mutex_lock(&async_sess_mutex);
     1893       
     1894        list_append(&exch->sess_link, &sess->exch_list);
     1895        list_append(&exch->global_link, &inactive_exch_list);
     1896        fibril_condvar_signal(&avail_phone_cv);
     1897       
     1898        fibril_mutex_unlock(&async_sess_mutex);
     1899}
     1900
    14251901/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
    14261902 *
    1427  * @param phoneid Phone that will be used to contact the receiving side.
    1428  * @param dst     Destination address space area base.
    1429  * @param size    Size of the destination address space area.
    1430  * @param arg     User defined argument.
    1431  * @param flags   Storage for the received flags. Can be NULL.
     1903 * @param exch  Exchange for sending the message.
     1904 * @param dst   Destination address space area base.
     1905 * @param size  Size of the destination address space area.
     1906 * @param arg   User defined argument.
     1907 * @param flags Storage for the received flags. Can be NULL.
    14321908 *
    14331909 * @return Zero on success or a negative error code from errno.h.
    14341910 *
    14351911 */
    1436 int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
    1437     unsigned int *flags)
    1438 {
     1912int async_share_in_start(async_exch_t *exch, void *dst, size_t size,
     1913    sysarg_t arg, unsigned int *flags)
     1914{
     1915        if (exch == NULL)
     1916                return ENOENT;
     1917       
    14391918        sysarg_t tmp_flags;
    1440         int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
     1919        int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
    14411920            (sysarg_t) size, arg, NULL, &tmp_flags);
    14421921       
     
    14961975/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
    14971976 *
    1498  * @param phoneid Phone that will be used to contact the receiving side.
    1499  * @param src     Source address space area base address.
    1500  * @param flags   Flags to be used for sharing. Bits can be only cleared.
     1977 * @param exch  Exchange for sending the message.
     1978 * @param src   Source address space area base address.
     1979 * @param flags Flags to be used for sharing. Bits can be only cleared.
    15011980 *
    15021981 * @return Zero on success or a negative error code from errno.h.
    15031982 *
    15041983 */
    1505 int async_share_out_start(int phoneid, void *src, unsigned int flags)
    1506 {
    1507         return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
     1984int async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
     1985{
     1986        if (exch == NULL)
     1987                return ENOENT;
     1988       
     1989        return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
    15081990            (sysarg_t) flags);
    15091991}
     
    15582040}
    15592041
     2042/** Start IPC_M_DATA_READ using the async framework.
     2043 *
     2044 * @param exch    Exchange for sending the message.
     2045 * @param dst     Address of the beginning of the destination buffer.
     2046 * @param size    Size of the destination buffer (in bytes).
     2047 * @param dataptr Storage of call data (arg 2 holds actual data size).
     2048 *
     2049 * @return Hash of the sent message or 0 on error.
     2050 *
     2051 */
     2052aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
     2053    ipc_call_t *dataptr)
     2054{
     2055        return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
     2056            (sysarg_t) size, dataptr);
     2057}
     2058
    15602059/** Wrapper for IPC_M_DATA_READ calls using the async framework.
    15612060 *
    1562  * @param phoneid Phone that will be used to contact the receiving side.
    1563  * @param dst     Address of the beginning of the destination buffer.
    1564  * @param size    Size of the destination buffer.
     2061 * @param exch Exchange for sending the message.
     2062 * @param dst  Address of the beginning of the destination buffer.
     2063 * @param size Size of the destination buffer.
    15652064 *
    15662065 * @return Zero on success or a negative error code from errno.h.
    15672066 *
    15682067 */
    1569 int async_data_read_start(int phoneid, void *dst, size_t size)
    1570 {
    1571         return async_req_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
     2068int async_data_read_start(async_exch_t *exch, void *dst, size_t size)
     2069{
     2070        if (exch == NULL)
     2071                return ENOENT;
     2072       
     2073        return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
    15722074            (sysarg_t) size);
    15732075}
     
    16252127 *
    16262128 */
    1627 int async_data_read_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
    1628     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    1629 {
     2129int async_data_read_forward_fast(async_exch_t *exch, sysarg_t imethod,
     2130    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
     2131    ipc_call_t *dataptr)
     2132{
     2133        if (exch == NULL)
     2134                return ENOENT;
     2135       
    16302136        ipc_callid_t callid;
    16312137        if (!async_data_read_receive(&callid, NULL)) {
     
    16342140        }
    16352141       
    1636         aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
     2142        aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
    16372143            dataptr);
    16382144        if (msg == 0) {
     
    16412147        }
    16422148       
    1643         int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
     2149        int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
    16442150            IPC_FF_ROUTE_FROM_ME);
    16452151        if (retval != EOK) {
     
    16572163/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
    16582164 *
    1659  * @param phoneid Phone that will be used to contact the receiving side.
    1660  * @param src     Address of the beginning of the source buffer.
    1661  * @param size    Size of the source buffer.
     2165 * @param exch Exchange for sending the message.
     2166 * @param src  Address of the beginning of the source buffer.
     2167 * @param size Size of the source buffer.
    16622168 *
    16632169 * @return Zero on success or a negative error code from errno.h.
    16642170 *
    16652171 */
    1666 int async_data_write_start(int phoneid, const void *src, size_t size)
    1667 {
    1668         return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
     2172int async_data_write_start(async_exch_t *exch, const void *src, size_t size)
     2173{
     2174        if (exch == NULL)
     2175                return ENOENT;
     2176       
     2177        return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
    16692178            (sysarg_t) size);
    16702179}
     
    17432252    size_t *received)
    17442253{
     2254        assert(data);
     2255       
    17452256        ipc_callid_t callid;
    17462257        size_t size;
     
    18102321 *
    18112322 */
    1812 int async_data_write_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
    1813     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    1814 {
     2323int async_data_write_forward_fast(async_exch_t *exch, sysarg_t imethod,
     2324    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
     2325    ipc_call_t *dataptr)
     2326{
     2327        if (exch == NULL)
     2328                return ENOENT;
     2329       
    18152330        ipc_callid_t callid;
    18162331        if (!async_data_write_receive(&callid, NULL)) {
     
    18192334        }
    18202335       
    1821         aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
     2336        aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
    18222337            dataptr);
    18232338        if (msg == 0) {
     
    18262341        }
    18272342       
    1828         int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
     2343        int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
    18292344            IPC_FF_ROUTE_FROM_ME);
    18302345        if (retval != EOK) {
     
    18402355}
    18412356
     2357/** Wrapper for sending an exchange over different exchange for cloning
     2358 *
     2359 * @param exch       Exchange to be used for sending.
     2360 * @param clone_exch Exchange to be cloned.
     2361 *
     2362 */
     2363int async_exchange_clone(async_exch_t *exch, async_exch_t *clone_exch)
     2364{
     2365        return async_req_1_0(exch, IPC_M_CONNECTION_CLONE, clone_exch->phone);
     2366}
     2367
     2368/** Wrapper for receiving the IPC_M_CONNECTION_CLONE calls.
     2369 *
     2370 * If the current call is IPC_M_CONNECTION_CLONE then a new
     2371 * async session is created for the accepted phone.
     2372 *
     2373 * @param mgmt Exchange management style.
     2374 *
     2375 * @return New async session or NULL on failure.
     2376 *
     2377 */
     2378async_sess_t *async_clone_receive(exch_mgmt_t mgmt)
     2379{
     2380        /* Accept the phone */
     2381        ipc_call_t call;
     2382        ipc_callid_t callid = async_get_call(&call);
     2383        int phone = (int) IPC_GET_ARG1(call);
     2384       
     2385        if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECTION_CLONE) ||
     2386            (phone < 0)) {
     2387                async_answer_0(callid, EINVAL);
     2388                return NULL;
     2389        }
     2390       
     2391        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2392        if (sess == NULL) {
     2393                async_answer_0(callid, ENOMEM);
     2394                return NULL;
     2395        }
     2396       
     2397        sess->mgmt = mgmt;
     2398        sess->phone = phone;
     2399        sess->arg1 = 0;
     2400        sess->arg2 = 0;
     2401        sess->arg3 = 0;
     2402       
     2403        fibril_mutex_initialize(&sess->remote_state_mtx);
     2404        sess->remote_state_data = NULL;
     2405       
     2406        list_initialize(&sess->exch_list);
     2407        fibril_mutex_initialize(&sess->mutex);
     2408        atomic_set(&sess->refcnt, 0);
     2409       
     2410        /* Acknowledge the cloned phone */
     2411        async_answer_0(callid, EOK);
     2412       
     2413        return sess;
     2414}
     2415
     2416/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
     2417 *
     2418 * If the current call is IPC_M_CONNECT_TO_ME then a new
     2419 * async session is created for the accepted phone.
     2420 *
     2421 * @param mgmt Exchange management style.
     2422 *
     2423 * @return New async session.
     2424 * @return NULL on failure.
     2425 *
     2426 */
     2427async_sess_t *async_callback_receive(exch_mgmt_t mgmt)
     2428{
     2429        /* Accept the phone */
     2430        ipc_call_t call;
     2431        ipc_callid_t callid = async_get_call(&call);
     2432        int phone = (int) IPC_GET_ARG5(call);
     2433       
     2434        if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) ||
     2435            (phone < 0)) {
     2436                async_answer_0(callid, EINVAL);
     2437                return NULL;
     2438        }
     2439       
     2440        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2441        if (sess == NULL) {
     2442                async_answer_0(callid, ENOMEM);
     2443                return NULL;
     2444        }
     2445       
     2446        sess->mgmt = mgmt;
     2447        sess->phone = phone;
     2448        sess->arg1 = 0;
     2449        sess->arg2 = 0;
     2450        sess->arg3 = 0;
     2451       
     2452        fibril_mutex_initialize(&sess->remote_state_mtx);
     2453        sess->remote_state_data = NULL;
     2454       
     2455        list_initialize(&sess->exch_list);
     2456        fibril_mutex_initialize(&sess->mutex);
     2457        atomic_set(&sess->refcnt, 0);
     2458       
     2459        /* Acknowledge the connected phone */
     2460        async_answer_0(callid, EOK);
     2461       
     2462        return sess;
     2463}
     2464
     2465/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
     2466 *
     2467 * If the call is IPC_M_CONNECT_TO_ME then a new
     2468 * async session is created. However, the phone is
     2469 * not accepted automatically.
     2470 *
     2471 * @param mgmt   Exchange management style.
     2472 * @param call   Call data.
     2473 *
     2474 * @return New async session.
     2475 * @return NULL on failure.
     2476 * @return NULL if the call is not IPC_M_CONNECT_TO_ME.
     2477 *
     2478 */
     2479async_sess_t *async_callback_receive_start(exch_mgmt_t mgmt, ipc_call_t *call)
     2480{
     2481        int phone = (int) IPC_GET_ARG5(*call);
     2482       
     2483        if ((IPC_GET_IMETHOD(*call) != IPC_M_CONNECT_TO_ME) ||
     2484            (phone < 0))
     2485                return NULL;
     2486       
     2487        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2488        if (sess == NULL)
     2489                return NULL;
     2490       
     2491        sess->mgmt = mgmt;
     2492        sess->phone = phone;
     2493        sess->arg1 = 0;
     2494        sess->arg2 = 0;
     2495        sess->arg3 = 0;
     2496       
     2497        fibril_mutex_initialize(&sess->remote_state_mtx);
     2498        sess->remote_state_data = NULL;
     2499       
     2500        list_initialize(&sess->exch_list);
     2501        fibril_mutex_initialize(&sess->mutex);
     2502        atomic_set(&sess->refcnt, 0);
     2503       
     2504        return sess;
     2505}
     2506
     2507int async_state_change_start(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
     2508    sysarg_t arg3, async_exch_t *other_exch)
     2509{
     2510        return async_req_5_0(exch, IPC_M_STATE_CHANGE_AUTHORIZE,
     2511            arg1, arg2, arg3, 0, other_exch->phone);
     2512}
     2513
     2514bool async_state_change_receive(ipc_callid_t *callid, sysarg_t *arg1,
     2515    sysarg_t *arg2, sysarg_t *arg3)
     2516{
     2517        assert(callid);
     2518
     2519        ipc_call_t call;
     2520        *callid = async_get_call(&call);
     2521
     2522        if (IPC_GET_IMETHOD(call) != IPC_M_STATE_CHANGE_AUTHORIZE)
     2523                return false;
     2524       
     2525        if (arg1)
     2526                *arg1 = IPC_GET_ARG1(call);
     2527        if (arg2)
     2528                *arg2 = IPC_GET_ARG2(call);
     2529        if (arg3)
     2530                *arg3 = IPC_GET_ARG3(call);
     2531
     2532        return true;
     2533}
     2534
     2535int async_state_change_finalize(ipc_callid_t callid, async_exch_t *other_exch)
     2536{
     2537        return ipc_answer_1(callid, EOK, other_exch->phone);
     2538}
     2539
     2540/** Lock and get session remote state
     2541 *
     2542 * Lock and get the local replica of the remote state
     2543 * in stateful sessions. The call should be paired
     2544 * with async_remote_state_release*().
     2545 *
     2546 * @param[in] sess Stateful session.
     2547 *
     2548 * @return Local replica of the remote state.
     2549 *
     2550 */
     2551void *async_remote_state_acquire(async_sess_t *sess)
     2552{
     2553        fibril_mutex_lock(&sess->remote_state_mtx);
     2554        return sess->remote_state_data;
     2555}
     2556
     2557/** Update the session remote state
     2558 *
     2559 * Update the local replica of the remote state
     2560 * in stateful sessions. The remote state must
     2561 * be already locked.
     2562 *
     2563 * @param[in] sess  Stateful session.
     2564 * @param[in] state New local replica of the remote state.
     2565 *
     2566 */
     2567void async_remote_state_update(async_sess_t *sess, void *state)
     2568{
     2569        assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
     2570        sess->remote_state_data = state;
     2571}
     2572
     2573/** Release the session remote state
     2574 *
     2575 * Unlock the local replica of the remote state
     2576 * in stateful sessions.
     2577 *
     2578 * @param[in] sess Stateful session.
     2579 *
     2580 */
     2581void async_remote_state_release(async_sess_t *sess)
     2582{
     2583        assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
     2584       
     2585        fibril_mutex_unlock(&sess->remote_state_mtx);
     2586}
     2587
     2588/** Release the session remote state and end an exchange
     2589 *
     2590 * Unlock the local replica of the remote state
     2591 * in stateful sessions. This is convenience function
     2592 * which gets the session pointer from the exchange
     2593 * and also ends the exchange.
     2594 *
     2595 * @param[in] exch Stateful session's exchange.
     2596 *
     2597 */
     2598void async_remote_state_release_exchange(async_exch_t *exch)
     2599{
     2600        if (exch == NULL)
     2601                return;
     2602       
     2603        async_sess_t *sess = exch->sess;
     2604        assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
     2605       
     2606        async_exchange_end(exch);
     2607        fibril_mutex_unlock(&sess->remote_state_mtx);
     2608}
     2609
    18422610/** @}
    18432611 */
Note: See TracChangeset for help on using the changeset viewer.