Changeset c07544d3 in mainline


Ignore:
Timestamp:
2009-04-24T15:38:18Z (15 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
10270a8
Parents:
422fd81
Message:

create a new fibril for each notification received, which allows to do nested async calls from the notification handler
(this fixes ticket #19 and solves various problems with klog)

Location:
uspace/lib/libc
Files:
2 edited

Legend:

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

    r422fd81 rc07544d3  
    3131 */
    3232/** @file
    33  */ 
     33 */
    3434
    3535/**
    3636 * Asynchronous library
    3737 *
    38  * The aim of this library is facilitating writing programs utilizing the
    39  * asynchronous nature of HelenOS IPC, yet using a normal way of programming.
     38 * The aim of this library is to provide a facility for writing programs which
     39 * utilize the asynchronous nature of HelenOS IPC, yet using a normal way of
     40 * programming.
    4041 *
    4142 * You should be able to write very simple multithreaded programs, the async
     
    4344 *
    4445 * Default semantics:
    45  * - async_send_*():    send asynchronously. If the kernel refuses to send
    46  *                      more messages, [ try to get responses from kernel, if
    47  *                      nothing found, might try synchronous ]
     46 * - async_send_*(): Send asynchronously. If the kernel refuses to send
     47 *                   more messages, [ try to get responses from kernel, if
     48 *                   nothing found, might try synchronous ]
    4849 *
    4950 * Example of use (pseudo C):
    50  * 
     51 *
    5152 * 1) Multithreaded client application
    5253 *
    53  * fibril_create(fibril1, ...);
    54  * fibril_create(fibril2, ...);
    55  * ...
    56  * 
    57  * int fibril1(void *arg)
    58  * {
    59  *      conn = ipc_connect_me_to();
    60  *      c1 = async_send(conn);
    61  *      c2 = async_send(conn);
    62  *      async_wait_for(c1);
    63  *      async_wait_for(c2);
    64  *      ...
    65  * }
     54 *   fibril_create(fibril1, ...);
     55 *   fibril_create(fibril2, ...);
     56 *   ...
     57 *
     58 *   int fibril1(void *arg)
     59 *   {
     60 *     conn = ipc_connect_me_to();
     61 *     c1 = async_send(conn);
     62 *     c2 = async_send(conn);
     63 *     async_wait_for(c1);
     64 *     async_wait_for(c2);
     65 *     ...
     66 *   }
    6667 *
    6768 *
    6869 * 2) Multithreaded server application
    69  * main()
    70  * {
    71  *      async_manager();
    72  * }
    73  *
    74  *
    75  * my_client_connection(icallid, *icall)
    76  * {
    77  *      if (want_refuse) {
    78  *              ipc_answer_0(icallid, ELIMIT);
    79  *              return;
    80  *      }
    81  *      ipc_answer_0(icallid, EOK);
    82  *
    83  *      callid = async_get_call(&call);
    84  *      handle_call(callid, call);
    85  *      ipc_answer_2(callid, 1, 2, 3);
    86  *
    87  *      callid = async_get_call(&call);
    88  *      ....
    89  * }
     70 *
     71 *   main()
     72 *   {
     73 *     async_manager();
     74 *   }
     75 *
     76 *   my_client_connection(icallid, *icall)
     77 *   {
     78 *     if (want_refuse) {
     79 *       ipc_answer_0(icallid, ELIMIT);
     80 *       return;
     81 *     }
     82 *     ipc_answer_0(icallid, EOK);
     83 *
     84 *     callid = async_get_call(&call);
     85 *     handle_call(callid, call);
     86 *     ipc_answer_2(callid, 1, 2, 3);
     87 *
     88 *     callid = async_get_call(&call);
     89 *     ...
     90 *   }
    9091 *
    9192 */
     
    105106
    106107atomic_t async_futex = FUTEX_INITIALIZER;
    107 static hash_table_t conn_hash_table;
    108 static LIST_INITIALIZE(timeout_list);
    109108
    110109/** Structures of this type represent a waiting fibril. */
    111110typedef struct {
    112111        /** Expiration time. */
    113         struct timeval expires;         
     112        struct timeval expires;
     113       
    114114        /** If true, this struct is in the timeout list. */
    115         int inlist;
     115        bool inlist;
     116       
    116117        /** Timeout list link. */
    117118        link_t link;
    118 
     119       
    119120        /** Identification of and link to the waiting fibril. */
    120121        fid_t fid;
     122       
    121123        /** If true, this fibril is currently active. */
    122         int active;
     124        bool active;
     125       
    123126        /** If true, we have timed out. */
    124         int timedout;
     127        bool timedout;
    125128} awaiter_t;
    126129
     
    129132       
    130133        /** If reply was received. */
    131         int done;
     134        bool done;
     135       
    132136        /** Pointer to where the answer data is stored. */
    133         ipc_call_t *dataptr;
    134 
     137        ipc_call_t *dataptr;
     138       
    135139        ipcarg_t retval;
    136140} amsg_t;
     
    148152typedef struct {
    149153        awaiter_t wdata;
    150 
     154       
    151155        /** Hash table link. */
    152156        link_t link;
    153 
     157       
    154158        /** Incoming phone hash. */
    155         ipcarg_t in_phone_hash;         
    156 
     159        ipcarg_t in_phone_hash;
     160       
    157161        /** Messages that should be delivered to this fibril. */
    158         link_t msg_queue;               
    159                                          
     162        link_t msg_queue;
     163       
    160164        /** Identification of the opening call. */
    161165        ipc_callid_t callid;
    162166        /** Call data of the opening call. */
    163167        ipc_call_t call;
    164 
     168       
    165169        /** Identification of the closing call. */
    166170        ipc_callid_t close_callid;
    167 
     171       
    168172        /** Fibril function that will be used to handle the connection. */
    169173        void (*cfibril)(ipc_callid_t, ipc_call_t *);
     
    173177__thread connection_t *FIBRIL_connection;
    174178
    175 /**
    176  * If true, it is forbidden to use async_req functions and all preemption is
    177  * disabled.
    178  */
    179 __thread int _in_interrupt_handler;
    180 
    181179static void default_client_connection(ipc_callid_t callid, ipc_call_t *call);
    182180static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call);
     
    186184 */
    187185static async_client_conn_t client_connection = default_client_connection;
     186
    188187/**
    189188 * Pointer to a fibril function that will be used to handle interrupt
     
    192191static async_client_conn_t interrupt_received = default_interrupt_received;
    193192
    194 /*
    195  * Getter for _in_interrupt_handler. We need to export the value of this thread
    196  * local variable to other modules, but the binutils 2.18 linkers die on an
    197  * attempt to export this symbol in the header file. For now, consider this as a
    198  * workaround.
    199  */
    200 bool in_interrupt_handler(void)
    201 {
    202         return _in_interrupt_handler;
    203 }
    204 
    205 #define CONN_HASH_TABLE_CHAINS  32
     193
     194static hash_table_t conn_hash_table;
     195static LIST_INITIALIZE(timeout_list);
     196
     197
     198#define CONN_HASH_TABLE_CHAINS  32
    206199
    207200/** Compute hash into the connection hash table based on the source phone hash.
    208201 *
    209  * @param key           Pointer to source phone hash.
    210  *
    211  * @return              Index into the connection hash table.
     202 * @param key Pointer to source phone hash.
     203 *
     204 * @return Index into the connection hash table.
     205 *
    212206 */
    213207static hash_index_t conn_hash(unsigned long *key)
    214208{
    215209        assert(key);
    216         return ((*key) >> 4) % CONN_HASH_TABLE_CHAINS;
     210        return (((*key) >> 4) % CONN_HASH_TABLE_CHAINS);
    217211}
    218212
    219213/** Compare hash table item with a key.
    220214 *
    221  * @param key           Array containing the source phone hash as the only item.
    222  * @param keys          Expected 1 but ignored.
    223  * @param item          Connection hash table item.
    224  *
    225  * @return              True on match, false otherwise.
     215 * @param key  Array containing the source phone hash as the only item.
     216 * @param keys Expected 1 but ignored.
     217 * @param item Connection hash table item.
     218 *
     219 * @return True on match, false otherwise.
     220 *
    226221 */
    227222static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
    228223{
    229         connection_t *hs;
    230 
    231         hs = hash_table_get_instance(item, connection_t, link);
    232        
    233         return key[0] == hs->in_phone_hash;
     224        connection_t *hs = hash_table_get_instance(item, connection_t, link);
     225        return (key[0] == hs->in_phone_hash);
    234226}
    235227
     
    239231 * hash table.
    240232 *
    241  * @param item          Connection hash table item being removed.
     233 * @param item Connection hash table item being removed.
     234 *
    242235 */
    243236static void conn_remove(link_t *item)
     
    256249/** Sort in current fibril's timeout request.
    257250 *
    258  * @param wd            Wait data of the current fibril.
     251 * @param wd Wait data of the current fibril.
     252 *
    259253 */
    260254static void insert_timeout(awaiter_t *wd)
    261255{
    262         link_t *tmp;
    263         awaiter_t *cur;
    264 
    265         wd->timedout = 0;
    266         wd->inlist = 1;
    267 
    268         tmp = timeout_list.next;
     256        wd->timedout = false;
     257        wd->inlist = true;
     258       
     259        link_t *tmp = timeout_list.next;
    269260        while (tmp != &timeout_list) {
    270                 cur = list_get_instance(tmp, awaiter_t, link);
     261                awaiter_t *cur = list_get_instance(tmp, awaiter_t, link);
     262               
    271263                if (tv_gteq(&cur->expires, &wd->expires))
    272264                        break;
     265               
    273266                tmp = tmp->next;
    274267        }
     268       
    275269        list_append(&wd->link, tmp);
    276270}
     
    282276 * timeouts are unregistered.
    283277 *
    284  * @param callid        Hash of the incoming call.
    285  * @param call          Data of the incoming call.
    286  *
    287  * @return              Zero if the call doesn't match any connection.
    288  *                      One if the call was passed to the respective connection
    289  *                      fibril.
    290  */
    291 static int route_call(ipc_callid_t callid, ipc_call_t *call)
    292 {
    293         connection_t *conn;
    294         msg_t *msg;
    295         link_t *hlp;
    296         unsigned long key;
    297 
     278 * @param callid Hash of the incoming call.
     279 * @param call   Data of the incoming call.
     280 *
     281 * @return False if the call doesn't match any connection.
     282 *         True if the call was passed to the respective connection fibril.
     283 *
     284 */
     285static bool route_call(ipc_callid_t callid, ipc_call_t *call)
     286{
    298287        futex_down(&async_futex);
    299 
    300         key = call->in_phone_hash;
    301         hlp = hash_table_find(&conn_hash_table, &key);
     288       
     289        unsigned long key = call->in_phone_hash;
     290        link_t *hlp = hash_table_find(&conn_hash_table, &key);
     291       
    302292        if (!hlp) {
    303293                futex_up(&async_futex);
    304                 return 0;
    305         }
    306         conn = hash_table_get_instance(hlp, connection_t, link);
    307 
    308         msg = malloc(sizeof(*msg));
     294                return false;
     295        }
     296       
     297        connection_t *conn = hash_table_get_instance(hlp, connection_t, link);
     298       
     299        msg_t *msg = malloc(sizeof(*msg));
     300        if (!msg) {
     301                futex_up(&async_futex);
     302                return false;
     303        }
     304       
    309305        msg->callid = callid;
    310306        msg->call = *call;
    311307        list_append(&msg->link, &conn->msg_queue);
    312 
     308       
    313309        if (IPC_GET_METHOD(*call) == IPC_M_PHONE_HUNGUP)
    314310                conn->close_callid = callid;
     
    316312        /* If the connection fibril is waiting for an event, activate it */
    317313        if (!conn->wdata.active) {
     314               
    318315                /* If in timeout list, remove it */
    319316                if (conn->wdata.inlist) {
    320                         conn->wdata.inlist = 0;
     317                        conn->wdata.inlist = false;
    321318                        list_remove(&conn->wdata.link);
    322319                }
    323                 conn->wdata.active = 1;
     320               
     321                conn->wdata.active = true;
    324322                fibril_add_ready(conn->wdata.fid);
    325323        }
    326 
     324       
    327325        futex_up(&async_futex);
    328 
    329         return 1;
     326        return true;
     327}
     328
     329/** Notification fibril.
     330 *
     331 * When a notification arrives, a fibril with this implementing function is
     332 * created. It calls interrupt_received() and does the final cleanup.
     333 *
     334 * @param arg Message structure pointer.
     335 *
     336 * @return Always zero.
     337 *
     338 */
     339static int notification_fibril(void *arg)
     340{
     341        msg_t *msg = (msg_t *) arg;
     342        interrupt_received(msg->callid, &msg->call);
     343       
     344        free(msg);
     345        return 0;
     346}
     347
     348/** Process interrupt notification.
     349 *
     350 * A new fibril is created which would process the notification.
     351 *
     352 * @param callid Hash of the incoming call.
     353 * @param call   Data of the incoming call.
     354 *
     355 * @return False if an error occured.
     356 *         True if the call was passed to the notification fibril.
     357 *
     358 */
     359static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
     360{
     361        futex_down(&async_futex);
     362       
     363        msg_t *msg = malloc(sizeof(*msg));
     364        if (!msg) {
     365                futex_up(&async_futex);
     366                return false;
     367        }
     368       
     369        msg->callid = callid;
     370        msg->call = *call;
     371       
     372        fid_t fid = fibril_create(notification_fibril, msg);
     373        fibril_add_ready(fid);
     374       
     375        futex_up(&async_futex);
     376        return true;
    330377}
    331378
    332379/** Return new incoming message for the current (fibril-local) connection.
    333380 *
    334  * @param call          Storage where the incoming call data will be stored.
    335  * @param usecs         Timeout in microseconds. Zero denotes no timeout.
    336  *
    337  * @return              If no timeout was specified, then a hash of the
    338  *                      incoming call is returned. If a timeout is specified,
    339  *                      then a hash of the incoming call is returned unless
    340  *                      the timeout expires prior to receiving a message. In
    341  *                      that case zero is returned.
     381 * @param call  Storage where the incoming call data will be stored.
     382 * @param usecs Timeout in microseconds. Zero denotes no timeout.
     383 *
     384 * @return If no timeout was specified, then a hash of the
     385 *         incoming call is returned. If a timeout is specified,
     386 *         then a hash of the incoming call is returned unless
     387 *         the timeout expires prior to receiving a message. In
     388 *         that case zero is returned.
     389 *
    342390 */
    343391ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
    344392{
    345         msg_t *msg;
    346         ipc_callid_t callid;
    347         connection_t *conn;
    348        
    349393        assert(FIBRIL_connection);
    350         /* GCC 4.1.0 coughs on FIBRIL_connection-> dereference,
     394       
     395        /* Why doing this?
     396         * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
    351397         * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
    352          *           I would never expect to find so many errors in 
    353          *           a compiler *($&$(*&$
     398         *           I would never expect to find so many errors in
     399         *           a compiler.
    354400         */
    355         conn = FIBRIL_connection;
    356 
     401        connection_t *conn = FIBRIL_connection;
     402       
    357403        futex_down(&async_futex);
    358 
     404       
    359405        if (usecs) {
    360406                gettimeofday(&conn->wdata.expires, NULL);
    361407                tv_add(&conn->wdata.expires, usecs);
    362         } else {
    363                 conn->wdata.inlist = 0;
    364         }
     408        } else
     409                conn->wdata.inlist = false;
     410       
    365411        /* If nothing in queue, wait until something arrives */
    366412        while (list_empty(&conn->msg_queue)) {
    367413                if (usecs)
    368414                        insert_timeout(&conn->wdata);
    369 
    370                 conn->wdata.active = 0;
     415               
     416                conn->wdata.active = false;
     417               
    371418                /*
    372419                 * Note: the current fibril will be rescheduled either due to a
     
    376423                 */
    377424                fibril_switch(FIBRIL_TO_MANAGER);
     425               
    378426                /*
    379                  * Futex is up after getting back from async_manager get it
    380                  * again.
     427                 * Futex is up after getting back from async_manager.
     428                 * Get it again.
    381429                 */
    382430                futex_down(&async_futex);
    383                 if (usecs && conn->wdata.timedout &&
    384                     list_empty(&conn->msg_queue)) {
     431                if ((usecs) && (conn->wdata.timedout)
     432                    && (list_empty(&conn->msg_queue))) {
    385433                        /* If we timed out -> exit */
    386434                        futex_up(&async_futex);
     
    389437        }
    390438       
    391         msg = list_get_instance(conn->msg_queue.next, msg_t, link);
     439        msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
    392440        list_remove(&msg->link);
    393         callid = msg->callid;
     441       
     442        ipc_callid_t callid = msg->callid;
    394443        *call = msg->call;
    395444        free(msg);
     
    403452 * This function is defined as a weak symbol - to be redefined in user code.
    404453 *
    405  * @param callid        Hash of the incoming call.
    406  * @param call          Data of the incoming call.
     454 * @param callid Hash of the incoming call.
     455 * @param call   Data of the incoming call.
     456 *
    407457 */
    408458static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
     
    413463/** Default fibril function that gets called to handle interrupt notifications.
    414464 *
    415  * @param callid        Hash of the incoming call.
    416  * @param call          Data of the incoming call.
     465 * This function is defined as a weak symbol - to be redefined in user code.
     466 *
     467 * @param callid Hash of the incoming call.
     468 * @param call   Data of the incoming call.
     469 *
    417470 */
    418471static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
     
    425478 * created. It calls client_connection() and does the final cleanup.
    426479 *
    427  * @param arg           Connection structure pointer.
    428  *
    429  * @return              Always zero.
    430  */
    431 static int connection_fibril(void  *arg)
    432 {
    433         unsigned long key;
    434         msg_t *msg;
    435         int close_answered = 0;
    436 
    437         /* Setup fibril-local connection pointer */
     480 * @param arg Connection structure pointer.
     481 *
     482 * @return Always zero.
     483 *
     484 */
     485static int connection_fibril(void *arg)
     486{
     487        /*
     488         * Setup fibril-local connection pointer and call client_connection().
     489         *
     490        */
    438491        FIBRIL_connection = (connection_t *) arg;
    439492        FIBRIL_connection->cfibril(FIBRIL_connection->callid,
     
    442495        /* Remove myself from the connection hash table */
    443496        futex_down(&async_futex);
    444         key = FIBRIL_connection->in_phone_hash;
     497        unsigned long key = FIBRIL_connection->in_phone_hash;
    445498        hash_table_remove(&conn_hash_table, &key, 1);
    446499        futex_up(&async_futex);
     
    448501        /* Answer all remaining messages with EHANGUP */
    449502        while (!list_empty(&FIBRIL_connection->msg_queue)) {
    450                 msg = list_get_instance(FIBRIL_connection->msg_queue.next,
    451                     msg_t, link);
     503                msg_t *msg
     504                    = list_get_instance(FIBRIL_connection->msg_queue.next, msg_t, link);
     505               
    452506                list_remove(&msg->link);
    453                 if (msg->callid == FIBRIL_connection->close_callid)
    454                         close_answered = 1;
    455507                ipc_answer_0(msg->callid, EHANGUP);
    456508                free(msg);
    457509        }
     510       
    458511        if (FIBRIL_connection->close_callid)
    459512                ipc_answer_0(FIBRIL_connection->close_callid, EOK);
     
    464517/** Create a new fibril for a new connection.
    465518 *
    466  * Creates new fibril for connection, fills in connection structures and inserts
     519 * Create new fibril for connection, fill in connection structures and inserts
    467520 * it into the hash table, so that later we can easily do routing of messages to
    468521 * particular fibrils.
    469522 *
    470  * @param in_phone_hash Identification of the incoming connection.
    471  * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
    472  *                      If callid is zero, the connection was opened by
    473  *                      accepting the IPC_M_CONNECT_TO_ME call and this function
    474  *                      is called directly by the server.
    475  * @param call          Call data of the opening call.
    476  * @param cfibril       Fibril function that should be called upon opening the
    477  *                      connection.
    478  *
    479  * @return              New fibril id or NULL on failure.
     523 * @param in_phone_hash Identification of the incoming connection.
     524 * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
     525 *                      If callid is zero, the connection was opened by
     526 *                      accepting the IPC_M_CONNECT_TO_ME call and this function
     527 *                      is called directly by the server.
     528 * @param call          Call data of the opening call.
     529 * @param cfibril       Fibril function that should be called upon opening the
     530 *                      connection.
     531 *
     532 * @return New fibril id or NULL on failure.
     533 *
    480534 */
    481535fid_t async_new_connection(ipcarg_t in_phone_hash, ipc_callid_t callid,
    482536    ipc_call_t *call, void (*cfibril)(ipc_callid_t, ipc_call_t *))
    483537{
    484         connection_t *conn;
    485         unsigned long key;
    486        
    487         conn = malloc(sizeof(*conn));
     538        connection_t *conn = malloc(sizeof(*conn));
    488539        if (!conn) {
    489540                if (callid)
     
    491542                return NULL;
    492543        }
     544       
    493545        conn->in_phone_hash = in_phone_hash;
    494546        list_initialize(&conn->msg_queue);
    495547        conn->callid = callid;
    496         conn->close_callid = 0;
     548        conn->close_callid = false;
     549       
    497550        if (call)
    498551                conn->call = *call;
    499         conn->wdata.active = 1; /* We will activate the fibril ASAP */
     552       
     553        /* We will activate the fibril ASAP */
     554        conn->wdata.active = true;
    500555        conn->cfibril = cfibril;
    501        
    502556        conn->wdata.fid = fibril_create(connection_fibril, conn);
     557       
    503558        if (!conn->wdata.fid) {
    504559                free(conn);
     
    509564       
    510565        /* Add connection to the connection hash table */
    511         key = conn->in_phone_hash;
     566        ipcarg_t key = conn->in_phone_hash;
     567       
    512568        futex_down(&async_futex);
    513569        hash_table_insert(&conn_hash_table, &key, &conn->link);
     
    524580 * Otherwise the call is routed to its connection fibril.
    525581 *
    526  * @param callid        Hash of the incoming call.
    527  * @param call          Data of the incoming call.
     582 * @param callid Hash of the incoming call.
     583 * @param call   Data of the incoming call.
    528584 *
    529585 */
     
    532588        /* Unrouted call - do some default behaviour */
    533589        if ((callid & IPC_CALLID_NOTIFICATION)) {
    534                 _in_interrupt_handler = 1;
    535                 (*interrupt_received)(callid, call);
    536                 _in_interrupt_handler = 0;
     590                process_notification(callid, call);
    537591                return;
    538592        }
     
    558612{
    559613        struct timeval tv;
    560         awaiter_t *waiter;
    561         link_t *cur;
    562 
    563614        gettimeofday(&tv, NULL);
     615       
    564616        futex_down(&async_futex);
    565 
    566         cur = timeout_list.next;
     617       
     618        link_t *cur = timeout_list.next;
    567619        while (cur != &timeout_list) {
    568                 waiter = list_get_instance(cur, awaiter_t, link);
     620                awaiter_t *waiter = list_get_instance(cur, awaiter_t, link);
     621               
    569622                if (tv_gt(&waiter->expires, &tv))
    570623                        break;
     624               
    571625                cur = cur->next;
     626               
    572627                list_remove(&waiter->link);
    573                 waiter->inlist = 0;
    574                 waiter->timedout = 1;
     628                waiter->inlist = false;
     629                waiter->timedout = true;
     630               
    575631                /*
    576                  * Redundant condition?
    577                  * The fibril should not be active when it gets here.
     632                 * Redundant condition?
     633                 * The fibril should not be active when it gets here.
    578634                 */
    579635                if (!waiter->active) {
    580                         waiter->active = 1;
     636                        waiter->active = true;
    581637                        fibril_add_ready(waiter->fid);
    582638                }
    583639        }
    584 
     640       
    585641        futex_up(&async_futex);
    586642}
     
    588644/** Endless loop dispatching incoming calls and answers.
    589645 *
    590  * @return              Never returns.
     646 * @return Never returns.
     647 *
    591648 */
    592649static int async_manager_worker(void)
    593650{
    594         ipc_call_t call;
    595         ipc_callid_t callid;
    596         int timeout;
    597         awaiter_t *waiter;
    598         struct timeval tv;
    599 
    600         while (1) {
     651        while (true) {
    601652                if (fibril_switch(FIBRIL_FROM_MANAGER)) {
    602653                        futex_up(&async_futex);
     
    607658                        continue;
    608659                }
     660               
    609661                futex_down(&async_futex);
     662               
     663                suseconds_t timeout;
    610664                if (!list_empty(&timeout_list)) {
    611                         waiter = list_get_instance(timeout_list.next, awaiter_t,
    612                             link);
     665                        awaiter_t *waiter
     666                            = list_get_instance(timeout_list.next, awaiter_t, link);
     667                       
     668                        struct timeval tv;
    613669                        gettimeofday(&tv, NULL);
     670                       
    614671                        if (tv_gteq(&tv, &waiter->expires)) {
    615672                                futex_up(&async_futex);
     
    620677                } else
    621678                        timeout = SYNCH_NO_TIMEOUT;
     679               
    622680                futex_up(&async_futex);
    623 
    624                 callid = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
    625 
     681               
     682                ipc_call_t call;
     683                ipc_callid_t callid
     684                    = ipc_wait_cycle(&call, timeout, SYNCH_FLAGS_NONE);
     685               
    626686                if (!callid) {
    627687                        handle_expired_timeouts();
    628688                        continue;
    629689                }
    630 
    631                 if (callid & IPC_CALLID_ANSWERED) {
     690               
     691                if (callid & IPC_CALLID_ANSWERED)
    632692                        continue;
    633                 }
    634 
     693               
    635694                handle_call(callid, &call);
    636695        }
     
    640699
    641700/** Function to start async_manager as a standalone fibril.
    642  * 
     701 *
    643702 * When more kernel threads are used, one async manager should exist per thread.
    644703 *
    645  * @param arg           Unused.
    646  *
    647  * @return              Never returns.
     704 * @param arg Unused.
     705 * @return Never returns.
     706 *
    648707 */
    649708static int async_manager_fibril(void *arg)
    650709{
    651710        futex_up(&async_futex);
     711       
    652712        /*
    653713         * async_futex is always locked when entering manager
     
    661721void async_create_manager(void)
    662722{
    663         fid_t fid;
    664 
    665         fid = fibril_create(async_manager_fibril, NULL);
     723        fid_t fid = fibril_create(async_manager_fibril, NULL);
    666724        fibril_add_manager(fid);
    667725}
     
    675733/** Initialize the async framework.
    676734 *
    677  * @return              Zero on success or an error code.
     735 * @return Zero on success or an error code.
    678736 */
    679737int _async_init(void)
     
    695753 * Notify the fibril which is waiting for this message that it has arrived.
    696754 *
    697  * @param private       Pointer to the asynchronous message record.
    698  * @param retval        Value returned in the answer.
    699  * @param data          Call data of the answer.
    700  */
    701 static void reply_received(void *private, int retval, ipc_call_t *data)
    702 {
    703         amsg_t *msg = (amsg_t *) private;
    704 
     755 * @param arg    Pointer to the asynchronous message record.
     756 * @param retval Value returned in the answer.
     757 * @param data   Call data of the answer.
     758 */
     759static void reply_received(void *arg, int retval, ipc_call_t *data)
     760{
     761        amsg_t *msg = (amsg_t *) arg;
    705762        msg->retval = retval;
    706 
     763       
    707764        futex_down(&async_futex);
     765       
    708766        /* Copy data after futex_down, just in case the call was detached */
    709767        if (msg->dataptr)
    710                 *msg->dataptr = *data; 
    711 
     768                *msg->dataptr = *data;
     769       
    712770        write_barrier();
     771       
    713772        /* Remove message from timeout list */
    714773        if (msg->wdata.inlist)
    715774                list_remove(&msg->wdata.link);
    716         msg->done = 1;
     775       
     776        msg->done = true;
    717777        if (!msg->wdata.active) {
    718                 msg->wdata.active = 1;
     778                msg->wdata.active = true;
    719779                fibril_add_ready(msg->wdata.fid);
    720780        }
     781       
    721782        futex_up(&async_futex);
    722783}
     
    727788 * completion.
    728789 *
    729  * @param phoneid       Handle of the phone that will be used for the send.
    730  * @param method        Service-defined method.
    731  * @param arg1          Service-defined payload argument.
    732  * @param arg2          Service-defined payload argument.
    733  * @param arg3          Service-defined payload argument.
    734  * @param arg4          Service-defined payload argument.
    735  * @param dataptr       If non-NULL, storage where the reply data will be
    736  *                      stored.
    737  *
    738  * @return              Hash of the sent message.
     790 * @param phoneid Handle of the phone that will be used for the send.
     791 * @param method  Service-defined method.
     792 * @param arg1    Service-defined payload argument.
     793 * @param arg2    Service-defined payload argument.
     794 * @param arg3    Service-defined payload argument.
     795 * @param arg4    Service-defined payload argument.
     796 * @param dataptr If non-NULL, storage where the reply data will be
     797 *                stored.
     798 *
     799 * @return Hash of the sent message or 0 on error.
     800 *
    739801 */
    740802aid_t async_send_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
    741803    ipcarg_t arg2, ipcarg_t arg3, ipcarg_t arg4, ipc_call_t *dataptr)
    742804{
    743         amsg_t *msg;
    744        
    745         msg = malloc(sizeof(*msg));
    746         msg->done = 0;
     805        amsg_t *msg = malloc(sizeof(*msg));
     806       
     807        if (!msg)
     808                return 0;
     809       
     810        msg->done = false;
    747811        msg->dataptr = dataptr;
    748812       
    749813        /* We may sleep in the next method, but it will use its own mechanism */
    750         msg->wdata.active = 1;
    751                                
     814        msg->wdata.active = true;
     815       
    752816        ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
    753             reply_received, !_in_interrupt_handler);
     817            reply_received, true);
    754818       
    755819        return (aid_t) msg;
     
    761825 * completion.
    762826 *
    763  * @param phoneid       Handle of the phone that will be used for the send.
    764  * @param method        Service-defined method.
    765  * @param arg1          Service-defined payload argument.
    766  * @param arg2          Service-defined payload argument.
    767  * @param arg3          Service-defined payload argument.
    768  * @param arg4          Service-defined payload argument.
    769  * @param arg5          Service-defined payload argument.
    770  * @param dataptr       If non-NULL, storage where the reply data will be
    771  *                      stored.
    772  *
    773  * @return              Hash of the sent message.
     827 * @param phoneid Handle of the phone that will be used for the send.
     828 * @param method  Service-defined method.
     829 * @param arg1    Service-defined payload argument.
     830 * @param arg2    Service-defined payload argument.
     831 * @param arg3    Service-defined payload argument.
     832 * @param arg4    Service-defined payload argument.
     833 * @param arg5    Service-defined payload argument.
     834 * @param dataptr If non-NULL, storage where the reply data will be
     835 *                stored.
     836 *
     837 * @return Hash of the sent message or 0 on error.
     838 *
    774839 */
    775840aid_t async_send_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
     
    777842    ipc_call_t *dataptr)
    778843{
    779         amsg_t *msg;
    780        
    781         msg = malloc(sizeof(*msg));
    782         msg->done = 0;
     844        amsg_t *msg = malloc(sizeof(*msg));
     845       
     846        if (!msg)
     847                return 0;
     848       
     849        msg->done = false;
    783850        msg->dataptr = dataptr;
    784851       
    785852        /* We may sleep in next method, but it will use its own mechanism */
    786         msg->wdata.active = 1;
     853        msg->wdata.active = true;
    787854       
    788855        ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
    789             reply_received, !_in_interrupt_handler);
     856            reply_received, true);
    790857       
    791858        return (aid_t) msg;
     
    794861/** Wait for a message sent by the async framework.
    795862 *
    796  * @param amsgid        Hash of the message to wait for.
    797  * @param retval        Pointer to storage where the retval of the answer will
    798  *                      be stored.
     863 * @param amsgid Hash of the message to wait for.
     864 * @param retval Pointer to storage where the retval of the answer will
     865 *               be stored.
     866 *
    799867 */
    800868void async_wait_for(aid_t amsgid, ipcarg_t *retval)
    801869{
    802870        amsg_t *msg = (amsg_t *) amsgid;
    803 
     871       
    804872        futex_down(&async_futex);
    805873        if (msg->done) {
     
    807875                goto done;
    808876        }
    809 
     877       
    810878        msg->wdata.fid = fibril_get_id();
    811         msg->wdata.active = 0;
    812         msg->wdata.inlist = 0;
     879        msg->wdata.active = false;
     880        msg->wdata.inlist = false;
     881       
    813882        /* Leave the async_futex locked when entering this function */
    814883        fibril_switch(FIBRIL_TO_MANAGER);
    815         /* futex is up automatically after fibril_switch...*/
     884       
     885        /* Futex is up automatically after fibril_switch */
     886       
    816887done:
    817888        if (retval)
    818889                *retval = msg->retval;
     890       
    819891        free(msg);
    820892}
     
    822894/** Wait for a message sent by the async framework, timeout variant.
    823895 *
    824  * @param amsgid        Hash of the message to wait for.
    825  * @param retval        Pointer to storage where the retval of the answer will
    826  *                      be stored.
    827  * @param timeout       Timeout in microseconds.
    828  *
    829  * @return              Zero on success, ETIMEOUT if the timeout has expired.
     896 * @param amsgid  Hash of the message to wait for.
     897 * @param retval  Pointer to storage where the retval of the answer will
     898 *                be stored.
     899 * @param timeout Timeout in microseconds.
     900 *
     901 * @return Zero on success, ETIMEOUT if the timeout has expired.
     902 *
    830903 */
    831904int async_wait_timeout(aid_t amsgid, ipcarg_t *retval, suseconds_t timeout)
    832905{
    833906        amsg_t *msg = (amsg_t *) amsgid;
    834 
     907       
    835908        /* TODO: Let it go through the event read at least once */
    836909        if (timeout < 0)
    837910                return ETIMEOUT;
    838 
     911       
    839912        futex_down(&async_futex);
    840913        if (msg->done) {
     
    842915                goto done;
    843916        }
    844 
     917       
    845918        gettimeofday(&msg->wdata.expires, NULL);
    846919        tv_add(&msg->wdata.expires, timeout);
    847 
     920       
    848921        msg->wdata.fid = fibril_get_id();
    849         msg->wdata.active = 0;
     922        msg->wdata.active = false;
    850923        insert_timeout(&msg->wdata);
    851 
     924       
    852925        /* Leave the async_futex locked when entering this function */
    853926        fibril_switch(FIBRIL_TO_MANAGER);
    854         /* futex is up automatically after fibril_switch...*/
    855 
     927       
     928        /* Futex is up automatically after fibril_switch */
     929       
    856930        if (!msg->done)
    857931                return ETIMEOUT;
    858 
     932       
    859933done:
    860934        if (retval)
    861935                *retval = msg->retval;
     936       
    862937        free(msg);
    863 
     938       
    864939        return 0;
    865940}
     
    869944 * The current fibril is suspended but the thread continues to execute.
    870945 *
    871  * @param timeout       Duration of the wait in microseconds.
     946 * @param timeout Duration of the wait in microseconds.
     947 *
    872948 */
    873949void async_usleep(suseconds_t timeout)
    874950{
    875         amsg_t *msg;
    876        
    877         msg = malloc(sizeof(*msg));
     951        amsg_t *msg = malloc(sizeof(*msg));
     952       
    878953        if (!msg)
    879954                return;
    880955       
    881956        msg->wdata.fid = fibril_get_id();
    882         msg->wdata.active = 0;
     957        msg->wdata.active = false;
    883958       
    884959        gettimeofday(&msg->wdata.expires, NULL);
     
    886961       
    887962        futex_down(&async_futex);
     963       
    888964        insert_timeout(&msg->wdata);
     965       
    889966        /* Leave the async_futex locked when entering this function */
    890967        fibril_switch(FIBRIL_TO_MANAGER);
    891         /* futex is up automatically after fibril_switch()...*/
     968       
     969        /* Futex is up automatically after fibril_switch() */
     970       
    892971        free(msg);
    893972}
     
    895974/** Setter for client_connection function pointer.
    896975 *
    897  * @param conn          Function that will implement a new connection fibril.
     976 * @param conn Function that will implement a new connection fibril.
     977 *
    898978 */
    899979void async_set_client_connection(async_client_conn_t conn)
     
    904984/** Setter for interrupt_received function pointer.
    905985 *
    906  * @param conn          Function that will implement a new interrupt
    907  *                      notification fibril.
    908  */
    909 void async_set_interrupt_received(async_client_conn_t conn)
    910 {
    911         interrupt_received = conn;
     986 * @param intr Function that will implement a new interrupt
     987 *             notification fibril.
     988 */
     989void async_set_interrupt_received(async_client_conn_t intr)
     990{
     991        interrupt_received = intr;
    912992}
    913993
     
    919999 * transferring more arguments, see the slower async_req_slow().
    9201000 *
    921  * @param phoneid       Hash of the phone through which to make the call.
    922  * @param method        Method of the call.
    923  * @param arg1          Service-defined payload argument.
    924  * @param arg2          Service-defined payload argument.
    925  * @param arg3          Service-defined payload argument.
    926  * @param arg4          Service-defined payload argument.
    927  * @param r1            If non-NULL, storage for the 1st reply argument.
    928  * @param r2            If non-NULL, storage for the 2nd reply argument.
    929  * @param r3            If non-NULL, storage for the 3rd reply argument.
    930  * @param r4            If non-NULL, storage for the 4th reply argument.
    931  * @param r5            If non-NULL, storage for the 5th reply argument.
    932  * @return              Return code of the reply or a negative error code.
     1001 * @param phoneid Hash of the phone through which to make the call.
     1002 * @param method  Method of the call.
     1003 * @param arg1    Service-defined payload argument.
     1004 * @param arg2    Service-defined payload argument.
     1005 * @param arg3    Service-defined payload argument.
     1006 * @param arg4    Service-defined payload argument.
     1007 * @param r1      If non-NULL, storage for the 1st reply argument.
     1008 * @param r2      If non-NULL, storage for the 2nd reply argument.
     1009 * @param r3      If non-NULL, storage for the 3rd reply argument.
     1010 * @param r4      If non-NULL, storage for the 4th reply argument.
     1011 * @param r5      If non-NULL, storage for the 5th reply argument.
     1012 *
     1013 * @return Return code of the reply or a negative error code.
     1014 *
    9331015 */
    9341016ipcarg_t async_req_fast(int phoneid, ipcarg_t method, ipcarg_t arg1,
     
    9371019{
    9381020        ipc_call_t result;
    939         ipcarg_t rc;
    940 
    9411021        aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
    9421022            &result);
     1023       
     1024        ipcarg_t rc;
    9431025        async_wait_for(eid, &rc);
    944         if (r1)
     1026       
     1027        if (r1)
    9451028                *r1 = IPC_GET_ARG1(result);
     1029       
    9461030        if (r2)
    9471031                *r2 = IPC_GET_ARG2(result);
     1032       
    9481033        if (r3)
    9491034                *r3 = IPC_GET_ARG3(result);
     1035       
    9501036        if (r4)
    9511037                *r4 = IPC_GET_ARG4(result);
     1038       
    9521039        if (r5)
    9531040                *r5 = IPC_GET_ARG5(result);
     1041       
    9541042        return rc;
    9551043}
     
    9591047 * Send message asynchronously and return only after the reply arrives.
    9601048 *
    961  * @param phoneid       Hash of the phone through which to make the call.
    962  * @param method        Method of the call.
    963  * @param arg1          Service-defined payload argument.
    964  * @param arg2          Service-defined payload argument.
    965  * @param arg3          Service-defined payload argument.
    966  * @param arg4          Service-defined payload argument.
    967  * @param arg5          Service-defined payload argument.
    968  * @param r1            If non-NULL, storage for the 1st reply argument.
    969  * @param r2            If non-NULL, storage for the 2nd reply argument.
    970  * @param r3            If non-NULL, storage for the 3rd reply argument.
    971  * @param r4            If non-NULL, storage for the 4th reply argument.
    972  * @param r5            If non-NULL, storage for the 5th reply argument.
    973  * @return              Return code of the reply or a negative error code.
     1049 * @param phoneid Hash of the phone through which to make the call.
     1050 * @param method  Method of the call.
     1051 * @param arg1    Service-defined payload argument.
     1052 * @param arg2    Service-defined payload argument.
     1053 * @param arg3    Service-defined payload argument.
     1054 * @param arg4    Service-defined payload argument.
     1055 * @param arg5    Service-defined payload argument.
     1056 * @param r1      If non-NULL, storage for the 1st reply argument.
     1057 * @param r2      If non-NULL, storage for the 2nd reply argument.
     1058 * @param r3      If non-NULL, storage for the 3rd reply argument.
     1059 * @param r4      If non-NULL, storage for the 4th reply argument.
     1060 * @param r5      If non-NULL, storage for the 5th reply argument.
     1061 *
     1062 * @return Return code of the reply or a negative error code.
     1063 *
    9741064 */
    9751065ipcarg_t async_req_slow(int phoneid, ipcarg_t method, ipcarg_t arg1,
     
    9781068{
    9791069        ipc_call_t result;
    980         ipcarg_t rc;
    981 
    9821070        aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
    9831071            &result);
     1072       
     1073        ipcarg_t rc;
    9841074        async_wait_for(eid, &rc);
    985         if (r1)
     1075       
     1076        if (r1)
    9861077                *r1 = IPC_GET_ARG1(result);
     1078       
    9871079        if (r2)
    9881080                *r2 = IPC_GET_ARG2(result);
     1081       
    9891082        if (r3)
    9901083                *r3 = IPC_GET_ARG3(result);
     1084       
    9911085        if (r4)
    9921086                *r4 = IPC_GET_ARG4(result);
     1087       
    9931088        if (r5)
    9941089                *r5 = IPC_GET_ARG5(result);
     1090       
    9951091        return rc;
    9961092}
  • uspace/lib/libc/include/async.h

    r422fd81 rc07544d3  
    9999/* Wrappers for simple communication */
    100100#define async_msg_0(phone, method) \
    101     ipc_call_async_0((phone), (method), NULL, NULL, !in_interrupt_handler())
     101    ipc_call_async_0((phone), (method), NULL, NULL, true)
    102102#define async_msg_1(phone, method, arg1) \
    103103    ipc_call_async_1((phone), (method), (arg1), NULL, NULL, \
    104         !in_interrupt_handler())
     104        true)
    105105#define async_msg_2(phone, method, arg1, arg2) \
    106106    ipc_call_async_2((phone), (method), (arg1), (arg2), NULL, NULL, \
    107         !in_interrupt_handler())
     107        true)
    108108#define async_msg_3(phone, method, arg1, arg2, arg3) \
    109109    ipc_call_async_3((phone), (method), (arg1), (arg2), (arg3), NULL, NULL, \
    110         !in_interrupt_handler())
     110        true)
    111111#define async_msg_4(phone, method, arg1, arg2, arg3, arg4) \
    112112    ipc_call_async_4((phone), (method), (arg1), (arg2), (arg3), (arg4), NULL, \
    113         NULL, !in_interrupt_handler())
     113        NULL, true)
    114114#define async_msg_5(phone, method, arg1, arg2, arg3, arg4, arg5) \
    115115    ipc_call_async_5((phone), (method), (arg1), (arg2), (arg3), (arg4), \
    116         (arg5), NULL, NULL, !in_interrupt_handler())
     116        (arg5), NULL, NULL, true)
    117117
    118118/*
     
    254254}
    255255
    256 extern bool in_interrupt_handler(void);
    257 
    258256extern atomic_t async_futex;
    259257
Note: See TracChangeset for help on using the changeset viewer.