Ignore:
File:
1 edited

Legend:

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

    r58cbf8d5 r9c31643  
    4040 * programming.
    4141 *
    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.
     42 * You should be able to write very simple multithreaded programs, the async
     43 * framework will automatically take care of most synchronization problems.
    4544 *
    4645 * Example of use (pseudo C):
     
    5453 *   int fibril1(void *arg)
    5554 *   {
    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  *
     55 *     conn = async_connect_me_to();
     56 *     c1 = async_send(conn);
     57 *     c2 = async_send(conn);
    6658 *     async_wait_for(c1);
    6759 *     async_wait_for(c2);
     
    9890#include <ipc/ipc.h>
    9991#include <async.h>
    100 #include "private/async.h"
    10192#undef LIBC_ASYNC_C_
    10293
    10394#include <futex.h>
    10495#include <fibril.h>
     96#include <stdio.h>
    10597#include <adt/hash_table.h>
    10698#include <adt/list.h>
     
    108100#include <errno.h>
    109101#include <sys/time.h>
    110 #include <libarch/barrier.h>
     102#include <arch/barrier.h>
    111103#include <bool.h>
    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 */
     104#include "private/async.h"
     105
    121106atomic_t async_futex = FUTEX_INITIALIZER;
    122107
     
    124109atomic_t threads_in_ipc_wait = { 0 };
    125110
    126 /** Naming service session */
    127 async_sess_t *session_ns;
    128 
    129 /** Call data */
     111typedef 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 */
    130127typedef struct {
    131128        link_t link;
    132        
    133129        ipc_callid_t callid;
    134130        ipc_call_t call;
    135131} msg_t;
    136132
    137 /* Client connection data */
    138133typedef struct {
     134        sysarg_t in_task_hash;
    139135        link_t link;
    140        
    141         task_id_t in_task_id;
    142         atomic_t refcnt;
     136        int refcnt;
    143137        void *data;
    144138} client_t;
    145139
    146 /* Server connection data */
    147140typedef struct {
    148141        awaiter_t wdata;
     
    151144        link_t link;
    152145       
    153         /** Incoming client task ID. */
    154         task_id_t in_task_id;
    155        
     146        /** Incoming client task hash. */
     147        sysarg_t in_task_hash;
    156148        /** Incoming phone hash. */
    157149        sysarg_t in_phone_hash;
     
    161153       
    162154        /** Messages that should be delivered to this fibril. */
    163         list_t msg_queue;
     155        link_t msg_queue;
    164156       
    165157        /** Identification of the opening call. */
     
    167159        /** Call data of the opening call. */
    168160        ipc_call_t call;
    169         /** Local argument or NULL if none. */
    170         void *carg;
    171161       
    172162        /** Identification of the closing call. */
     
    174164       
    175165        /** Fibril function that will be used to handle the connection. */
    176         async_client_conn_t cfibril;
     166        void (*cfibril)(ipc_callid_t, ipc_call_t *);
    177167} connection_t;
    178168
    179169/** Identifier of the incoming connection handled by the current fibril. */
    180 static fibril_local connection_t *fibril_connection;
     170static fibril_local connection_t *FIBRIL_connection;
    181171
    182172static void *default_client_data_constructor(void)
     
    204194}
    205195
     196void *async_client_data_get(void)
     197{
     198        assert(FIBRIL_connection);
     199        return FIBRIL_connection->client->data;
     200}
     201
    206202/** Default fibril function that gets called to handle new connection.
    207203 *
     
    210206 * @param callid Hash of the incoming call.
    211207 * @param call   Data of the incoming call.
    212  * @param arg    Local argument
    213  *
    214  */
    215 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call,
    216     void *arg)
     208 *
     209 */
     210static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
    217211{
    218212        ipc_answer_0(callid, ENOENT);
    219213}
     214
     215/**
     216 * Pointer to a fibril function that will be used to handle connections.
     217 */
     218static async_client_conn_t client_connection = default_client_connection;
    220219
    221220/** Default fibril function that gets called to handle interrupt notifications.
     
    225224 * @param callid Hash of the incoming call.
    226225 * @param call   Data of the incoming call.
    227  * @param arg    Local argument.
    228226 *
    229227 */
     
    232230}
    233231
    234 static async_client_conn_t client_connection = default_client_connection;
    235 static 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  */
    242 void 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  */
    252 void 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  */
    260 static FIBRIL_MUTEX_INITIALIZE(async_sess_mutex);
    261 
    262 /** List of all currently inactive exchanges.
    263  *
    264  */
    265 static LIST_INITIALIZE(inactive_exch_list);
    266 
    267 /** Condition variable to wait for a phone to become available.
    268  *
    269  */
    270 static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
     232/**
     233 * Pointer to a fibril function that will be used to handle interrupt
     234 * notifications.
     235 */
     236static async_client_conn_t interrupt_received = default_interrupt_received;
    271237
    272238static hash_table_t client_hash_table;
     
    274240static LIST_INITIALIZE(timeout_list);
    275241
     242#define CLIENT_HASH_TABLE_BUCKETS  32
     243#define CONN_HASH_TABLE_BUCKETS    32
     244
    276245static hash_index_t client_hash(unsigned long key[])
    277246{
    278247        assert(key);
    279        
    280248        return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
    281249}
     
    283251static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
    284252{
    285         assert(key);
    286         assert(keys == 2);
    287         assert(item);
    288        
    289253        client_t *client = hash_table_get_instance(item, client_t, link);
    290         return (key[0] == LOWER32(client->in_task_id) &&
    291             (key[1] == UPPER32(client->in_task_id)));
     254        return (key[0] == client->in_task_hash);
    292255}
    293256
     
    313276{
    314277        assert(key);
    315        
    316278        return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
    317279}
     
    328290static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
    329291{
    330         assert(key);
    331         assert(item);
    332        
    333292        connection_t *conn = hash_table_get_instance(item, connection_t, link);
    334293        return (key[0] == conn->in_phone_hash);
     
    353312void async_insert_timeout(awaiter_t *wd)
    354313{
    355         assert(wd);
    356        
    357314        wd->to_event.occurred = false;
    358315        wd->to_event.inlist = true;
    359316       
    360         link_t *tmp = timeout_list.head.next;
    361         while (tmp != &timeout_list.head) {
     317        link_t *tmp = timeout_list.next;
     318        while (tmp != &timeout_list) {
    362319                awaiter_t *cur
    363320                    = list_get_instance(tmp, awaiter_t, to_event.link);
     
    369326        }
    370327       
    371         list_insert_before(&wd->to_event.link, tmp);
     328        list_append(&wd->to_event.link, tmp);
    372329}
    373330
     
    387344static bool route_call(ipc_callid_t callid, ipc_call_t *call)
    388345{
    389         assert(call);
    390        
    391346        futex_down(&async_futex);
    392347       
     
    443398static int notification_fibril(void *arg)
    444399{
    445         assert(arg);
    446        
    447400        msg_t *msg = (msg_t *) arg;
    448401        interrupt_received(msg->callid, &msg->call);
     
    465418static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
    466419{
    467         assert(call);
    468        
    469420        futex_down(&async_futex);
    470421       
     
    479430       
    480431        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        
    487432        fibril_add_ready(fid);
    488433       
     
    505450ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
    506451{
    507         assert(call);
    508         assert(fibril_connection);
     452        assert(FIBRIL_connection);
    509453       
    510454        /* Why doing this?
    511          * GCC 4.1.0 coughs on fibril_connection-> dereference.
     455         * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
    512456         * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
    513457         *           I would never expect to find so many errors in
    514458         *           a compiler.
    515459         */
    516         connection_t *conn = fibril_connection;
     460        connection_t *conn = FIBRIL_connection;
    517461       
    518462        futex_down(&async_futex);
     
    566510        }
    567511       
    568         msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link);
     512        msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
    569513        list_remove(&msg->link);
    570514       
     
    577521}
    578522
    579 static 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 
    607 static 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 
    633 void *async_get_client_data(void)
    634 {
    635         assert(fibril_connection);
    636         return fibril_connection->client->data;
    637 }
    638 
    639 void *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 
    652 void 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 
    666523/** Wrapper for client connection fibril.
    667524 *
     
    676533static int connection_fibril(void *arg)
    677534{
    678         assert(arg);
    679        
    680535        /*
    681536         * Setup fibril-local connection pointer.
    682537         */
    683         fibril_connection = (connection_t *) arg;
     538        FIBRIL_connection = (connection_t *) arg;
     539       
     540        futex_down(&async_futex);
    684541       
    685542        /*
     
    688545         * hash in a new tracking structure.
    689546         */
    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;
     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;
    698577       
    699578        /*
    700579         * Call the connection handler function.
    701580         */
    702         fibril_connection->cfibril(fibril_connection->callid,
    703             &fibril_connection->call, fibril_connection->carg);
     581        FIBRIL_connection->cfibril(FIBRIL_connection->callid,
     582            &FIBRIL_connection->call);
    704583       
    705584        /*
    706585         * Remove the reference for this client task connection.
    707586         */
    708         async_client_put(client);
     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        }
    709605       
    710606        /*
     
    712608         */
    713609        futex_down(&async_futex);
    714         unsigned long key = fibril_connection->in_phone_hash;
     610        key = FIBRIL_connection->in_phone_hash;
    715611        hash_table_remove(&conn_hash_table, &key, 1);
    716612        futex_up(&async_futex);
     
    719615         * Answer all remaining messages with EHANGUP.
    720616         */
    721         while (!list_empty(&fibril_connection->msg_queue)) {
     617        while (!list_empty(&FIBRIL_connection->msg_queue)) {
    722618                msg_t *msg =
    723                     list_get_instance(list_first(&fibril_connection->msg_queue),
    724                     msg_t, link);
     619                    list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
     620                    link);
    725621               
    726622                list_remove(&msg->link);
     
    733629         * i.e. IPC_M_PHONE_HUNGUP.
    734630         */
    735         if (fibril_connection->close_callid)
    736                 ipc_answer_0(fibril_connection->close_callid, EOK);
    737        
    738         free(fibril_connection);
     631        if (FIBRIL_connection->close_callid)
     632                ipc_answer_0(FIBRIL_connection->close_callid, EOK);
     633       
     634        free(FIBRIL_connection);
    739635        return 0;
    740636}
     
    742638/** Create a new fibril for a new connection.
    743639 *
    744  * Create new fibril for connection, fill in connection structures and insert
     640 * Create new fibril for connection, fill in connection structures and inserts
    745641 * it into the hash table, so that later we can easily do routing of messages to
    746642 * particular fibrils.
    747643 *
    748  * @param in_task_id    Identification of the incoming connection.
     644 * @param in_task_hash  Identification of the incoming connection.
    749645 * @param in_phone_hash Identification of the incoming connection.
    750646 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
     
    755651 * @param cfibril       Fibril function that should be called upon opening the
    756652 *                      connection.
    757  * @param carg          Extra argument to pass to the connection fibril
    758653 *
    759654 * @return New fibril id or NULL on failure.
    760655 *
    761656 */
    762 fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
     657fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
    763658    ipc_callid_t callid, ipc_call_t *call,
    764     async_client_conn_t cfibril, void *carg)
     659    void (*cfibril)(ipc_callid_t, ipc_call_t *))
    765660{
    766661        connection_t *conn = malloc(sizeof(*conn));
     
    772667        }
    773668       
    774         conn->in_task_id = in_task_id;
     669        conn->in_task_hash = in_task_hash;
    775670        conn->in_phone_hash = in_phone_hash;
    776671        list_initialize(&conn->msg_queue);
    777672        conn->callid = callid;
    778673        conn->close_callid = 0;
    779         conn->carg = carg;
    780674       
    781675        if (call)
     
    787681        conn->wdata.fid = fibril_create(connection_fibril, conn);
    788682       
    789         if (conn->wdata.fid == 0) {
     683        if (!conn->wdata.fid) {
    790684                free(conn);
    791                
    792685                if (callid)
    793686                        ipc_answer_0(callid, ENOMEM);
    794                
    795687                return (uintptr_t) NULL;
    796688        }
     
    819711static void handle_call(ipc_callid_t callid, ipc_call_t *call)
    820712{
    821         assert(call);
    822        
    823713        /* Unrouted call - take some default action */
    824714        if ((callid & IPC_CALLID_NOTIFICATION)) {
     
    831721        case IPC_M_CONNECT_ME_TO:
    832722                /* Open new connection with fibril, etc. */
    833                 async_new_connection(call->in_task_id, IPC_GET_ARG5(*call),
    834                     callid, call, client_connection, NULL);
     723                async_new_connection(call->in_task_hash, IPC_GET_ARG5(*call),
     724                    callid, call, client_connection);
    835725                return;
    836726        }
     
    852742        futex_down(&async_futex);
    853743       
    854         link_t *cur = list_first(&timeout_list);
    855         while (cur != NULL) {
     744        link_t *cur = timeout_list.next;
     745        while (cur != &timeout_list) {
    856746                awaiter_t *waiter =
    857747                    list_get_instance(cur, awaiter_t, to_event.link);
     
    859749                if (tv_gt(&waiter->to_event.expires, &tv))
    860750                        break;
     751               
     752                cur = cur->next;
    861753               
    862754                list_remove(&waiter->to_event.link);
     
    872764                        fibril_add_ready(waiter->fid);
    873765                }
    874                
    875                 cur = list_first(&timeout_list);
    876766        }
    877767       
     
    900790                suseconds_t timeout;
    901791                if (!list_empty(&timeout_list)) {
    902                         awaiter_t *waiter = list_get_instance(
    903                             list_first(&timeout_list), awaiter_t, to_event.link);
     792                        awaiter_t *waiter = list_get_instance(timeout_list.next,
     793                            awaiter_t, to_event.link);
    904794                       
    905795                        struct timeval tv;
     
    963853{
    964854        fid_t fid = fibril_create(async_manager_fibril, NULL);
    965         if (fid != 0)
    966                 fibril_add_manager(fid);
     855        fibril_add_manager(fid);
    967856}
    968857
     
    978867void __async_init(void)
    979868{
    980         if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS,
    981             2, &client_hash_table_ops))
     869        if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
     870            &client_hash_table_ops))
    982871                abort();
    983872       
    984         if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS,
    985             1, &conn_hash_table_ops))
     873        if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1,
     874            &conn_hash_table_ops))
    986875                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);
    1004876}
    1005877
     
    1016888 *
    1017889 */
    1018 void reply_received(void *arg, int retval, ipc_call_t *data)
    1019 {
    1020         assert(arg);
    1021        
     890static void reply_received(void *arg, int retval, ipc_call_t *data)
     891{
    1022892        futex_down(&async_futex);
    1023893       
     
    1049919 * completion.
    1050920 *
    1051  * @param exch    Exchange for sending the message.
    1052  * @param imethod Service-defined interface and method.
     921 * @param phoneid Handle of the phone that will be used for the send.
     922 * @param method  Service-defined method.
    1053923 * @param arg1    Service-defined payload argument.
    1054924 * @param arg2    Service-defined payload argument.
     
    1061931 *
    1062932 */
    1063 aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     933aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
    1064934    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
    1065935{
    1066         if (exch == NULL)
    1067                 return 0;
    1068        
    1069936        amsg_t *msg = malloc(sizeof(amsg_t));
    1070         if (msg == NULL)
     937       
     938        if (!msg)
    1071939                return 0;
    1072940       
     
    1082950        msg->wdata.active = true;
    1083951       
    1084         ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
     952        ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
    1085953            reply_received, true);
    1086954       
     
    1093961 * completion.
    1094962 *
    1095  * @param exch    Exchange for sending the message.
    1096  * @param imethod Service-defined interface and method.
     963 * @param phoneid Handle of the phone that will be used for the send.
     964 * @param method  Service-defined method.
    1097965 * @param arg1    Service-defined payload argument.
    1098966 * @param arg2    Service-defined payload argument.
     
    1106974 *
    1107975 */
    1108 aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     976aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
    1109977    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
    1110978    ipc_call_t *dataptr)
    1111979{
    1112         if (exch == NULL)
    1113                 return 0;
    1114        
    1115980        amsg_t *msg = malloc(sizeof(amsg_t));
    1116981       
    1117         if (msg == NULL)
     982        if (!msg)
    1118983                return 0;
    1119984       
     
    1129994        msg->wdata.active = true;
    1130995       
    1131         ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
    1132             msg, reply_received, true);
     996        ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
     997            reply_received, true);
    1133998       
    1134999        return (aid_t) msg;
     
    11441009void async_wait_for(aid_t amsgid, sysarg_t *retval)
    11451010{
    1146         assert(amsgid);
    1147        
    11481011        amsg_t *msg = (amsg_t *) amsgid;
    11491012       
     
    11821045int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout)
    11831046{
    1184         assert(amsgid);
    1185        
    11861047        amsg_t *msg = (amsg_t *) amsgid;
    11871048       
     
    12521113}
    12531114
     1115/** Setter for client_connection function pointer.
     1116 *
     1117 * @param conn Function that will implement a new connection fibril.
     1118 *
     1119 */
     1120void 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 */
     1130void async_set_interrupt_received(async_client_conn_t intr)
     1131{
     1132        interrupt_received = intr;
     1133}
     1134
    12541135/** Pseudo-synchronous message sending - fast version.
    12551136 *
     
    12591140 * transferring more arguments, see the slower async_req_slow().
    12601141 *
    1261  * @param exch    Exchange for sending the message.
    1262  * @param imethod Interface and method of the call.
     1142 * @param phoneid Hash of the phone through which to make the call.
     1143 * @param method  Method of the call.
    12631144 * @param arg1    Service-defined payload argument.
    12641145 * @param arg2    Service-defined payload argument.
     
    12741155 *
    12751156 */
    1276 sysarg_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1157sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
    12771158    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
    12781159    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    12791160{
    1280         if (exch == NULL)
    1281                 return ENOENT;
    1282        
    12831161        ipc_call_t result;
    1284         aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
     1162        aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
    12851163            &result);
    12861164       
    12871165        sysarg_t rc;
    1288         async_wait_for(aid, &rc);
     1166        async_wait_for(eid, &rc);
    12891167       
    12901168        if (r1)
     
    13101188 * Send message asynchronously and return only after the reply arrives.
    13111189 *
    1312  * @param exch    Exchange for sending the message.
    1313  * @param imethod Interface and method of the call.
     1190 * @param phoneid Hash of the phone through which to make the call.
     1191 * @param method  Method of the call.
    13141192 * @param arg1    Service-defined payload argument.
    13151193 * @param arg2    Service-defined payload argument.
     
    13261204 *
    13271205 */
    1328 sysarg_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     1206sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
    13291207    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
    13301208    sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
    13311209{
    1332         if (exch == NULL)
    1333                 return ENOENT;
    1334        
    13351210        ipc_call_t result;
    1336         aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
     1211        aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
    13371212            &result);
    13381213       
    13391214        sysarg_t rc;
    1340         async_wait_for(aid, &rc);
     1215        async_wait_for(eid, &rc);
    13411216       
    13421217        if (r1)
     
    13581233}
    13591234
    1360 void 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 
    1366 void 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 
    1372 void 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 
    1380 void 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 
    1388 void 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 
    1396 void 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);
     1235void async_msg_0(int phone, sysarg_t imethod)
     1236{
     1237        ipc_call_async_0(phone, imethod, NULL, NULL, true);
     1238}
     1239
     1240void 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
     1245void 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
     1250void 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
     1256void 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
     1263void 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);
    14021268}
    14031269
     
    14361302}
    14371303
    1438 int 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 
    1447 int 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);
     1304int 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
     1310int 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);
    14561316}
    14571317
     
    14601320 * Ask through phone for a new connection to some service.
    14611321 *
    1462  * @param exch            Exchange for sending the message.
     1322 * @param phone           Phone handle used for contacting the other side.
    14631323 * @param arg1            User defined argument.
    14641324 * @param arg2            User defined argument.
     
    14661326 * @param client_receiver Connection handing routine.
    14671327 *
    1468  * @return Zero on success or a negative error code.
    1469  *
    1470  */
    1471 int 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        
     1328 * @return New phone handle on success or a negative error code.
     1329 *
     1330 */
     1331int 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;
    14771335        sysarg_t 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  */
    1507 async_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 
    1576 static 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        
     1336        int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     1337            NULL, NULL, NULL, &task_hash, &phone_hash);
    16021338        if (rc != EOK)
    16031339                return rc;
    16041340       
    1605         return (int) IPC_GET_ARG5(result);
     1341        if (client_receiver != NULL)
     1342                async_new_connection(task_hash, phone_hash, 0, NULL,
     1343                    client_receiver);
     1344       
     1345        return EOK;
    16061346}
    16071347
    16081348/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
    16091349 *
    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  */
    1621 async_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;
     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 */
     1360int 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;
    16581371}
    16591372
     
    16631376 * success.
    16641377 *
    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  */
    1674 async_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;
     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 */
     1386int 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;
    17111397}
    17121398
     
    17141400 *
    17151401 */
    1716 async_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 
    1747 static int async_hangup_internal(int phone)
     1402int async_connect_kbox(task_id_t id)
     1403{
     1404        return ipc_connect_kbox(id);
     1405}
     1406
     1407/** Wrapper for ipc_hangup.
     1408 *
     1409 * @param phone Phone handle to hung up.
     1410 *
     1411 * @return Zero on success or a negative error code.
     1412 *
     1413 */
     1414int async_hangup(int phone)
    17481415{
    17491416        return ipc_hangup(phone);
    1750 }
    1751 
    1752 /** Wrapper for ipc_hangup.
    1753  *
    1754  * @param sess Session to hung up.
    1755  *
    1756  * @return Zero on success or a negative error code.
    1757  *
    1758  */
    1759 int 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;
    17711417}
    17721418
     
    17771423}
    17781424
    1779 /** Start new exchange in a session.
    1780  *
    1781  * @param session Session.
    1782  *
    1783  * @return New exchange or NULL on error.
    1784  *
    1785  */
    1786 async_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                        
    1826 retry:
    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  */
    1880 void 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 
    19011425/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
    19021426 *
    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.
     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.
    19081432 *
    19091433 * @return Zero on success or a negative error code from errno.h.
    19101434 *
    19111435 */
    1912 int 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        
     1436int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
     1437    unsigned int *flags)
     1438{
    19181439        sysarg_t tmp_flags;
    1919         int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
     1440        int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
    19201441            (sysarg_t) size, arg, NULL, &tmp_flags);
    19211442       
     
    19751496/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
    19761497 *
    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.
     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.
    19801501 *
    19811502 * @return Zero on success or a negative error code from errno.h.
    19821503 *
    19831504 */
    1984 int 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,
     1505int 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,
    19901508            (sysarg_t) flags);
    19911509}
     
    20401558}
    20411559
    2042 /** Start IPC_M_DATA_READ using the async framework.
    2043  *
    2044  * @param exch    Exchange for sending the message.
     1560/** Wrapper for IPC_M_DATA_READ calls using the async framework.
     1561 *
     1562 * @param phoneid Phone that will be used to contact the receiving side.
    20451563 * @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  */
    2052 aid_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 
    2059 /** Wrapper for IPC_M_DATA_READ calls using the async framework.
    2060  *
    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.
     1564 * @param size    Size of the destination buffer.
    20641565 *
    20651566 * @return Zero on success or a negative error code from errno.h.
    20661567 *
    20671568 */
    2068 int 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,
     1569int 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,
    20741572            (sysarg_t) size);
    20751573}
     
    21271625 *
    21281626 */
    2129 int 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        
     1627int 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{
    21361630        ipc_callid_t callid;
    21371631        if (!async_data_read_receive(&callid, NULL)) {
     
    21401634        }
    21411635       
    2142         aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
     1636        aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
    21431637            dataptr);
    21441638        if (msg == 0) {
     
    21471641        }
    21481642       
    2149         int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
     1643        int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
    21501644            IPC_FF_ROUTE_FROM_ME);
    21511645        if (retval != EOK) {
     
    21631657/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
    21641658 *
    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.
     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.
    21681662 *
    21691663 * @return Zero on success or a negative error code from errno.h.
    21701664 *
    21711665 */
    2172 int 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,
     1666int 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,
    21781669            (sysarg_t) size);
    21791670}
     
    22521743    size_t *received)
    22531744{
    2254         assert(data);
    2255        
    22561745        ipc_callid_t callid;
    22571746        size_t size;
     
    23211810 *
    23221811 */
    2323 int 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        
     1812int 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{
    23301815        ipc_callid_t callid;
    23311816        if (!async_data_write_receive(&callid, NULL)) {
     
    23341819        }
    23351820       
    2336         aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
     1821        aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
    23371822            dataptr);
    23381823        if (msg == 0) {
     
    23411826        }
    23421827       
    2343         int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
     1828        int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
    23441829            IPC_FF_ROUTE_FROM_ME);
    23451830        if (retval != EOK) {
     
    23551840}
    23561841
    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  */
    2363 int 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  */
    2378 async_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  */
    2427 async_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  */
    2479 async_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 
    2507 int 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 
    2514 bool 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 
    2535 int 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  */
    2551 void *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  */
    2567 void 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  */
    2581 void 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  */
    2598 void 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 
    26101842/** @}
    26111843 */
Note: See TracChangeset for help on using the changeset viewer.