Ignore:
File:
1 edited

Legend:

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

    r8820544 r927a181e  
    101101#undef LIBC_ASYNC_C_
    102102
    103 #include <ipc/irq.h>
    104 #include <ipc/event.h>
    105103#include <futex.h>
    106104#include <fibril.h>
     
    111109#include <sys/time.h>
    112110#include <libarch/barrier.h>
    113 #include <stdbool.h>
     111#include <bool.h>
    114112#include <malloc.h>
    115113#include <mem.h>
     
    118116#include "private/libc.h"
    119117
     118
    120119/** Session data */
    121120struct async_sess {
     
    167166
    168167/** Async framework global futex */
    169 atomic_t async_futex = FUTEX_INITIALIZER;
     168futex_t async_futex = FUTEX_INITIALIZER;
    170169
    171170/** Number of threads waiting for IPC in the kernel. */
     
    243242        async_client_conn_t cfibril;
    244243} connection_t;
    245 
    246 /* Notification data */
    247 typedef struct {
    248         ht_link_t link;
    249        
    250         /** Notification method */
    251         sysarg_t imethod;
    252        
    253         /** Notification handler */
    254         async_notification_handler_t handler;
    255        
    256         /** Notification data */
    257         void *data;
    258 } notification_t;
    259244
    260245/** Identifier of the incoming connection handled by the current fibril. */
     
    350335}
    351336
     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
    352350static async_client_conn_t client_connection = default_client_connection;
    353 static size_t notification_handler_stksz = FIBRIL_DFLT_STK_SIZE;
     351static async_interrupt_handler_t interrupt_received = default_interrupt_received;
    354352
    355353/** Setter for client_connection function pointer.
     
    364362}
    365363
    366 /** Set the stack size for the notification handler notification fibrils.
    367  *
    368  * @param size Stack size in bytes.
    369  */
    370 void async_set_notification_handler_stack_size(size_t size)
    371 {
    372         notification_handler_stksz = size;
     364/** Setter for interrupt_received function pointer.
     365 *
     366 * @param intr Function that will implement a new interrupt
     367 *             notification fibril.
     368 */
     369void async_set_interrupt_received(async_interrupt_handler_t intr)
     370{
     371        interrupt_received = intr;
    373372}
    374373
     
    390389static hash_table_t client_hash_table;
    391390static hash_table_t conn_hash_table;
    392 static hash_table_t notification_hash_table;
    393391static LIST_INITIALIZE(timeout_list);
    394392
    395 static sysarg_t notification_avail = 0;
    396 
    397 static size_t client_key_hash(void *key)
    398 {
    399         task_id_t in_task_id = *(task_id_t *) key;
    400         return in_task_id;
     393static size_t client_key_hash(void *k)
     394{
     395        task_id_t key = *(task_id_t*)k;
     396        return key;
    401397}
    402398
     
    407403}
    408404
    409 static bool client_key_equal(void *key, const ht_link_t *item)
    410 {
    411         task_id_t in_task_id = *(task_id_t *) key;
     405static bool client_key_equal(void *k, const ht_link_t *item)
     406{
     407        task_id_t key = *(task_id_t*)k;
    412408        client_t *client = hash_table_get_inst(item, client_t, link);
    413         return in_task_id == client->in_task_id;
    414 }
     409        return key == client->in_task_id;
     410}
     411
    415412
    416413/** Operations for the client hash table. */
     
    432429static size_t conn_key_hash(void *key)
    433430{
    434         sysarg_t in_phone_hash = *(sysarg_t *) key;
    435         return in_phone_hash;
     431        sysarg_t in_phone_hash  = *(sysarg_t*)key;
     432        return in_phone_hash ;
    436433}
    437434
     
    444441static bool conn_key_equal(void *key, const ht_link_t *item)
    445442{
    446         sysarg_t in_phone_hash = *(sysarg_t *) key;
     443        sysarg_t in_phone_hash = *(sysarg_t*)key;
    447444        connection_t *conn = hash_table_get_inst(item, connection_t, link);
    448445        return (in_phone_hash == conn->in_phone_hash);
    449446}
     447
    450448
    451449/** Operations for the connection hash table. */
     
    458456};
    459457
    460 static size_t notification_key_hash(void *key)
    461 {
    462         sysarg_t id = *(sysarg_t *) key;
    463         return id;
    464 }
    465 
    466 static size_t notification_hash(const ht_link_t *item)
    467 {
    468         notification_t *notification =
    469             hash_table_get_inst(item, notification_t, link);
    470         return notification_key_hash(&notification->imethod);
    471 }
    472 
    473 static bool notification_key_equal(void *key, const ht_link_t *item)
    474 {
    475         sysarg_t id = *(sysarg_t *) key;
    476         notification_t *notification =
    477             hash_table_get_inst(item, notification_t, link);
    478         return id == notification->imethod;
    479 }
    480 
    481 /** Operations for the notification hash table. */
    482 static hash_table_ops_t notification_hash_table_ops = {
    483         .hash = notification_hash,
    484         .key_hash = notification_key_hash,
    485         .key_equal = notification_key_equal,
    486         .equal = NULL,
    487         .remove_callback = NULL
    488 };
    489 
    490458/** Sort in current fibril's timeout request.
    491459 *
     
    533501        futex_down(&async_futex);
    534502       
    535         ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash);
    536         if (!link) {
     503        ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash);
     504       
     505        if (!hlp) {
    537506                futex_up(&async_futex);
    538507                return false;
    539508        }
    540509       
    541         connection_t *conn = hash_table_get_inst(link, connection_t, link);
     510        connection_t *conn = hash_table_get_inst(hlp, connection_t, link);
    542511       
    543512        msg_t *msg = malloc(sizeof(*msg));
     
    574543 *
    575544 * When a notification arrives, a fibril with this implementing function is
    576  * created. It calls the corresponding notification handler and does the final
    577  * cleanup.
     545 * created. It calls interrupt_received() and does the final cleanup.
    578546 *
    579547 * @param arg Message structure pointer.
     
    587555       
    588556        msg_t *msg = (msg_t *) arg;
    589         async_notification_handler_t handler = NULL;
    590         void *data = NULL;
    591        
    592         futex_down(&async_futex);
    593        
    594         ht_link_t *link = hash_table_find(&notification_hash_table,
    595             &IPC_GET_IMETHOD(msg->call));
    596         if (link) {
    597                 notification_t *notification =
    598                     hash_table_get_inst(link, notification_t, link);
    599                 handler = notification->handler;
    600                 data = notification->data;
    601         }
    602        
    603         futex_up(&async_futex);
    604        
    605         if (handler)
    606                 handler(msg->callid, &msg->call, data);
     557        interrupt_received(msg->callid, &msg->call);
    607558       
    608559        free(msg);
     
    610561}
    611562
    612 /** Process notification.
     563/** Process interrupt notification.
    613564 *
    614565 * A new fibril is created which would process the notification.
     
    636587        msg->call = *call;
    637588       
    638         fid_t fid = fibril_create_generic(notification_fibril, msg,
    639             notification_handler_stksz);
     589        fid_t fid = fibril_create(notification_fibril, msg);
    640590        if (fid == 0) {
    641591                free(msg);
     
    648598        futex_up(&async_futex);
    649599        return true;
    650 }
    651 
    652 /** Subscribe to IRQ notification.
    653  *
    654  * @param inr     IRQ number.
    655  * @param devno   Device number of the device generating inr.
    656  * @param handler Notification handler.
    657  * @param data    Notification handler client data.
    658  * @param ucode   Top-half pseudocode handler.
    659  *
    660  * @return Zero on success or a negative error code.
    661  *
    662  */
    663 int async_irq_subscribe(int inr, int devno,
    664     async_notification_handler_t handler, void *data, const irq_code_t *ucode)
    665 {
    666         notification_t *notification =
    667             (notification_t *) malloc(sizeof(notification_t));
    668         if (!notification)
    669                 return ENOMEM;
    670        
    671         futex_down(&async_futex);
    672        
    673         sysarg_t imethod = notification_avail;
    674         notification_avail++;
    675        
    676         notification->imethod = imethod;
    677         notification->handler = handler;
    678         notification->data = data;
    679        
    680         hash_table_insert(&notification_hash_table, &notification->link);
    681        
    682         futex_up(&async_futex);
    683        
    684         return ipc_irq_subscribe(inr, devno, imethod, ucode);
    685 }
    686 
    687 /** Unsubscribe from IRQ notification.
    688  *
    689  * @param inr     IRQ number.
    690  * @param devno   Device number of the device generating inr.
    691  *
    692  * @return Zero on success or a negative error code.
    693  *
    694  */
    695 int async_irq_unsubscribe(int inr, int devno)
    696 {
    697         // TODO: Remove entry from hash table
    698         //       to avoid memory leak
    699        
    700         return ipc_irq_unsubscribe(inr, devno);
    701 }
    702 
    703 /** Subscribe to event notifications.
    704  *
    705  * @param evno    Event type to subscribe.
    706  * @param handler Notification handler.
    707  * @param data    Notification handler client data.
    708  *
    709  * @return Zero on success or a negative error code.
    710  *
    711  */
    712 int async_event_subscribe(event_type_t evno,
    713     async_notification_handler_t handler, void *data)
    714 {
    715         notification_t *notification =
    716             (notification_t *) malloc(sizeof(notification_t));
    717         if (!notification)
    718                 return ENOMEM;
    719        
    720         futex_down(&async_futex);
    721        
    722         sysarg_t imethod = notification_avail;
    723         notification_avail++;
    724        
    725         notification->imethod = imethod;
    726         notification->handler = handler;
    727         notification->data = data;
    728        
    729         hash_table_insert(&notification_hash_table, &notification->link);
    730        
    731         futex_up(&async_futex);
    732        
    733         return ipc_event_subscribe(evno, imethod);
    734 }
    735 
    736 /** Subscribe to task event notifications.
    737  *
    738  * @param evno    Event type to subscribe.
    739  * @param handler Notification handler.
    740  * @param data    Notification handler client data.
    741  *
    742  * @return Zero on success or a negative error code.
    743  *
    744  */
    745 int async_event_task_subscribe(event_task_type_t evno,
    746     async_notification_handler_t handler, void *data)
    747 {
    748         notification_t *notification =
    749             (notification_t *) malloc(sizeof(notification_t));
    750         if (!notification)
    751                 return ENOMEM;
    752        
    753         futex_down(&async_futex);
    754        
    755         sysarg_t imethod = notification_avail;
    756         notification_avail++;
    757        
    758         notification->imethod = imethod;
    759         notification->handler = handler;
    760         notification->data = data;
    761        
    762         hash_table_insert(&notification_hash_table, &notification->link);
    763        
    764         futex_up(&async_futex);
    765        
    766         return ipc_event_task_subscribe(evno, imethod);
    767 }
    768 
    769 /** Unmask event notifications.
    770  *
    771  * @param evno Event type to unmask.
    772  *
    773  * @return Value returned by the kernel.
    774  *
    775  */
    776 int async_event_unmask(event_type_t evno)
    777 {
    778         return ipc_event_unmask(evno);
    779 }
    780 
    781 /** Unmask task event notifications.
    782  *
    783  * @param evno Event type to unmask.
    784  *
    785  * @return Value returned by the kernel.
    786  *
    787  */
    788 int async_event_task_unmask(event_task_type_t evno)
    789 {
    790         return ipc_event_task_unmask(evno);
    791600}
    792601
     
    882691
    883692        futex_down(&async_futex);
    884         ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
    885         if (link) {
    886                 client = hash_table_get_inst(link, client_t, link);
     693        ht_link_t *lnk = hash_table_find(&client_hash_table, &client_id);
     694        if (lnk) {
     695                client = hash_table_get_inst(lnk, client_t, link);
    887696                atomic_inc(&client->refcnt);
    888697        } else if (create) {
     
    12861095       
    12871096        if (!hash_table_create(&conn_hash_table, 0, 0, &conn_hash_table_ops))
    1288                 abort();
    1289        
    1290         if (!hash_table_create(&notification_hash_table, 0, 0,
    1291             &notification_hash_table_ops))
    12921097                abort();
    12931098       
     
    22522057       
    22532058        async_sess_t *sess = exch->sess;
    2254         assert(sess != NULL);
    22552059       
    22562060        atomic_dec(&sess->refcnt);
     
    22742078 * @param arg   User defined argument.
    22752079 * @param flags Storage for the received flags. Can be NULL.
    2276  * @param dst   Address of the storage for the destination address space area
    2277  *              base address. Cannot be NULL.
     2080 * @param dst   Destination address space area base. Cannot be NULL.
    22782081 *
    22792082 * @return Zero on success or a negative error code from errno.h.
     
    24032206 *
    24042207 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.
    2405  * @param dst    Address of the storage for the destination address space area
    2406  *               base address.
     2208 * @param dst    Destination address space area base address.
    24072209 *
    24082210 * @return Zero on success or a value from @ref errno.h on failure.
     
    24652267bool async_data_read_receive(ipc_callid_t *callid, size_t *size)
    24662268{
     2269        assert(callid);
     2270       
    24672271        ipc_call_t data;
    2468         return async_data_read_receive_call(callid, &data, size);
    2469 }
    2470 
    2471 /** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework.
    2472  *
    2473  * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ
    2474  * calls so that the user doesn't have to remember the meaning of each IPC
    2475  * argument.
    2476  *
    2477  * So far, this wrapper is to be used from within a connection fibril.
    2478  *
    2479  * @param callid Storage for the hash of the IPC_M_DATA_READ.
    2480  * @param size   Storage for the maximum size. Can be NULL.
    2481  *
    2482  * @return True on success, false on failure.
    2483  *
    2484  */
    2485 bool async_data_read_receive_call(ipc_callid_t *callid, ipc_call_t *data,
    2486     size_t *size)
    2487 {
    2488         assert(callid);
    2489         assert(data);
    2490        
    2491         *callid = async_get_call(data);
    2492        
    2493         if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_READ)
     2272        *callid = async_get_call(&data);
     2273       
     2274        if (IPC_GET_IMETHOD(data) != IPC_M_DATA_READ)
    24942275                return false;
    24952276       
    24962277        if (size)
    2497                 *size = (size_t) IPC_GET_ARG2(*data);
     2278                *size = (size_t) IPC_GET_ARG2(data);
    24982279       
    24992280        return true;
     
    25902371bool async_data_write_receive(ipc_callid_t *callid, size_t *size)
    25912372{
     2373        assert(callid);
     2374       
    25922375        ipc_call_t data;
    2593         return async_data_write_receive_call(callid, &data, size);
    2594 }
    2595 
    2596 /** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework.
    2597  *
    2598  * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE
    2599  * calls so that the user doesn't have to remember the meaning of each IPC
    2600  * argument.
    2601  *
    2602  * So far, this wrapper is to be used from within a connection fibril.
    2603  *
    2604  * @param callid Storage for the hash of the IPC_M_DATA_WRITE.
    2605  * @param data   Storage for the ipc call data.
    2606  * @param size   Storage for the suggested size. May be NULL.
    2607  *
    2608  * @return True on success, false on failure.
    2609  *
    2610  */
    2611 bool async_data_write_receive_call(ipc_callid_t *callid, ipc_call_t *data,
    2612     size_t *size)
    2613 {
    2614         assert(callid);
    2615         assert(data);
    2616        
    2617         *callid = async_get_call(data);
    2618        
    2619         if (IPC_GET_IMETHOD(*data) != IPC_M_DATA_WRITE)
     2376        *callid = async_get_call(&data);
     2377       
     2378        if (IPC_GET_IMETHOD(data) != IPC_M_DATA_WRITE)
    26202379                return false;
    26212380       
    26222381        if (size)
    2623                 *size = (size_t) IPC_GET_ARG2(*data);
     2382                *size = (size_t) IPC_GET_ARG2(data);
    26242383       
    26252384        return true;
Note: See TracChangeset for help on using the changeset viewer.