Changeset 8820544 in mainline for uspace/lib/c/generic/async.c


Ignore:
Timestamp:
2014-08-16T00:02:04Z (10 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
35b8bfe, 8cd680c
Parents:
83f29e0
Message:

support for kernel notification multiplexing in the async framework

  • rename SYS_EVENT_* and SYS_IRQ_* syscalls to unify the terminology
  • add SYS_IPC_EVENT_UNSUBSCRIBE
  • remove IRQ handler multiplexing from DDF, the generic mechanism replaces it (unfortunatelly the order of arguments used by interrupt_handler_t needs to be permutated to align with the async framework conventions)
File:
1 edited

Legend:

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

    r83f29e0 r8820544  
    101101#undef LIBC_ASYNC_C_
    102102
     103#include <ipc/irq.h>
     104#include <ipc/event.h>
    103105#include <futex.h>
    104106#include <fibril.h>
     
    116118#include "private/libc.h"
    117119
    118 
    119120/** Session data */
    120121struct async_sess {
     
    242243        async_client_conn_t cfibril;
    243244} connection_t;
     245
     246/* Notification data */
     247typedef 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;
    244259
    245260/** Identifier of the incoming connection handled by the current fibril. */
     
    335350}
    336351
    337 /** Default fibril function that gets called to handle interrupt notifications.
    338  *
    339  * This function is defined as a weak symbol - to be redefined in user code.
    340  *
    341  * @param callid Hash of the incoming call.
    342  * @param call   Data of the incoming call.
    343  * @param arg    Local argument.
    344  *
    345  */
    346 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    347 {
    348 }
    349 
    350352static async_client_conn_t client_connection = default_client_connection;
    351 static async_interrupt_handler_t interrupt_received = default_interrupt_received;
    352 static size_t interrupt_handler_stksz = FIBRIL_DFLT_STK_SIZE;
     353static size_t notification_handler_stksz = FIBRIL_DFLT_STK_SIZE;
    353354
    354355/** Setter for client_connection function pointer.
     
    363364}
    364365
    365 /** Setter for interrupt_received function pointer.
    366  *
    367  * @param intr Function that will implement a new interrupt
    368  *             notification fibril.
    369  */
    370 void async_set_interrupt_received(async_interrupt_handler_t intr)
    371 {
    372         interrupt_received = intr;
    373 }
    374 
    375 /** Set the stack size for the interrupt handler notification fibrils.
     366/** Set the stack size for the notification handler notification fibrils.
    376367 *
    377368 * @param size Stack size in bytes.
    378369 */
    379 void async_set_interrupt_handler_stack_size(size_t size)
    380 {
    381         interrupt_handler_stksz = size;
     370void async_set_notification_handler_stack_size(size_t size)
     371{
     372        notification_handler_stksz = size;
    382373}
    383374
     
    399390static hash_table_t client_hash_table;
    400391static hash_table_t conn_hash_table;
     392static hash_table_t notification_hash_table;
    401393static LIST_INITIALIZE(timeout_list);
    402394
    403 static size_t client_key_hash(void *k)
    404 {
    405         task_id_t key = *(task_id_t*)k;
    406         return key;
     395static sysarg_t notification_avail = 0;
     396
     397static size_t client_key_hash(void *key)
     398{
     399        task_id_t in_task_id = *(task_id_t *) key;
     400        return in_task_id;
    407401}
    408402
     
    413407}
    414408
    415 static bool client_key_equal(void *k, const ht_link_t *item)
    416 {
    417         task_id_t key = *(task_id_t*)k;
     409static bool client_key_equal(void *key, const ht_link_t *item)
     410{
     411        task_id_t in_task_id = *(task_id_t *) key;
    418412        client_t *client = hash_table_get_inst(item, client_t, link);
    419         return key == client->in_task_id;
    420 }
    421 
     413        return in_task_id == client->in_task_id;
     414}
    422415
    423416/** Operations for the client hash table. */
     
    439432static size_t conn_key_hash(void *key)
    440433{
    441         sysarg_t in_phone_hash  = *(sysarg_t*)key;
    442         return in_phone_hash ;
     434        sysarg_t in_phone_hash = *(sysarg_t *) key;
     435        return in_phone_hash;
    443436}
    444437
     
    451444static bool conn_key_equal(void *key, const ht_link_t *item)
    452445{
    453         sysarg_t in_phone_hash = *(sysarg_t*)key;
     446        sysarg_t in_phone_hash = *(sysarg_t *) key;
    454447        connection_t *conn = hash_table_get_inst(item, connection_t, link);
    455448        return (in_phone_hash == conn->in_phone_hash);
    456449}
    457 
    458450
    459451/** Operations for the connection hash table. */
     
    462454        .key_hash = conn_key_hash,
    463455        .key_equal = conn_key_equal,
     456        .equal = NULL,
     457        .remove_callback = NULL
     458};
     459
     460static size_t notification_key_hash(void *key)
     461{
     462        sysarg_t id = *(sysarg_t *) key;
     463        return id;
     464}
     465
     466static 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
     473static 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. */
     482static hash_table_ops_t notification_hash_table_ops = {
     483        .hash = notification_hash,
     484        .key_hash = notification_key_hash,
     485        .key_equal = notification_key_equal,
    464486        .equal = NULL,
    465487        .remove_callback = NULL
     
    511533        futex_down(&async_futex);
    512534       
    513         ht_link_t *hlp = hash_table_find(&conn_hash_table, &call->in_phone_hash);
    514        
    515         if (!hlp) {
     535        ht_link_t *link = hash_table_find(&conn_hash_table, &call->in_phone_hash);
     536        if (!link) {
    516537                futex_up(&async_futex);
    517538                return false;
    518539        }
    519540       
    520         connection_t *conn = hash_table_get_inst(hlp, connection_t, link);
     541        connection_t *conn = hash_table_get_inst(link, connection_t, link);
    521542       
    522543        msg_t *msg = malloc(sizeof(*msg));
     
    553574 *
    554575 * When a notification arrives, a fibril with this implementing function is
    555  * created. It calls interrupt_received() and does the final cleanup.
     576 * created. It calls the corresponding notification handler and does the final
     577 * cleanup.
    556578 *
    557579 * @param arg Message structure pointer.
     
    565587       
    566588        msg_t *msg = (msg_t *) arg;
    567         interrupt_received(msg->callid, &msg->call);
     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);
    568607       
    569608        free(msg);
     
    571610}
    572611
    573 /** Process interrupt notification.
     612/** Process notification.
    574613 *
    575614 * A new fibril is created which would process the notification.
     
    598637       
    599638        fid_t fid = fibril_create_generic(notification_fibril, msg,
    600             interrupt_handler_stksz);
     639            notification_handler_stksz);
    601640        if (fid == 0) {
    602641                free(msg);
     
    609648        futex_up(&async_futex);
    610649        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 */
     663int 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 */
     695int 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 */
     712int 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 */
     745int 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 */
     776int 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 */
     788int async_event_task_unmask(event_task_type_t evno)
     789{
     790        return ipc_event_task_unmask(evno);
    611791}
    612792
     
    702882
    703883        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);
     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);
    707887                atomic_inc(&client->refcnt);
    708888        } else if (create) {
     
    11061286       
    11071287        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))
    11081292                abort();
    11091293       
Note: See TracChangeset for help on using the changeset viewer.