Ignore:
File:
1 edited

Legend:

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

    rae6021d rdf956b9b  
    7777 *   }
    7878 *
    79  *   port_handler(icallid, *icall)
     79 *   my_client_connection(icallid, *icall)
    8080 *   {
    8181 *     if (want_refuse) {
     
    101101#undef LIBC_ASYNC_C_
    102102
    103 #include <ipc/irq.h>
    104 #include <ipc/event.h>
    105103#include <futex.h>
    106104#include <fibril.h>
     
    116114#include <stdlib.h>
    117115#include <macros.h>
    118 #include <as.h>
    119 #include <abi/mm/as.h>
    120116#include "private/libc.h"
     117
    121118
    122119/** Session data */
     
    125122        list_t exch_list;
    126123       
    127         /** Session interface */
    128         iface_t iface;
    129        
    130124        /** Exchange management style */
    131125        exch_mgmt_t mgmt;
     
    172166
    173167/** Async framework global futex */
    174 futex_t async_futex = FUTEX_INITIALIZER;
     168atomic_t async_futex = FUTEX_INITIALIZER;
    175169
    176170/** Number of threads waiting for IPC in the kernel. */
     
    194188        /** If reply was received. */
    195189        bool done;
    196        
     190
    197191        /** If the message / reply should be discarded on arrival. */
    198192        bool forget;
    199        
     193
    200194        /** If already destroyed. */
    201195        bool destroyed;
     
    237231        /** Identification of the opening call. */
    238232        ipc_callid_t callid;
    239        
    240233        /** Call data of the opening call. */
    241234        ipc_call_t call;
     235        /** Local argument or NULL if none. */
     236        void *carg;
    242237       
    243238        /** Identification of the closing call. */
     
    245240       
    246241        /** Fibril function that will be used to handle the connection. */
    247         async_port_handler_t handler;
    248        
    249         /** Client data */
    250         void *data;
     242        async_client_conn_t cfibril;
    251243} connection_t;
    252 
    253 /** Interface data */
    254 typedef 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 */
    271 typedef 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 */
    285 typedef 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;
    297244
    298245/** Identifier of the incoming connection handled by the current fibril. */
     
    302249{
    303250        struct timeval tv = { 0, 0 };
    304        
     251
    305252        to->inlist = false;
    306253        to->occurred = false;
     
    325272static amsg_t *amsg_create(void)
    326273{
    327         amsg_t *msg = malloc(sizeof(amsg_t));
     274        amsg_t *msg;
     275
     276        msg = malloc(sizeof(amsg_t));
    328277        if (msg) {
    329278                msg->done = false;
     
    334283                awaiter_initialize(&msg->wdata);
    335284        }
    336        
     285
    337286        return msg;
    338287}
     
    371320}
    372321
    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.
     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.
    377325 *
    378326 * @param callid Hash of the incoming call.
     
    381329 *
    382330 */
    383 static void default_fallback_port_handler(ipc_callid_t callid, ipc_call_t *call,
     331static void default_client_connection(ipc_callid_t callid, ipc_call_t *call,
    384332    void *arg)
    385333{
     
    387335}
    388336
    389 static async_port_handler_t fallback_port_handler =
    390     default_fallback_port_handler;
    391 static void *fallback_port_data = NULL;
    392 
    393 static hash_table_t interface_hash_table;
    394 
    395 static size_t interface_key_hash(void *key)
    396 {
    397         iface_t iface = *(iface_t *) key;
    398         return iface;
    399 }
    400 
    401 static 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 
    407 static 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. */
    415 static 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 
    423 static size_t port_key_hash(void *key)
    424 {
    425         port_id_t port_id = *(port_id_t *) key;
    426         return port_id;
    427 }
    428 
    429 static 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 
    435 static 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. */
    443 static 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 
    451 static 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 
    474 static 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;
     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 */
     346static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
     347{
     348}
     349
     350static async_client_conn_t client_connection = default_client_connection;
     351static async_interrupt_handler_t interrupt_received = default_interrupt_received;
     352static 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 */
     359void 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 */
     370void 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 */
     379void async_set_interrupt_handler_stack_size(size_t size)
     380{
     381        interrupt_handler_stksz = size;
    495382}
    496383
     
    509396 */
    510397static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
    511 
    512 int 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 
    546 void 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 }
    553398
    554399static hash_table_t client_hash_table;
    555400static hash_table_t conn_hash_table;
    556 static hash_table_t notification_hash_table;
    557401static LIST_INITIALIZE(timeout_list);
    558402
    559 static sysarg_t notification_avail = 0;
    560 
    561 static size_t client_key_hash(void *key)
    562 {
    563         task_id_t in_task_id = *(task_id_t *) key;
    564         return in_task_id;
     403static size_t client_key_hash(void *k)
     404{
     405        task_id_t key = *(task_id_t*)k;
     406        return key;
    565407}
    566408
     
    571413}
    572414
    573 static bool client_key_equal(void *key, const ht_link_t *item)
    574 {
    575         task_id_t in_task_id = *(task_id_t *) key;
     415static bool client_key_equal(void *k, const ht_link_t *item)
     416{
     417        task_id_t key = *(task_id_t*)k;
    576418        client_t *client = hash_table_get_inst(item, client_t, link);
    577         return in_task_id == client->in_task_id;
    578 }
     419        return key == client->in_task_id;
     420}
     421
    579422
    580423/** Operations for the client hash table. */
     
    596439static size_t conn_key_hash(void *key)
    597440{
    598         sysarg_t in_phone_hash = *(sysarg_t *) key;
    599         return in_phone_hash;
     441        sysarg_t in_phone_hash  = *(sysarg_t*)key;
     442        return in_phone_hash ;
    600443}
    601444
     
    608451static bool conn_key_equal(void *key, const ht_link_t *item)
    609452{
    610         sysarg_t in_phone_hash = *(sysarg_t *) key;
     453        sysarg_t in_phone_hash = *(sysarg_t*)key;
    611454        connection_t *conn = hash_table_get_inst(item, connection_t, link);
    612455        return (in_phone_hash == conn->in_phone_hash);
    613456}
     457
    614458
    615459/** Operations for the connection hash table. */
     
    622466};
    623467
    624 static 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 
    648 static 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  */
    680 static 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  */
    764 static 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  */
    826 int 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 
    878 static size_t notification_key_hash(void *key)
    879 {
    880         sysarg_t id = *(sysarg_t *) key;
    881         return id;
    882 }
    883 
    884 static 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 
    891 static 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. */
    900 static 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 
    908468/** Sort in current fibril's timeout request.
    909469 *
     
    951511        futex_down(&async_futex);
    952512       
    953         ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash);
    954         if (!link) {
     513        ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash);
     514       
     515        if (!hlp) {
    955516                futex_up(&async_futex);
    956517                return false;
    957518        }
    958519       
    959         connection_t *conn = hash_table_get_inst(link, connection_t, link);
     520        connection_t *conn = hash_table_get_inst(hlp, connection_t, link);
    960521       
    961522        msg_t *msg = malloc(sizeof(*msg));
     
    989550}
    990551
    991 /** Process notification.
     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 */
     562static 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.
    992576 *
    993577 * @param callid Hash of the incoming call.
    994578 * @param call   Data of the incoming call.
    995579 *
    996  */
    997 static void process_notification(ipc_callid_t callid, ipc_call_t *call)
    998 {
    999         async_notification_handler_t handler = NULL;
    1000         void *data = NULL;
    1001 
     580 * @return False if an error occured.
     581 *         True if the call was passed to the notification fibril.
     582 *
     583 */
     584static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
     585{
    1002586        assert(call);
    1003587       
    1004588        futex_down(&async_futex);
    1005589       
    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         }
     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);
    1014608       
    1015609        futex_up(&async_futex);
    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  */
    1032 int 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  */
    1064 int 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  */
    1081 int 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  */
    1114 int 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  */
    1145 int 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  */
    1157 int async_event_task_unmask(event_task_type_t evno)
    1158 {
    1159         return ipc_event_task_unmask(evno);
     610        return true;
    1160611}
    1161612
     
    1189640        if (usecs) {
    1190641                getuptime(&conn->wdata.to_event.expires);
    1191                 tv_add_diff(&conn->wdata.to_event.expires, usecs);
     642                tv_add(&conn->wdata.to_event.expires, usecs);
    1192643        } else
    1193644                conn->wdata.to_event.inlist = false;
     
    1235686        }
    1236687       
    1237         msg_t *msg = list_get_instance(list_first(&conn->msg_queue),
    1238             msg_t, link);
     688        msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link);
    1239689        list_remove(&msg->link);
    1240690       
     
    1247697}
    1248698
     699static 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
     723static 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
    1249745void *async_get_client_data(void)
    1250746{
     
    1258754        if (!client)
    1259755                return NULL;
    1260        
    1261756        if (!client->data) {
    1262757                async_client_put(client);
    1263758                return NULL;
    1264759        }
    1265        
     760
    1266761        return client->data;
    1267762}
     
    1270765{
    1271766        client_t *client = async_client_get(client_id, false);
    1272        
     767
    1273768        assert(client);
    1274769        assert(client->data);
    1275        
     770
    1276771        /* Drop the reference we got in async_get_client_data_by_hash(). */
    1277772        async_client_put(client);
    1278        
     773
    1279774        /* Drop our own reference we got at the beginning of this function. */
    1280775        async_client_put(client);
    1281776}
    1282777
    1283 static port_t *async_find_port(iface_t iface, port_id_t port_id)
    1284 {
    1285         port_t *port = NULL;
    1286        
     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 */
     788static 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         */
    1287825        futex_down(&async_futex);
    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        
     826        hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
    1299827        futex_up(&async_futex);
    1300828       
    1301         return port;
     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 */
     873fid_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;
    1302918}
    1303919
     
    1315931        assert(call);
    1316932       
    1317         /* Kernel notification */
     933        /* Unrouted call - take some default action */
    1318934        if ((callid & IPC_CALLID_NOTIFICATION)) {
    1319                 fibril_t *fibril = (fibril_t *) __tcb_get()->fibril_data;
    1320                 unsigned oldsw = fibril->switches;
    1321                
    1322935                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                
    1340936                return;
    1341937        }
    1342938       
    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                
     939        switch (IPC_GET_IMETHOD(*call)) {
     940        case IPC_M_CLONE_ESTABLISH:
     941        case IPC_M_CONNECT_ME_TO:
    1367942                /* Open new connection with fibril, etc. */
    1368943                async_new_connection(call->in_task_id, IPC_GET_ARG5(*call),
    1369                     callid, call, fallback_port_handler, fallback_port_data);
     944                    callid, call, client_connection, NULL);
    1370945                return;
    1371946        }
     
    14591034
    14601035                        } else {
    1461                                 timeout = tv_sub_diff(&waiter->to_event.expires,
    1462                                     &tv);
     1036                                timeout = tv_sub(&waiter->to_event.expires, &tv);
    14631037                                futex_up(&async_futex);
    14641038                        }
     
    15121086void async_create_manager(void)
    15131087{
    1514         fid_t fid = fibril_create_generic(async_manager_fibril, NULL, PAGE_SIZE);
     1088        fid_t fid = fibril_create(async_manager_fibril, NULL);
    15151089        if (fid != 0)
    15161090                fibril_add_manager(fid);
     
    15281102void __async_init(void)
    15291103{
    1530         if (!hash_table_create(&interface_hash_table, 0, 0,
    1531             &interface_hash_table_ops))
    1532                 abort();
    1533        
    15341104        if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops))
    15351105                abort();
    15361106       
    15371107        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))
    15421108                abort();
    15431109       
     
    15461112                abort();
    15471113       
    1548         session_ns->iface = 0;
    15491114        session_ns->mgmt = EXCHANGE_ATOMIC;
    15501115        session_ns->phone = PHONE_NS;
     
    15931158       
    15941159        msg->done = true;
    1595        
     1160
    15961161        if (msg->forget) {
    15971162                assert(msg->wdata.active);
     
    16011166                fibril_add_ready(msg->wdata.fid);
    16021167        }
    1603        
     1168
    16041169        futex_up(&async_futex);
    16051170}
     
    16361201       
    16371202        ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
    1638             reply_received);
     1203            reply_received, true);
    16391204       
    16401205        return (aid_t) msg;
     
    16741239       
    16751240        ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
    1676             msg, reply_received);
     1241            msg, reply_received, true);
    16771242       
    16781243        return (aid_t) msg;
     
    16931258       
    16941259        futex_down(&async_futex);
    1695        
     1260
    16961261        assert(!msg->forget);
    16971262        assert(!msg->destroyed);
    1698        
     1263
    16991264        if (msg->done) {
    17001265                futex_up(&async_futex);
     
    17371302       
    17381303        amsg_t *msg = (amsg_t *) amsgid;
    1739        
     1304
    17401305        futex_down(&async_futex);
    1741        
     1306
    17421307        assert(!msg->forget);
    17431308        assert(!msg->destroyed);
    1744        
     1309
    17451310        if (msg->done) {
    17461311                futex_up(&async_futex);
     
    17541319        if (timeout < 0)
    17551320                timeout = 0;
    1756        
     1321
    17571322        getuptime(&msg->wdata.to_event.expires);
    1758         tv_add_diff(&msg->wdata.to_event.expires, timeout);
     1323        tv_add(&msg->wdata.to_event.expires, timeout);
    17591324       
    17601325        /*
     
    18071372{
    18081373        amsg_t *msg = (amsg_t *) amsgid;
    1809        
     1374
    18101375        assert(msg);
    18111376        assert(!msg->forget);
    18121377        assert(!msg->destroyed);
    1813        
     1378
    18141379        futex_down(&async_futex);
    1815        
    18161380        if (msg->done) {
    18171381                amsg_destroy(msg);
     
    18201384                msg->forget = true;
    18211385        }
    1822        
    18231386        futex_up(&async_futex);
    18241387}
     
    18401403       
    18411404        getuptime(&msg->wdata.to_event.expires);
    1842         tv_add_diff(&msg->wdata.to_event.expires, timeout);
     1405        tv_add(&msg->wdata.to_event.expires, timeout);
    18431406       
    18441407        futex_down(&async_futex);
     
    19631526{
    19641527        if (exch != NULL)
    1965                 ipc_call_async_0(exch->phone, imethod, NULL, NULL);
     1528                ipc_call_async_0(exch->phone, imethod, NULL, NULL, true);
    19661529}
    19671530
     
    19691532{
    19701533        if (exch != NULL)
    1971                 ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL);
     1534                ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL, true);
    19721535}
    19731536
     
    19761539{
    19771540        if (exch != NULL)
    1978                 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL);
     1541                ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL,
     1542                    true);
    19791543}
    19801544
     
    19841548        if (exch != NULL)
    19851549                ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
    1986                     NULL);
     1550                    NULL, true);
    19871551}
    19881552
     
    19921556        if (exch != NULL)
    19931557                ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
    1994                     NULL, NULL);
     1558                    NULL, NULL, true);
    19951559}
    19961560
     
    20001564        if (exch != NULL)
    20011565                ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
    2002                     arg5, NULL, NULL);
     1566                    arg5, NULL, NULL, true);
    20031567}
    20041568
     
    20651629 * @param arg2            User defined argument.
    20661630 * @param arg3            User defined argument.
     1631 * @param client_receiver Connection handing routine.
    20671632 *
    20681633 * @return Zero on success or a negative error code.
     
    20701635 */
    20711636int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
    2072     sysarg_t arg3)
     1637    sysarg_t arg3, async_client_conn_t client_receiver, void *carg)
    20731638{
    20741639        if (exch == NULL)
    20751640                return ENOENT;
    20761641       
     1642        sysarg_t phone_hash;
     1643        sysarg_t rc;
     1644
     1645        aid_t req;
    20771646        ipc_call_t answer;
    2078         aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     1647        req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
    20791648            &answer);
    2080        
    2081         sysarg_t rc;
    20821649        async_wait_for(req, &rc);
    20831650        if (rc != EOK)
    20841651                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);
    20851658       
    20861659        return EOK;
     
    21231696       
    21241697        ipc_call_async_0(exch->phone, IPC_M_CLONE_ESTABLISH, msg,
    2125             reply_received);
     1698            reply_received, true);
    21261699       
    21271700        sysarg_t rc;
     
    21421715        }
    21431716       
    2144         sess->iface = 0;
    21451717        sess->mgmt = mgmt;
    21461718        sess->phone = phone;
     
    21721744       
    21731745        ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
    2174             msg, reply_received);
     1746            msg, reply_received, true);
    21751747       
    21761748        sysarg_t rc;
     
    22121784        int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
    22131785            0);
     1786       
    22141787        if (phone < 0) {
    22151788                errno = phone;
     
    22181791        }
    22191792       
    2220         sess->iface = 0;
    22211793        sess->mgmt = mgmt;
    22221794        sess->phone = phone;
     
    22351807}
    22361808
    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  */
    2250 async_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 
    22881809/** Set arguments for new connections.
    22891810 *
     
    23411862        }
    23421863       
    2343         sess->iface = 0;
    23441864        sess->mgmt = mgmt;
    23451865        sess->phone = phone;
     
    23581878}
    23591879
    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  */
    2373 async_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 
    24111880/** Connect to a task specified by id.
    24121881 *
     
    24271896        }
    24281897       
    2429         sess->iface = 0;
    24301898        sess->mgmt = EXCHANGE_ATOMIC;
    24311899        sess->phone = phone;
     
    25051973                return NULL;
    25061974       
    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;
     1975        async_exch_t *exch;
    25121976       
    25131977        fibril_mutex_lock(&async_sess_mutex);
     
    25281992                 */
    25291993               
    2530                 if ((mgmt == EXCHANGE_ATOMIC) ||
    2531                     (mgmt == EXCHANGE_SERIALIZE)) {
     1994                if ((sess->mgmt == EXCHANGE_ATOMIC) ||
     1995                    (sess->mgmt == EXCHANGE_SERIALIZE)) {
    25321996                        exch = (async_exch_t *) malloc(sizeof(async_exch_t));
    25331997                        if (exch != NULL) {
     
    25372001                                exch->phone = sess->phone;
    25382002                        }
    2539                 } else if (mgmt == EXCHANGE_PARALLEL) {
    2540                         int phone;
    2541                        
    2542                 retry:
     2003                } else {  /* EXCHANGE_PARALLEL */
    25432004                        /*
    25442005                         * Make a one-time attempt to connect a new data phone.
    25452006                         */
     2007                       
     2008                        int phone;
     2009                       
     2010retry:
    25462011                        phone = async_connect_me_to_internal(sess->phone, sess->arg1,
    25472012                            sess->arg2, sess->arg3, 0);
     
    25852050                atomic_inc(&sess->refcnt);
    25862051               
    2587                 if (mgmt == EXCHANGE_SERIALIZE)
     2052                if (sess->mgmt == EXCHANGE_SERIALIZE)
    25882053                        fibril_mutex_lock(&sess->mutex);
    25892054        }
     
    26052070        assert(sess != NULL);
    26062071       
    2607         exch_mgmt_t mgmt = sess->mgmt;
    2608         if (sess->iface != 0)
    2609                 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
    2610        
    26112072        atomic_dec(&sess->refcnt);
    26122073       
    2613         if (mgmt == EXCHANGE_SERIALIZE)
     2074        if (sess->mgmt == EXCHANGE_SERIALIZE)
    26142075                fibril_mutex_unlock(&sess->mutex);
    26152076       
     
    28202281bool async_data_read_receive(ipc_callid_t *callid, size_t *size)
    28212282{
     2283        assert(callid);
     2284       
    28222285        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  */
    2840 bool async_data_read_receive_call(ipc_callid_t *callid, ipc_call_t *data,
    2841     size_t *size)
    2842 {
    2843         assert(callid);
    2844         assert(data);
    2845        
    2846         *callid = async_get_call(data);
    2847        
    2848         if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ)
     2286        *callid = async_get_call(&data);
     2287       
     2288        if (IPC_GET_IMETHOD(data) != IPC_M_DATA_READ)
    28492289                return false;
    28502290       
    28512291        if (size)
    2852                 *size = (size_t) IPC_GET_ARG2(*data);
     2292                *size = (size_t) IPC_GET_ARG2(data);
    28532293       
    28542294        return true;
     
    29452385bool async_data_write_receive(ipc_callid_t *callid, size_t *size)
    29462386{
     2387        assert(callid);
     2388       
    29472389        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  */
    2966 bool async_data_write_receive_call(ipc_callid_t *callid, ipc_call_t *data,
    2967     size_t *size)
    2968 {
    2969         assert(callid);
    2970         assert(data);
    2971        
    2972         *callid = async_get_call(data);
    2973        
    2974         if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE)
     2390        *callid = async_get_call(&data);
     2391       
     2392        if (IPC_GET_IMETHOD(data) != IPC_M_DATA_WRITE)
    29752393                return false;
    29762394       
    29772395        if (size)
    2978                 *size = (size_t) IPC_GET_ARG2(*data);
     2396                *size = (size_t) IPC_GET_ARG2(data);
    29792397       
    29802398        return true;
     
    30482466        }
    30492467       
    3050         void *arg_data;
     2468        void *_data;
    30512469       
    30522470        if (nullterm)
    3053                 arg_data = malloc(size + 1);
     2471                _data = malloc(size + 1);
    30542472        else
    3055                 arg_data = malloc(size);
    3056        
    3057         if (arg_data == NULL) {
     2473                _data = malloc(size);
     2474       
     2475        if (_data == NULL) {
    30582476                ipc_answer_0(callid, ENOMEM);
    30592477                return ENOMEM;
    30602478        }
    30612479       
    3062         int rc = async_data_write_finalize(callid, arg_data, size);
     2480        int rc = async_data_write_finalize(callid, _data, size);
    30632481        if (rc != EOK) {
    3064                 free(arg_data);
     2482                free(_data);
    30652483                return rc;
    30662484        }
    30672485       
    30682486        if (nullterm)
    3069                 ((char *) arg_data)[size] = 0;
    3070        
    3071         *data = arg_data;
     2487                ((char *) _data)[size] = 0;
     2488       
     2489        *data = _data;
    30722490        if (received != NULL)
    30732491                *received = size;
     
    31672585        }
    31682586       
    3169         sess->iface = 0;
    31702587        sess->mgmt = mgmt;
    31712588        sess->phone = phone;
     
    32172634        }
    32182635       
    3219         sess->iface = 0;
    32202636        sess->mgmt = mgmt;
    32212637        sess->phone = phone;
     
    32632679                return NULL;
    32642680       
    3265         sess->iface = 0;
    32662681        sess->mgmt = mgmt;
    32672682        sess->phone = phone;
     
    32912706{
    32922707        assert(callid);
    3293        
     2708
    32942709        ipc_call_t call;
    32952710        *callid = async_get_call(&call);
    3296        
     2711
    32972712        if (IPC_GET_IMETHOD(call) != IPC_M_STATE_CHANGE_AUTHORIZE)
    32982713                return false;
     
    33042719        if (arg3)
    33052720                *arg3 = IPC_GET_ARG3(call);
    3306        
     2721
    33072722        return true;
    33082723}
     
    33832798}
    33842799
    3385 void *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 
    33972800/** @}
    33982801 */
Note: See TracChangeset for help on using the changeset viewer.