Ignore:
File:
1 edited

Legend:

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

    rdf956b9b rae6021d  
    7777 *   }
    7878 *
    79  *   my_client_connection(icallid, *icall)
     79 *   port_handler(icallid, *icall)
    8080 *   {
    8181 *     if (want_refuse) {
     
    101101#undef LIBC_ASYNC_C_
    102102
     103#include <ipc/irq.h>
     104#include <ipc/event.h>
    103105#include <futex.h>
    104106#include <fibril.h>
     
    114116#include <stdlib.h>
    115117#include <macros.h>
     118#include <as.h>
     119#include <abi/mm/as.h>
    116120#include "private/libc.h"
    117 
    118121
    119122/** Session data */
     
    122125        list_t exch_list;
    123126       
     127        /** Session interface */
     128        iface_t iface;
     129       
    124130        /** Exchange management style */
    125131        exch_mgmt_t mgmt;
     
    166172
    167173/** Async framework global futex */
    168 atomic_t async_futex = FUTEX_INITIALIZER;
     174futex_t async_futex = FUTEX_INITIALIZER;
    169175
    170176/** Number of threads waiting for IPC in the kernel. */
     
    188194        /** If reply was received. */
    189195        bool done;
    190 
     196       
    191197        /** If the message / reply should be discarded on arrival. */
    192198        bool forget;
    193 
     199       
    194200        /** If already destroyed. */
    195201        bool destroyed;
     
    231237        /** Identification of the opening call. */
    232238        ipc_callid_t callid;
     239       
    233240        /** Call data of the opening call. */
    234241        ipc_call_t call;
    235         /** Local argument or NULL if none. */
    236         void *carg;
    237242       
    238243        /** Identification of the closing call. */
     
    240245       
    241246        /** Fibril function that will be used to handle the connection. */
    242         async_client_conn_t cfibril;
     247        async_port_handler_t handler;
     248       
     249        /** Client data */
     250        void *data;
    243251} connection_t;
     252
     253/** Interface data */
     254typedef struct {
     255        ht_link_t link;
     256       
     257        /** Interface ID */
     258        iface_t iface;
     259       
     260        /** Futex protecting the hash table */
     261        futex_t futex;
     262       
     263        /** Interface ports */
     264        hash_table_t port_hash_table;
     265       
     266        /** Next available port ID */
     267        port_id_t port_id_avail;
     268} interface_t;
     269
     270/* Port data */
     271typedef struct {
     272        ht_link_t link;
     273       
     274        /** Port ID */
     275        port_id_t id;
     276       
     277        /** Port connection handler */
     278        async_port_handler_t handler;
     279       
     280        /** Client data */
     281        void *data;
     282} port_t;
     283
     284/* Notification data */
     285typedef struct {
     286        ht_link_t link;
     287       
     288        /** Notification method */
     289        sysarg_t imethod;
     290       
     291        /** Notification handler */
     292        async_notification_handler_t handler;
     293       
     294        /** Notification data */
     295        void *data;
     296} notification_t;
    244297
    245298/** Identifier of the incoming connection handled by the current fibril. */
     
    249302{
    250303        struct timeval tv = { 0, 0 };
    251 
     304       
    252305        to->inlist = false;
    253306        to->occurred = false;
     
    272325static amsg_t *amsg_create(void)
    273326{
    274         amsg_t *msg;
    275 
    276         msg = malloc(sizeof(amsg_t));
     327        amsg_t *msg = malloc(sizeof(amsg_t));
    277328        if (msg) {
    278329                msg->done = false;
     
    283334                awaiter_initialize(&msg->wdata);
    284335        }
    285 
     336       
    286337        return msg;
    287338}
     
    320371}
    321372
    322 /** Default fibril function that gets called to handle new connection.
    323  *
    324  * This function is defined as a weak symbol - to be redefined in user code.
     373/** Default fallback fibril function.
     374 *
     375 * This fallback fibril function gets called on incomming
     376 * connections that do not have a specific handler defined.
    325377 *
    326378 * @param callid Hash of the incoming call.
     
    329381 *
    330382 */
    331 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call,
     383static void default_fallback_port_handler(ipc_callid_t callid, ipc_call_t *call,
    332384    void *arg)
    333385{
     
    335387}
    336388
    337 /** Default fibril function that gets called to handle interrupt notifications.
    338  *
    339  * This function is defined as a weak symbol - to be redefined in user code.
    340  *
    341  * @param callid Hash of the incoming call.
    342  * @param call   Data of the incoming call.
    343  * @param arg    Local argument.
    344  *
    345  */
    346 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    347 {
    348 }
    349 
    350 static async_client_conn_t client_connection = default_client_connection;
    351 static async_interrupt_handler_t interrupt_received = default_interrupt_received;
    352 static size_t interrupt_handler_stksz = FIBRIL_DFLT_STK_SIZE;
    353 
    354 /** Setter for client_connection function pointer.
    355  *
    356  * @param conn Function that will implement a new connection fibril.
    357  *
    358  */
    359 void async_set_client_connection(async_client_conn_t conn)
    360 {
    361         assert(client_connection == default_client_connection);
    362         client_connection = conn;
    363 }
    364 
    365 /** Setter for interrupt_received function pointer.
    366  *
    367  * @param intr Function that will implement a new interrupt
    368  *             notification fibril.
    369  */
    370 void async_set_interrupt_received(async_interrupt_handler_t intr)
    371 {
    372         interrupt_received = intr;
    373 }
    374 
    375 /** Set the stack size for the interrupt handler notification fibrils.
    376  *
    377  * @param size Stack size in bytes.
    378  */
    379 void async_set_interrupt_handler_stack_size(size_t size)
    380 {
    381         interrupt_handler_stksz = size;
     389static async_port_handler_t fallback_port_handler =
     390    default_fallback_port_handler;
     391static void *fallback_port_data = NULL;
     392
     393static hash_table_t interface_hash_table;
     394
     395static size_t interface_key_hash(void *key)
     396{
     397        iface_t iface = *(iface_t *) key;
     398        return iface;
     399}
     400
     401static size_t interface_hash(const ht_link_t *item)
     402{
     403        interface_t *interface = hash_table_get_inst(item, interface_t, link);
     404        return interface_key_hash(&interface->iface);
     405}
     406
     407static bool interface_key_equal(void *key, const ht_link_t *item)
     408{
     409        iface_t iface = *(iface_t *) key;
     410        interface_t *interface = hash_table_get_inst(item, interface_t, link);
     411        return iface == interface->iface;
     412}
     413
     414/** Operations for the port hash table. */
     415static hash_table_ops_t interface_hash_table_ops = {
     416        .hash = interface_hash,
     417        .key_hash = interface_key_hash,
     418        .key_equal = interface_key_equal,
     419        .equal = NULL,
     420        .remove_callback = NULL
     421};
     422
     423static size_t port_key_hash(void *key)
     424{
     425        port_id_t port_id = *(port_id_t *) key;
     426        return port_id;
     427}
     428
     429static size_t port_hash(const ht_link_t *item)
     430{
     431        port_t *port = hash_table_get_inst(item, port_t, link);
     432        return port_key_hash(&port->id);
     433}
     434
     435static bool port_key_equal(void *key, const ht_link_t *item)
     436{
     437        port_id_t port_id = *(port_id_t *) key;
     438        port_t *port = hash_table_get_inst(item, port_t, link);
     439        return port_id == port->id;
     440}
     441
     442/** Operations for the port hash table. */
     443static hash_table_ops_t port_hash_table_ops = {
     444        .hash = port_hash,
     445        .key_hash = port_key_hash,
     446        .key_equal = port_key_equal,
     447        .equal = NULL,
     448        .remove_callback = NULL
     449};
     450
     451static interface_t *async_new_interface(iface_t iface)
     452{
     453        interface_t *interface =
     454            (interface_t *) malloc(sizeof(interface_t));
     455        if (!interface)
     456                return NULL;
     457       
     458        bool ret = hash_table_create(&interface->port_hash_table, 0, 0,
     459            &port_hash_table_ops);
     460        if (!ret) {
     461                free(interface);
     462                return NULL;
     463        }
     464       
     465        interface->iface = iface;
     466        futex_initialize(&interface->futex, 1);
     467        interface->port_id_avail = 0;
     468       
     469        hash_table_insert(&interface_hash_table, &interface->link);
     470       
     471        return interface;
     472}
     473
     474static port_t *async_new_port(interface_t *interface,
     475    async_port_handler_t handler, void *data)
     476{
     477        port_t *port = (port_t *) malloc(sizeof(port_t));
     478        if (!port)
     479                return NULL;
     480       
     481        futex_down(&interface->futex);
     482       
     483        port_id_t id = interface->port_id_avail;
     484        interface->port_id_avail++;
     485       
     486        port->id = id;
     487        port->handler = handler;
     488        port->data = data;
     489       
     490        hash_table_insert(&interface->port_hash_table, &port->link);
     491       
     492        futex_up(&interface->futex);
     493       
     494        return port;
    382495}
    383496
     
    396509 */
    397510static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
     511
     512int async_create_port(iface_t iface, async_port_handler_t handler,
     513    void *data, port_id_t *port_id)
     514{
     515        if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
     516                return EINVAL;
     517       
     518        interface_t *interface;
     519       
     520        futex_down(&async_futex);
     521       
     522        ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
     523        if (link)
     524                interface = hash_table_get_inst(link, interface_t, link);
     525        else
     526                interface = async_new_interface(iface);
     527       
     528        if (!interface) {
     529                futex_up(&async_futex);
     530                return ENOMEM;
     531        }
     532       
     533        port_t *port = async_new_port(interface, handler, data);
     534        if (!port) {
     535                futex_up(&async_futex);
     536                return ENOMEM;
     537        }
     538       
     539        *port_id = port->id;
     540       
     541        futex_up(&async_futex);
     542       
     543        return EOK;
     544}
     545
     546void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
     547{
     548        assert(handler != NULL);
     549       
     550        fallback_port_handler = handler;
     551        fallback_port_data = data;
     552}
    398553
    399554static hash_table_t client_hash_table;
    400555static hash_table_t conn_hash_table;
     556static hash_table_t notification_hash_table;
    401557static LIST_INITIALIZE(timeout_list);
    402558
    403 static size_t client_key_hash(void *k)
    404 {
    405         task_id_t key = *(task_id_t*)k;
    406         return key;
     559static sysarg_t notification_avail = 0;
     560
     561static size_t client_key_hash(void *key)
     562{
     563        task_id_t in_task_id = *(task_id_t *) key;
     564        return in_task_id;
    407565}
    408566
     
    413571}
    414572
    415 static bool client_key_equal(void *k, const ht_link_t *item)
    416 {
    417         task_id_t key = *(task_id_t*)k;
     573static bool client_key_equal(void *key, const ht_link_t *item)
     574{
     575        task_id_t in_task_id = *(task_id_t *) key;
    418576        client_t *client = hash_table_get_inst(item, client_t, link);
    419         return key == client->in_task_id;
    420 }
    421 
     577        return in_task_id == client->in_task_id;
     578}
    422579
    423580/** Operations for the client hash table. */
     
    439596static size_t conn_key_hash(void *key)
    440597{
    441         sysarg_t in_phone_hash  = *(sysarg_t*)key;
    442         return in_phone_hash ;
     598        sysarg_t in_phone_hash = *(sysarg_t *) key;
     599        return in_phone_hash;
    443600}
    444601
     
    451608static bool conn_key_equal(void *key, const ht_link_t *item)
    452609{
    453         sysarg_t in_phone_hash = *(sysarg_t*)key;
     610        sysarg_t in_phone_hash = *(sysarg_t *) key;
    454611        connection_t *conn = hash_table_get_inst(item, connection_t, link);
    455612        return (in_phone_hash == conn->in_phone_hash);
    456613}
    457 
    458614
    459615/** Operations for the connection hash table. */
     
    466622};
    467623
     624static client_t *async_client_get(task_id_t client_id, bool create)
     625{
     626        client_t *client = NULL;
     627       
     628        futex_down(&async_futex);
     629        ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
     630        if (link) {
     631                client = hash_table_get_inst(link, client_t, link);
     632                atomic_inc(&client->refcnt);
     633        } else if (create) {
     634                client = malloc(sizeof(client_t));
     635                if (client) {
     636                        client->in_task_id = client_id;
     637                        client->data = async_client_data_create();
     638                       
     639                        atomic_set(&client->refcnt, 1);
     640                        hash_table_insert(&client_hash_table, &client->link);
     641                }
     642        }
     643       
     644        futex_up(&async_futex);
     645        return client;
     646}
     647
     648static void async_client_put(client_t *client)
     649{
     650        bool destroy;
     651       
     652        futex_down(&async_futex);
     653       
     654        if (atomic_predec(&client->refcnt) == 0) {
     655                hash_table_remove(&client_hash_table, &client->in_task_id);
     656                destroy = true;
     657        } else
     658                destroy = false;
     659       
     660        futex_up(&async_futex);
     661       
     662        if (destroy) {
     663                if (client->data)
     664                        async_client_data_destroy(client->data);
     665               
     666                free(client);
     667        }
     668}
     669
     670/** Wrapper for client connection fibril.
     671 *
     672 * When a new connection arrives, a fibril with this implementing
     673 * function is created.
     674 *
     675 * @param arg Connection structure pointer.
     676 *
     677 * @return Always zero.
     678 *
     679 */
     680static int connection_fibril(void *arg)
     681{
     682        assert(arg);
     683       
     684        /*
     685         * Setup fibril-local connection pointer.
     686         */
     687        fibril_connection = (connection_t *) arg;
     688       
     689        /*
     690         * Add our reference for the current connection in the client task
     691         * tracking structure. If this is the first reference, create and
     692         * hash in a new tracking structure.
     693         */
     694       
     695        client_t *client = async_client_get(fibril_connection->in_task_id, true);
     696        if (!client) {
     697                ipc_answer_0(fibril_connection->callid, ENOMEM);
     698                return 0;
     699        }
     700       
     701        fibril_connection->client = client;
     702       
     703        /*
     704         * Call the connection handler function.
     705         */
     706        fibril_connection->handler(fibril_connection->callid,
     707            &fibril_connection->call, fibril_connection->data);
     708       
     709        /*
     710         * Remove the reference for this client task connection.
     711         */
     712        async_client_put(client);
     713       
     714        /*
     715         * Remove myself from the connection hash table.
     716         */
     717        futex_down(&async_futex);
     718        hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
     719        futex_up(&async_futex);
     720       
     721        /*
     722         * Answer all remaining messages with EHANGUP.
     723         */
     724        while (!list_empty(&fibril_connection->msg_queue)) {
     725                msg_t *msg =
     726                    list_get_instance(list_first(&fibril_connection->msg_queue),
     727                    msg_t, link);
     728               
     729                list_remove(&msg->link);
     730                ipc_answer_0(msg->callid, EHANGUP);
     731                free(msg);
     732        }
     733       
     734        /*
     735         * If the connection was hung-up, answer the last call,
     736         * i.e. IPC_M_PHONE_HUNGUP.
     737         */
     738        if (fibril_connection->close_callid)
     739                ipc_answer_0(fibril_connection->close_callid, EOK);
     740       
     741        free(fibril_connection);
     742        return 0;
     743}
     744
     745/** Create a new fibril for a new connection.
     746 *
     747 * Create new fibril for connection, fill in connection structures
     748 * and insert it into the hash table, so that later we can easily
     749 * do routing of messages to particular fibrils.
     750 *
     751 * @param in_task_id    Identification of the incoming connection.
     752 * @param in_phone_hash Identification of the incoming connection.
     753 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
     754 *                      If callid is zero, the connection was opened by
     755 *                      accepting the IPC_M_CONNECT_TO_ME call and this
     756 *                      function is called directly by the server.
     757 * @param call          Call data of the opening call.
     758 * @param handler       Connection handler.
     759 * @param data          Client argument to pass to the connection handler.
     760 *
     761 * @return New fibril id or NULL on failure.
     762 *
     763 */
     764static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
     765    ipc_callid_t callid, ipc_call_t *call, async_port_handler_t handler,
     766    void *data)
     767{
     768        connection_t *conn = malloc(sizeof(*conn));
     769        if (!conn) {
     770                if (callid)
     771                        ipc_answer_0(callid, ENOMEM);
     772               
     773                return (uintptr_t) NULL;
     774        }
     775       
     776        conn->in_task_id = in_task_id;
     777        conn->in_phone_hash = in_phone_hash;
     778        list_initialize(&conn->msg_queue);
     779        conn->callid = callid;
     780        conn->close_callid = 0;
     781        conn->handler = handler;
     782        conn->data = data;
     783       
     784        if (call)
     785                conn->call = *call;
     786       
     787        /* We will activate the fibril ASAP */
     788        conn->wdata.active = true;
     789        conn->wdata.fid = fibril_create(connection_fibril, conn);
     790       
     791        if (conn->wdata.fid == 0) {
     792                free(conn);
     793               
     794                if (callid)
     795                        ipc_answer_0(callid, ENOMEM);
     796               
     797                return (uintptr_t) NULL;
     798        }
     799       
     800        /* Add connection to the connection hash table */
     801       
     802        futex_down(&async_futex);
     803        hash_table_insert(&conn_hash_table, &conn->link);
     804        futex_up(&async_futex);
     805       
     806        fibril_add_ready(conn->wdata.fid);
     807       
     808        return conn->wdata.fid;
     809}
     810
     811/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
     812 *
     813 * Ask through phone for a new connection to some service.
     814 *
     815 * @param exch    Exchange for sending the message.
     816 * @param iface   Callback interface.
     817 * @param arg1    User defined argument.
     818 * @param arg2    User defined argument.
     819 * @param handler Callback handler.
     820 * @param data    Handler data.
     821 * @param port_id ID of the newly created port.
     822 *
     823 * @return Zero on success or a negative error code.
     824 *
     825 */
     826int async_create_callback_port(async_exch_t *exch, iface_t iface, sysarg_t arg1,
     827    sysarg_t arg2, async_port_handler_t handler, void *data, port_id_t *port_id)
     828{
     829        if ((iface & IFACE_MOD_CALLBACK) != IFACE_MOD_CALLBACK)
     830                return EINVAL;
     831       
     832        if (exch == NULL)
     833                return ENOENT;
     834       
     835        ipc_call_t answer;
     836        aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, iface, arg1, arg2,
     837            &answer);
     838       
     839        sysarg_t ret;
     840        async_wait_for(req, &ret);
     841        if (ret != EOK)
     842                return (int) ret;
     843       
     844        sysarg_t phone_hash = IPC_GET_ARG5(answer);
     845        interface_t *interface;
     846       
     847        futex_down(&async_futex);
     848       
     849        ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
     850        if (link)
     851                interface = hash_table_get_inst(link, interface_t, link);
     852        else
     853                interface = async_new_interface(iface);
     854       
     855        if (!interface) {
     856                futex_up(&async_futex);
     857                return ENOMEM;
     858        }
     859       
     860        port_t *port = async_new_port(interface, handler, data);
     861        if (!port) {
     862                futex_up(&async_futex);
     863                return ENOMEM;
     864        }
     865       
     866        *port_id = port->id;
     867       
     868        futex_up(&async_futex);
     869       
     870        fid_t fid = async_new_connection(answer.in_task_id, phone_hash,
     871            0, NULL, handler, data);
     872        if (fid == (uintptr_t) NULL)
     873                return ENOMEM;
     874       
     875        return EOK;
     876}
     877
     878static size_t notification_key_hash(void *key)
     879{
     880        sysarg_t id = *(sysarg_t *) key;
     881        return id;
     882}
     883
     884static size_t notification_hash(const ht_link_t *item)
     885{
     886        notification_t *notification =
     887            hash_table_get_inst(item, notification_t, link);
     888        return notification_key_hash(&notification->imethod);
     889}
     890
     891static bool notification_key_equal(void *key, const ht_link_t *item)
     892{
     893        sysarg_t id = *(sysarg_t *) key;
     894        notification_t *notification =
     895            hash_table_get_inst(item, notification_t, link);
     896        return id == notification->imethod;
     897}
     898
     899/** Operations for the notification hash table. */
     900static hash_table_ops_t notification_hash_table_ops = {
     901        .hash = notification_hash,
     902        .key_hash = notification_key_hash,
     903        .key_equal = notification_key_equal,
     904        .equal = NULL,
     905        .remove_callback = NULL
     906};
     907
    468908/** Sort in current fibril's timeout request.
    469909 *
     
    511951        futex_down(&async_futex);
    512952       
    513         ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash);
    514        
    515         if (!hlp) {
     953        ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash);
     954        if (!link) {
    516955                futex_up(&async_futex);
    517956                return false;
    518957        }
    519958       
    520         connection_t *conn = hash_table_get_inst(hlp, connection_t, link);
     959        connection_t *conn = hash_table_get_inst(link, connection_t, link);
    521960       
    522961        msg_t *msg = malloc(sizeof(*msg));
     
    550989}
    551990
    552 /** Notification fibril.
    553  *
    554  * When a notification arrives, a fibril with this implementing function is
    555  * created. It calls interrupt_received() and does the final cleanup.
    556  *
    557  * @param arg Message structure pointer.
    558  *
    559  * @return Always zero.
    560  *
    561  */
    562 static int notification_fibril(void *arg)
    563 {
    564         assert(arg);
    565        
    566         msg_t *msg = (msg_t *) arg;
    567         interrupt_received(msg->callid, &msg->call);
    568        
    569         free(msg);
    570         return 0;
    571 }
    572 
    573 /** Process interrupt notification.
    574  *
    575  * A new fibril is created which would process the notification.
     991/** Process notification.
    576992 *
    577993 * @param callid Hash of the incoming call.
    578994 * @param call   Data of the incoming call.
    579995 *
    580  * @return False if an error occured.
    581  *         True if the call was passed to the notification fibril.
    582  *
    583  */
    584 static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
    585 {
     996 */
     997static void process_notification(ipc_callid_t callid, ipc_call_t *call)
     998{
     999        async_notification_handler_t handler = NULL;
     1000        void *data = NULL;
     1001
    5861002        assert(call);
    5871003       
    5881004        futex_down(&async_futex);
    5891005       
    590         msg_t *msg = malloc(sizeof(*msg));
    591         if (!msg) {
    592                 futex_up(&async_futex);
    593                 return false;
    594         }
    595        
    596         msg->callid = callid;
    597         msg->call = *call;
    598        
    599         fid_t fid = fibril_create_generic(notification_fibril, msg,
    600             interrupt_handler_stksz);
    601         if (fid == 0) {
    602                 free(msg);
    603                 futex_up(&async_futex);
    604                 return false;
    605         }
    606        
    607         fibril_add_ready(fid);
     1006        ht_link_t *link = hash_table_find(&notification_hash_table,
     1007            &IPC_GET_IMETHOD(*call));
     1008        if (link) {
     1009                notification_t *notification =
     1010                    hash_table_get_inst(link, notification_t, link);
     1011                handler = notification->handler;
     1012                data = notification->data;
     1013        }
    6081014       
    6091015        futex_up(&async_futex);
    610         return true;
     1016       
     1017        if (handler)
     1018                handler(callid, call, data);
     1019}
     1020
     1021/** Subscribe to IRQ notification.
     1022 *
     1023 * @param inr     IRQ number.
     1024 * @param devno   Device number of the device generating inr.
     1025 * @param handler Notification handler.
     1026 * @param data    Notification handler client data.
     1027 * @param ucode   Top-half pseudocode handler.
     1028 *
     1029 * @return Zero on success or a negative error code.
     1030 *
     1031 */
     1032int async_irq_subscribe(int inr, int devno,
     1033    async_notification_handler_t handler, void *data, const irq_code_t *ucode)
     1034{
     1035        notification_t *notification =
     1036            (notification_t *) malloc(sizeof(notification_t));
     1037        if (!notification)
     1038                return ENOMEM;
     1039       
     1040        futex_down(&async_futex);
     1041       
     1042        sysarg_t imethod = notification_avail;
     1043        notification_avail++;
     1044       
     1045        notification->imethod = imethod;
     1046        notification->handler = handler;
     1047        notification->data = data;
     1048       
     1049        hash_table_insert(&notification_hash_table, &notification->link);
     1050       
     1051        futex_up(&async_futex);
     1052       
     1053        return ipc_irq_subscribe(inr, devno, imethod, ucode);
     1054}
     1055
     1056/** Unsubscribe from IRQ notification.
     1057 *
     1058 * @param inr     IRQ number.
     1059 * @param devno   Device number of the device generating inr.
     1060 *
     1061 * @return Zero on success or a negative error code.
     1062 *
     1063 */
     1064int async_irq_unsubscribe(int inr, int devno)
     1065{
     1066        // TODO: Remove entry from hash table
     1067        //       to avoid memory leak
     1068       
     1069        return ipc_irq_unsubscribe(inr, devno);
     1070}
     1071
     1072/** Subscribe to event notifications.
     1073 *
     1074 * @param evno    Event type to subscribe.
     1075 * @param handler Notification handler.
     1076 * @param data    Notification handler client data.
     1077 *
     1078 * @return Zero on success or a negative error code.
     1079 *
     1080 */
     1081int async_event_subscribe(event_type_t evno,
     1082    async_notification_handler_t handler, void *data)
     1083{
     1084        notification_t *notification =
     1085            (notification_t *) malloc(sizeof(notification_t));
     1086        if (!notification)
     1087                return ENOMEM;
     1088       
     1089        futex_down(&async_futex);
     1090       
     1091        sysarg_t imethod = notification_avail;
     1092        notification_avail++;
     1093       
     1094        notification->imethod = imethod;
     1095        notification->handler = handler;
     1096        notification->data = data;
     1097       
     1098        hash_table_insert(&notification_hash_table, &notification->link);
     1099       
     1100        futex_up(&async_futex);
     1101       
     1102        return ipc_event_subscribe(evno, imethod);
     1103}
     1104
     1105/** Subscribe to task event notifications.
     1106 *
     1107 * @param evno    Event type to subscribe.
     1108 * @param handler Notification handler.
     1109 * @param data    Notification handler client data.
     1110 *
     1111 * @return Zero on success or a negative error code.
     1112 *
     1113 */
     1114int async_event_task_subscribe(event_task_type_t evno,
     1115    async_notification_handler_t handler, void *data)
     1116{
     1117        notification_t *notification =
     1118            (notification_t *) malloc(sizeof(notification_t));
     1119        if (!notification)
     1120                return ENOMEM;
     1121       
     1122        futex_down(&async_futex);
     1123       
     1124        sysarg_t imethod = notification_avail;
     1125        notification_avail++;
     1126       
     1127        notification->imethod = imethod;
     1128        notification->handler = handler;
     1129        notification->data = data;
     1130       
     1131        hash_table_insert(&notification_hash_table, &notification->link);
     1132       
     1133        futex_up(&async_futex);
     1134       
     1135        return ipc_event_task_subscribe(evno, imethod);
     1136}
     1137
     1138/** Unmask event notifications.
     1139 *
     1140 * @param evno Event type to unmask.
     1141 *
     1142 * @return Value returned by the kernel.
     1143 *
     1144 */
     1145int async_event_unmask(event_type_t evno)
     1146{
     1147        return ipc_event_unmask(evno);
     1148}
     1149
     1150/** Unmask task event notifications.
     1151 *
     1152 * @param evno Event type to unmask.
     1153 *
     1154 * @return Value returned by the kernel.
     1155 *
     1156 */
     1157int async_event_task_unmask(event_task_type_t evno)
     1158{
     1159        return ipc_event_task_unmask(evno);
    6111160}
    6121161
     
    6401189        if (usecs) {
    6411190                getuptime(&conn->wdata.to_event.expires);
    642                 tv_add(&conn->wdata.to_event.expires, usecs);
     1191                tv_add_diff(&conn->wdata.to_event.expires, usecs);
    6431192        } else
    6441193                conn->wdata.to_event.inlist = false;
     
    6861235        }
    6871236       
    688         msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link);
     1237        msg_t *msg = list_get_instance(list_first(&conn->msg_queue),
     1238            msg_t, link);
    6891239        list_remove(&msg->link);
    6901240       
     
    6971247}
    6981248
    699 static client_t *async_client_get(task_id_t client_id, bool create)
    700 {
    701         client_t *client = NULL;
    702 
    703         futex_down(&async_futex);
    704         ht_link_t *lnk = hash_table_find(&client_hash_table, &client_id);
    705         if (lnk) {
    706                 client = hash_table_get_inst(lnk, client_t, link);
    707                 atomic_inc(&client->refcnt);
    708         } else if (create) {
    709                 client = malloc(sizeof(client_t));
    710                 if (client) {
    711                         client->in_task_id = client_id;
    712                         client->data = async_client_data_create();
    713                
    714                         atomic_set(&client->refcnt, 1);
    715                         hash_table_insert(&client_hash_table, &client->link);
    716                 }
    717         }
    718 
    719         futex_up(&async_futex);
    720         return client;
    721 }
    722 
    723 static void async_client_put(client_t *client)
    724 {
    725         bool destroy;
    726 
    727         futex_down(&async_futex);
    728        
    729         if (atomic_predec(&client->refcnt) == 0) {
    730                 hash_table_remove(&client_hash_table, &client->in_task_id);
    731                 destroy = true;
    732         } else
    733                 destroy = false;
    734        
    735         futex_up(&async_futex);
    736        
    737         if (destroy) {
    738                 if (client->data)
    739                         async_client_data_destroy(client->data);
    740                
    741                 free(client);
    742         }
    743 }
    744 
    7451249void *async_get_client_data(void)
    7461250{
     
    7541258        if (!client)
    7551259                return NULL;
     1260       
    7561261        if (!client->data) {
    7571262                async_client_put(client);
    7581263                return NULL;
    7591264        }
    760 
     1265       
    7611266        return client->data;
    7621267}
     
    7651270{
    7661271        client_t *client = async_client_get(client_id, false);
    767 
     1272       
    7681273        assert(client);
    7691274        assert(client->data);
    770 
     1275       
    7711276        /* Drop the reference we got in async_get_client_data_by_hash(). */
    7721277        async_client_put(client);
    773 
     1278       
    7741279        /* Drop our own reference we got at the beginning of this function. */
    7751280        async_client_put(client);
    7761281}
    7771282
    778 /** Wrapper for client connection fibril.
    779  *
    780  * When a new connection arrives, a fibril with this implementing function is
    781  * created. It calls client_connection() and does the final cleanup.
    782  *
    783  * @param arg Connection structure pointer.
    784  *
    785  * @return Always zero.
    786  *
    787  */
    788 static int connection_fibril(void *arg)
    789 {
    790         assert(arg);
    791        
    792         /*
    793          * Setup fibril-local connection pointer.
    794          */
    795         fibril_connection = (connection_t *) arg;
    796        
    797         /*
    798          * Add our reference for the current connection in the client task
    799          * tracking structure. If this is the first reference, create and
    800          * hash in a new tracking structure.
    801          */
    802 
    803         client_t *client = async_client_get(fibril_connection->in_task_id, true);
    804         if (!client) {
    805                 ipc_answer_0(fibril_connection->callid, ENOMEM);
    806                 return 0;
    807         }
    808 
    809         fibril_connection->client = client;
    810        
    811         /*
    812          * Call the connection handler function.
    813          */
    814         fibril_connection->cfibril(fibril_connection->callid,
    815             &fibril_connection->call, fibril_connection->carg);
    816        
    817         /*
    818          * Remove the reference for this client task connection.
    819          */
    820         async_client_put(client);
    821        
    822         /*
    823          * Remove myself from the connection hash table.
    824          */
     1283static port_t *async_find_port(iface_t iface, port_id_t port_id)
     1284{
     1285        port_t *port = NULL;
     1286       
    8251287        futex_down(&async_futex);
    826         hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
     1288       
     1289        ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
     1290        if (link) {
     1291                interface_t *interface =
     1292                    hash_table_get_inst(link, interface_t, link);
     1293               
     1294                link = hash_table_find(&interface->port_hash_table, &port_id);
     1295                if (link)
     1296                        port = hash_table_get_inst(link, port_t, link);
     1297        }
     1298       
    8271299        futex_up(&async_futex);
    8281300       
    829         /*
    830          * Answer all remaining messages with EHANGUP.
    831          */
    832         while (!list_empty(&fibril_connection->msg_queue)) {
    833                 msg_t *msg =
    834                     list_get_instance(list_first(&fibril_connection->msg_queue),
    835                     msg_t, link);
    836                
    837                 list_remove(&msg->link);
    838                 ipc_answer_0(msg->callid, EHANGUP);
    839                 free(msg);
    840         }
    841        
    842         /*
    843          * If the connection was hung-up, answer the last call,
    844          * i.e. IPC_M_PHONE_HUNGUP.
    845          */
    846         if (fibril_connection->close_callid)
    847                 ipc_answer_0(fibril_connection->close_callid, EOK);
    848        
    849         free(fibril_connection);
    850         return 0;
    851 }
    852 
    853 /** Create a new fibril for a new connection.
    854  *
    855  * Create new fibril for connection, fill in connection structures and insert
    856  * it into the hash table, so that later we can easily do routing of messages to
    857  * particular fibrils.
    858  *
    859  * @param in_task_id    Identification of the incoming connection.
    860  * @param in_phone_hash Identification of the incoming connection.
    861  * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
    862  *                      If callid is zero, the connection was opened by
    863  *                      accepting the IPC_M_CONNECT_TO_ME call and this function
    864  *                      is called directly by the server.
    865  * @param call          Call data of the opening call.
    866  * @param cfibril       Fibril function that should be called upon opening the
    867  *                      connection.
    868  * @param carg          Extra argument to pass to the connection fibril
    869  *
    870  * @return New fibril id or NULL on failure.
    871  *
    872  */
    873 fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
    874     ipc_callid_t callid, ipc_call_t *call,
    875     async_client_conn_t cfibril, void *carg)
    876 {
    877         connection_t *conn = malloc(sizeof(*conn));
    878         if (!conn) {
    879                 if (callid)
    880                         ipc_answer_0(callid, ENOMEM);
    881                
    882                 return (uintptr_t) NULL;
    883         }
    884        
    885         conn->in_task_id = in_task_id;
    886         conn->in_phone_hash = in_phone_hash;
    887         list_initialize(&conn->msg_queue);
    888         conn->callid = callid;
    889         conn->close_callid = 0;
    890         conn->carg = carg;
    891        
    892         if (call)
    893                 conn->call = *call;
    894        
    895         /* We will activate the fibril ASAP */
    896         conn->wdata.active = true;
    897         conn->cfibril = cfibril;
    898         conn->wdata.fid = fibril_create(connection_fibril, conn);
    899        
    900         if (conn->wdata.fid == 0) {
    901                 free(conn);
    902                
    903                 if (callid)
    904                         ipc_answer_0(callid, ENOMEM);
    905                
    906                 return (uintptr_t) NULL;
    907         }
    908        
    909         /* Add connection to the connection hash table */
    910        
    911         futex_down(&async_futex);
    912         hash_table_insert(&conn_hash_table, &conn->link);
    913         futex_up(&async_futex);
    914        
    915         fibril_add_ready(conn->wdata.fid);
    916        
    917         return conn->wdata.fid;
     1301        return port;
    9181302}
    9191303
     
    9311315        assert(call);
    9321316       
    933         /* Unrouted call - take some default action */
     1317        /* Kernel notification */
    9341318        if ((callid & IPC_CALLID_NOTIFICATION)) {
     1319                fibril_t *fibril = (fibril_t *) __tcb_get()->fibril_data;
     1320                unsigned oldsw = fibril->switches;
     1321               
    9351322                process_notification(callid, call);
     1323               
     1324                if (oldsw != fibril->switches) {
     1325                        /*
     1326                         * The notification handler did not execute atomically
     1327                         * and so the current manager fibril assumed the role of
     1328                         * a notification fibril. While waiting for its
     1329                         * resources, it switched to another manager fibril that
     1330                         * had already existed or it created a new one. We
     1331                         * therefore know there is at least yet another
     1332                         * manager fibril that can take over. We now kill the
     1333                         * current 'notification' fibril to prevent fibril
     1334                         * population explosion.
     1335                         */
     1336                        futex_down(&async_futex);
     1337                        fibril_switch(FIBRIL_FROM_DEAD);
     1338                }
     1339               
    9361340                return;
    9371341        }
    9381342       
    939         switch (IPC_GET_IMETHOD(*call)) {
    940         case IPC_M_CLONE_ESTABLISH:
    941         case IPC_M_CONNECT_ME_TO:
     1343        /* New connection */
     1344        if (IPC_GET_IMETHOD(*call) == IPC_M_CONNECT_ME_TO) {
     1345                iface_t iface = (iface_t) IPC_GET_ARG1(*call);
     1346                sysarg_t in_phone_hash = IPC_GET_ARG5(*call);
     1347               
     1348                async_notification_handler_t handler = fallback_port_handler;
     1349                void *data = fallback_port_data;
     1350               
     1351                // TODO: Currently ignores all ports but the first one
     1352                port_t *port = async_find_port(iface, 0);
     1353                if (port) {
     1354                        handler = port->handler;
     1355                        data = port->data;
     1356                }
     1357               
     1358                async_new_connection(call->in_task_id, in_phone_hash, callid,
     1359                    call, handler, data);
     1360                return;
     1361        }
     1362       
     1363        /* Cloned connection */
     1364        if (IPC_GET_IMETHOD(*call) == IPC_M_CLONE_ESTABLISH) {
     1365                // TODO: Currently ignores ports altogether
     1366               
    9421367                /* Open new connection with fibril, etc. */
    9431368                async_new_connection(call->in_task_id, IPC_GET_ARG5(*call),
    944                     callid, call, client_connection, NULL);
     1369                    callid, call, fallback_port_handler, fallback_port_data);
    9451370                return;
    9461371        }
     
    10341459
    10351460                        } else {
    1036                                 timeout = tv_sub(&waiter->to_event.expires, &tv);
     1461                                timeout = tv_sub_diff(&waiter->to_event.expires,
     1462                                    &tv);
    10371463                                futex_up(&async_futex);
    10381464                        }
     
    10861512void async_create_manager(void)
    10871513{
    1088         fid_t fid = fibril_create(async_manager_fibril, NULL);
     1514        fid_t fid = fibril_create_generic(async_manager_fibril, NULL, PAGE_SIZE);
    10891515        if (fid != 0)
    10901516                fibril_add_manager(fid);
     
    11021528void __async_init(void)
    11031529{
     1530        if (!hash_table_create(&interface_hash_table, 0, 0,
     1531            &interface_hash_table_ops))
     1532                abort();
     1533       
    11041534        if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops))
    11051535                abort();
    11061536       
    11071537        if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops))
     1538                abort();
     1539       
     1540        if (!hash_table_create(&notification_hash_table, 0, 0,
     1541            &notification_hash_table_ops))
    11081542                abort();
    11091543       
     
    11121546                abort();
    11131547       
     1548        session_ns->iface = 0;
    11141549        session_ns->mgmt = EXCHANGE_ATOMIC;
    11151550        session_ns->phone = PHONE_NS;
     
    11581593       
    11591594        msg->done = true;
    1160 
     1595       
    11611596        if (msg->forget) {
    11621597                assert(msg->wdata.active);
     
    11661601                fibril_add_ready(msg->wdata.fid);
    11671602        }
    1168 
     1603       
    11691604        futex_up(&async_futex);
    11701605}
     
    12011636       
    12021637        ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
    1203             reply_received, true);
     1638            reply_received);
    12041639       
    12051640        return (aid_t) msg;
     
    12391674       
    12401675        ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
    1241             msg, reply_received, true);
     1676            msg, reply_received);
    12421677       
    12431678        return (aid_t) msg;
     
    12581693       
    12591694        futex_down(&async_futex);
    1260 
     1695       
    12611696        assert(!msg->forget);
    12621697        assert(!msg->destroyed);
    1263 
     1698       
    12641699        if (msg->done) {
    12651700                futex_up(&async_futex);
     
    13021737       
    13031738        amsg_t *msg = (amsg_t *) amsgid;
    1304 
     1739       
    13051740        futex_down(&async_futex);
    1306 
     1741       
    13071742        assert(!msg->forget);
    13081743        assert(!msg->destroyed);
    1309 
     1744       
    13101745        if (msg->done) {
    13111746                futex_up(&async_futex);
     
    13191754        if (timeout < 0)
    13201755                timeout = 0;
    1321 
     1756       
    13221757        getuptime(&msg->wdata.to_event.expires);
    1323         tv_add(&msg->wdata.to_event.expires, timeout);
     1758        tv_add_diff(&msg->wdata.to_event.expires, timeout);
    13241759       
    13251760        /*
     
    13721807{
    13731808        amsg_t *msg = (amsg_t *) amsgid;
    1374 
     1809       
    13751810        assert(msg);
    13761811        assert(!msg->forget);
    13771812        assert(!msg->destroyed);
    1378 
     1813       
    13791814        futex_down(&async_futex);
     1815       
    13801816        if (msg->done) {
    13811817                amsg_destroy(msg);
     
    13841820                msg->forget = true;
    13851821        }
     1822       
    13861823        futex_up(&async_futex);
    13871824}
     
    14031840       
    14041841        getuptime(&msg->wdata.to_event.expires);
    1405         tv_add(&msg->wdata.to_event.expires, timeout);
     1842        tv_add_diff(&msg->wdata.to_event.expires, timeout);
    14061843       
    14071844        futex_down(&async_futex);
     
    15261963{
    15271964        if (exch != NULL)
    1528                 ipc_call_async_0(exch->phone, imethod, NULL, NULL, true);
     1965                ipc_call_async_0(exch->phone, imethod, NULL, NULL);
    15291966}
    15301967
     
    15321969{
    15331970        if (exch != NULL)
    1534                 ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL, true);
     1971                ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL);
    15351972}
    15361973
     
    15391976{
    15401977        if (exch != NULL)
    1541                 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL,
    1542                     true);
     1978                ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL);
    15431979}
    15441980
     
    15481984        if (exch != NULL)
    15491985                ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
    1550                     NULL, true);
     1986                    NULL);
    15511987}
    15521988
     
    15561992        if (exch != NULL)
    15571993                ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
    1558                     NULL, NULL, true);
     1994                    NULL, NULL);
    15591995}
    15601996
     
    15642000        if (exch != NULL)
    15652001                ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
    1566                     arg5, NULL, NULL, true);
     2002                    arg5, NULL, NULL);
    15672003}
    15682004
     
    16292065 * @param arg2            User defined argument.
    16302066 * @param arg3            User defined argument.
    1631  * @param client_receiver Connection handing routine.
    16322067 *
    16332068 * @return Zero on success or a negative error code.
     
    16352070 */
    16362071int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
    1637     sysarg_t arg3, async_client_conn_t client_receiver, void *carg)
     2072    sysarg_t arg3)
    16382073{
    16392074        if (exch == NULL)
    16402075                return ENOENT;
    16412076       
    1642         sysarg_t phone_hash;
     2077        ipc_call_t answer;
     2078        aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     2079            &answer);
     2080       
    16432081        sysarg_t rc;
    1644 
    1645         aid_t req;
    1646         ipc_call_t answer;
    1647         req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
    1648             &answer);
    16492082        async_wait_for(req, &rc);
    16502083        if (rc != EOK)
    16512084                return (int) rc;
    1652 
    1653         phone_hash = IPC_GET_ARG5(answer);
    1654 
    1655         if (client_receiver != NULL)
    1656                 async_new_connection(answer.in_task_id, phone_hash, 0, NULL,
    1657                     client_receiver, carg);
    16582085       
    16592086        return EOK;
     
    16962123       
    16972124        ipc_call_async_0(exch->phone, IPC_M_CLONE_ESTABLISH, msg,
    1698             reply_received, true);
     2125            reply_received);
    16992126       
    17002127        sysarg_t rc;
     
    17152142        }
    17162143       
     2144        sess->iface = 0;
    17172145        sess->mgmt = mgmt;
    17182146        sess->phone = phone;
     
    17442172       
    17452173        ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
    1746             msg, reply_received, true);
     2174            msg, reply_received);
    17472175       
    17482176        sysarg_t rc;
     
    17842212        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
    17852213            0);
    1786        
    17872214        if (phone < 0) {
    17882215                errno = phone;
     
    17912218        }
    17922219       
     2220        sess->iface = 0;
    17932221        sess->mgmt = mgmt;
    17942222        sess->phone = phone;
     
    18072235}
    18082236
     2237/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
     2238 *
     2239 * Ask through phone for a new connection to some service and block until
     2240 * success.
     2241 *
     2242 * @param exch  Exchange for sending the message.
     2243 * @param iface Connection interface.
     2244 * @param arg2  User defined argument.
     2245 * @param arg3  User defined argument.
     2246 *
     2247 * @return New session on success or NULL on error.
     2248 *
     2249 */
     2250async_sess_t *async_connect_me_to_iface(async_exch_t *exch, iface_t iface,
     2251    sysarg_t arg2, sysarg_t arg3)
     2252{
     2253        if (exch == NULL) {
     2254                errno = ENOENT;
     2255                return NULL;
     2256        }
     2257       
     2258        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2259        if (sess == NULL) {
     2260                errno = ENOMEM;
     2261                return NULL;
     2262        }
     2263       
     2264        int phone = async_connect_me_to_internal(exch->phone, iface, arg2,
     2265            arg3, 0);
     2266        if (phone < 0) {
     2267                errno = phone;
     2268                free(sess);
     2269                return NULL;
     2270        }
     2271       
     2272        sess->iface = iface;
     2273        sess->phone = phone;
     2274        sess->arg1 = iface;
     2275        sess->arg2 = arg2;
     2276        sess->arg3 = arg3;
     2277       
     2278        fibril_mutex_initialize(&sess->remote_state_mtx);
     2279        sess->remote_state_data = NULL;
     2280       
     2281        list_initialize(&sess->exch_list);
     2282        fibril_mutex_initialize(&sess->mutex);
     2283        atomic_set(&sess->refcnt, 0);
     2284       
     2285        return sess;
     2286}
     2287
    18092288/** Set arguments for new connections.
    18102289 *
     
    18622341        }
    18632342       
     2343        sess->iface = 0;
    18642344        sess->mgmt = mgmt;
    18652345        sess->phone = phone;
     
    18782358}
    18792359
     2360/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
     2361 *
     2362 * Ask through phone for a new connection to some service and block until
     2363 * success.
     2364 *
     2365 * @param exch  Exchange for sending the message.
     2366 * @param iface Connection interface.
     2367 * @param arg2  User defined argument.
     2368 * @param arg3  User defined argument.
     2369 *
     2370 * @return New session on success or NULL on error.
     2371 *
     2372 */
     2373async_sess_t *async_connect_me_to_blocking_iface(async_exch_t *exch, iface_t iface,
     2374    sysarg_t arg2, sysarg_t arg3)
     2375{
     2376        if (exch == NULL) {
     2377                errno = ENOENT;
     2378                return NULL;
     2379        }
     2380       
     2381        async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
     2382        if (sess == NULL) {
     2383                errno = ENOMEM;
     2384                return NULL;
     2385        }
     2386       
     2387        int phone = async_connect_me_to_internal(exch->phone, iface, arg2,
     2388            arg3, IPC_FLAG_BLOCKING);
     2389        if (phone < 0) {
     2390                errno = phone;
     2391                free(sess);
     2392                return NULL;
     2393        }
     2394       
     2395        sess->iface = iface;
     2396        sess->phone = phone;
     2397        sess->arg1 = iface;
     2398        sess->arg2 = arg2;
     2399        sess->arg3 = arg3;
     2400       
     2401        fibril_mutex_initialize(&sess->remote_state_mtx);
     2402        sess->remote_state_data = NULL;
     2403       
     2404        list_initialize(&sess->exch_list);
     2405        fibril_mutex_initialize(&sess->mutex);
     2406        atomic_set(&sess->refcnt, 0);
     2407       
     2408        return sess;
     2409}
     2410
    18802411/** Connect to a task specified by id.
    18812412 *
     
    18962427        }
    18972428       
     2429        sess->iface = 0;
    18982430        sess->mgmt = EXCHANGE_ATOMIC;
    18992431        sess->phone = phone;
     
    19732505                return NULL;
    19742506       
    1975         async_exch_t *exch;
     2507        exch_mgmt_t mgmt = sess->mgmt;
     2508        if (sess->iface != 0)
     2509                mgmt = sess->iface & IFACE_EXCHANGE_MASK;
     2510       
     2511        async_exch_t *exch = NULL;
    19762512       
    19772513        fibril_mutex_lock(&async_sess_mutex);
     
    19922528                 */
    19932529               
    1994                 if ((sess->mgmt == EXCHANGE_ATOMIC) ||
    1995                     (sess->mgmt == EXCHANGE_SERIALIZE)) {
     2530                if ((mgmt == EXCHANGE_ATOMIC) ||
     2531                    (mgmt == EXCHANGE_SERIALIZE)) {
    19962532                        exch = (async_exch_t *) malloc(sizeof(async_exch_t));
    19972533                        if (exch != NULL) {
     
    20012537                                exch->phone = sess->phone;
    20022538                        }
    2003                 } else {  /* EXCHANGE_PARALLEL */
     2539                } else if (mgmt == EXCHANGE_PARALLEL) {
     2540                        int phone;
     2541                       
     2542                retry:
    20042543                        /*
    20052544                         * Make a one-time attempt to connect a new data phone.
    20062545                         */
    2007                        
    2008                         int phone;
    2009                        
    2010 retry:
    20112546                        phone = async_connect_me_to_internal(sess->phone, sess->arg1,
    20122547                            sess->arg2, sess->arg3, 0);
     
    20502585                atomic_inc(&sess->refcnt);
    20512586               
    2052                 if (sess->mgmt == EXCHANGE_SERIALIZE)
     2587                if (mgmt == EXCHANGE_SERIALIZE)
    20532588                        fibril_mutex_lock(&sess->mutex);
    20542589        }
     
    20702605        assert(sess != NULL);
    20712606       
     2607        exch_mgmt_t mgmt = sess->mgmt;
     2608        if (sess->iface != 0)
     2609                mgmt = sess->iface & IFACE_EXCHANGE_MASK;
     2610       
    20722611        atomic_dec(&sess->refcnt);
    20732612       
    2074         if (sess->mgmt == EXCHANGE_SERIALIZE)
     2613        if (mgmt == EXCHANGE_SERIALIZE)
    20752614                fibril_mutex_unlock(&sess->mutex);
    20762615       
     
    22812820bool async_data_read_receive(ipc_callid_t *callid, size_t *size)
    22822821{
     2822        ipc_call_t data;
     2823        return async_data_read_receive_call(callid, &data, size);
     2824}
     2825
     2826/** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework.
     2827 *
     2828 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ
     2829 * calls so that the user doesn't have to remember the meaning of each IPC
     2830 * argument.
     2831 *
     2832 * So far, this wrapper is to be used from within a connection fibril.
     2833 *
     2834 * @param callid Storage for the hash of the IPC_M_DATA_READ.
     2835 * @param size   Storage for the maximum size. Can be NULL.
     2836 *
     2837 * @return True on success, false on failure.
     2838 *
     2839 */
     2840bool async_data_read_receive_call(ipc_callid_t *callid, ipc_call_t *data,
     2841    size_t *size)
     2842{
    22832843        assert(callid);
    2284        
    2285         ipc_call_t data;
    2286         *callid = async_get_call(&data);
    2287        
    2288         if (IPC_GET_IMETHOD(data) != IPC_M_DATA_READ)
     2844        assert(data);
     2845       
     2846        *callid = async_get_call(data);
     2847       
     2848        if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ)
    22892849                return false;
    22902850       
    22912851        if (size)
    2292                 *size = (size_t) IPC_GET_ARG2(data);
     2852                *size = (size_t) IPC_GET_ARG2(*data);
    22932853       
    22942854        return true;
     
    23852945bool async_data_write_receive(ipc_callid_t *callid, size_t *size)
    23862946{
     2947        ipc_call_t data;
     2948        return async_data_write_receive_call(callid, &data, size);
     2949}
     2950
     2951/** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework.
     2952 *
     2953 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE
     2954 * calls so that the user doesn't have to remember the meaning of each IPC
     2955 * argument.
     2956 *
     2957 * So far, this wrapper is to be used from within a connection fibril.
     2958 *
     2959 * @param callid Storage for the hash of the IPC_M_DATA_WRITE.
     2960 * @param data   Storage for the ipc call data.
     2961 * @param size   Storage for the suggested size. May be NULL.
     2962 *
     2963 * @return True on success, false on failure.
     2964 *
     2965 */
     2966bool async_data_write_receive_call(ipc_callid_t *callid, ipc_call_t *data,
     2967    size_t *size)
     2968{
    23872969        assert(callid);
    2388        
    2389         ipc_call_t data;
    2390         *callid = async_get_call(&data);
    2391        
    2392         if (IPC_GET_IMETHOD(data) != IPC_M_DATA_WRITE)
     2970        assert(data);
     2971       
     2972        *callid = async_get_call(data);
     2973       
     2974        if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE)
    23932975                return false;
    23942976       
    23952977        if (size)
    2396                 *size = (size_t) IPC_GET_ARG2(data);
     2978                *size = (size_t) IPC_GET_ARG2(*data);
    23972979       
    23982980        return true;
     
    24663048        }
    24673049       
    2468         void *_data;
     3050        void *arg_data;
    24693051       
    24703052        if (nullterm)
    2471                 _data = malloc(size + 1);
     3053                arg_data = malloc(size + 1);
    24723054        else
    2473                 _data = malloc(size);
    2474        
    2475         if (_data == NULL) {
     3055                arg_data = malloc(size);
     3056       
     3057        if (arg_data == NULL) {
    24763058                ipc_answer_0(callid, ENOMEM);
    24773059                return ENOMEM;
    24783060        }
    24793061       
    2480         int rc = async_data_write_finalize(callid, _data, size);
     3062        int rc = async_data_write_finalize(callid, arg_data, size);
    24813063        if (rc != EOK) {
    2482                 free(_data);
     3064                free(arg_data);
    24833065                return rc;
    24843066        }
    24853067       
    24863068        if (nullterm)
    2487                 ((char *) _data)[size] = 0;
    2488        
    2489         *data = _data;
     3069                ((char *) arg_data)[size] = 0;
     3070       
     3071        *data = arg_data;
    24903072        if (received != NULL)
    24913073                *received = size;
     
    25853167        }
    25863168       
     3169        sess->iface = 0;
    25873170        sess->mgmt = mgmt;
    25883171        sess->phone = phone;
     
    26343217        }
    26353218       
     3219        sess->iface = 0;
    26363220        sess->mgmt = mgmt;
    26373221        sess->phone = phone;
     
    26793263                return NULL;
    26803264       
     3265        sess->iface = 0;
    26813266        sess->mgmt = mgmt;
    26823267        sess->phone = phone;
     
    27063291{
    27073292        assert(callid);
    2708 
     3293       
    27093294        ipc_call_t call;
    27103295        *callid = async_get_call(&call);
    2711 
     3296       
    27123297        if (IPC_GET_IMETHOD(call) != IPC_M_STATE_CHANGE_AUTHORIZE)
    27133298                return false;
     
    27193304        if (arg3)
    27203305                *arg3 = IPC_GET_ARG3(call);
    2721 
     3306       
    27223307        return true;
    27233308}
     
    27983383}
    27993384
     3385void *async_as_area_create(void *base, size_t size, unsigned int flags,
     3386    async_sess_t *pager, sysarg_t id1, sysarg_t id2, sysarg_t id3)
     3387{
     3388        as_area_pager_info_t pager_info = {
     3389                .pager = pager->phone,
     3390                .id1 = id1,
     3391                .id2 = id2,
     3392                .id3 = id3
     3393        };
     3394        return as_area_create(base, size, flags, &pager_info);
     3395}
     3396
    28003397/** @}
    28013398 */
Note: See TracChangeset for help on using the changeset viewer.