Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ipc/event.c

    r228e490 r0fe52ef  
    3636
    3737#include <ipc/event.h>
    38 #include <ipc/event_types.h>
    3938#include <mm/slab.h>
    4039#include <typedefs.h>
    4140#include <synch/spinlock.h>
    4241#include <console/console.h>
     42#include <proc/task.h>
    4343#include <memstr.h>
    4444#include <errno.h>
     
    4848static event_t events[EVENT_END];
    4949
    50 /** Initialize kernel events. */
     50static void event_initialize(event_t *event)
     51{
     52        spinlock_initialize(&event->lock, "event.lock");
     53        event->answerbox = NULL;
     54        event->counter = 0;
     55        event->imethod = 0;
     56        event->masked = false;
     57        event->unmask_callback = NULL;
     58}
     59
     60static event_t *evno2event(int evno, task_t *t)
     61{
     62        ASSERT(evno < EVENT_TASK_END);
     63
     64        event_t *event;
     65
     66        if (evno < EVENT_END)
     67                event = &events[(event_type_t) evno];
     68        else
     69                event = &t->events[(event_task_type_t) evno - EVENT_END];
     70
     71        return event;
     72}
     73
     74/** Initialize kernel events.
     75 *
     76 */
    5177void event_init(void)
    5278{
    53         unsigned int i;
    54        
    55         for (i = 0; i < EVENT_END; i++) {
    56                 spinlock_initialize(&events[i].lock, "event.lock");
    57                 events[i].answerbox = NULL;
    58                 events[i].counter = 0;
    59                 events[i].imethod = 0;
    60         }
    61 }
    62 
    63 static int event_subscribe(event_type_t evno, sysarg_t imethod,
    64     answerbox_t *answerbox)
    65 {
    66         if (evno >= EVENT_END)
    67                 return ELIMIT;
    68        
    69         spinlock_lock(&events[evno].lock);
    70        
    71         int res;
    72        
    73         if (events[evno].answerbox == NULL) {
    74                 events[evno].answerbox = answerbox;
    75                 events[evno].imethod = imethod;
    76                 events[evno].counter = 0;
    77                 res = EOK;
    78         } else
    79                 res = EEXISTS;
    80        
    81         spinlock_unlock(&events[evno].lock);
    82        
    83         return res;
    84 }
    85 
    86 sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod)
    87 {
    88         return (sysarg_t) event_subscribe((event_type_t) evno, (sysarg_t)
    89             imethod, &TASK->answerbox);
    90 }
    91 
    92 bool event_is_subscribed(event_type_t evno)
    93 {
    94         bool res;
    95        
    96         ASSERT(evno < EVENT_END);
    97        
    98         spinlock_lock(&events[evno].lock);
    99         res = events[evno].answerbox != NULL;
    100         spinlock_unlock(&events[evno].lock);
    101        
    102         return res;
    103 }
    104 
    105 
     79        for (unsigned int i = 0; i < EVENT_END; i++)
     80                event_initialize(evno2event(i, NULL));
     81}
     82
     83void event_task_init(task_t *task)
     84{
     85        for (unsigned int i = EVENT_END; i < EVENT_TASK_END; i++)
     86                event_initialize(evno2event(i, task));
     87}
     88
     89
     90/** Unsubscribe kernel events associated with an answerbox
     91 *
     92 * @param answerbox Answerbox to be unsubscribed.
     93 *
     94 */
    10695void event_cleanup_answerbox(answerbox_t *answerbox)
    10796{
    108         unsigned int i;
    109        
    110         for (i = 0; i < EVENT_END; i++) {
     97        for (unsigned int i = 0; i < EVENT_END; i++) {
    11198                spinlock_lock(&events[i].lock);
     99               
    112100                if (events[i].answerbox == answerbox) {
    113101                        events[i].answerbox = NULL;
    114102                        events[i].counter = 0;
    115103                        events[i].imethod = 0;
     104                        events[i].masked = false;
    116105                }
     106               
    117107                spinlock_unlock(&events[i].lock);
    118108        }
    119109}
    120110
    121 void event_notify(event_type_t evno, sysarg_t a1, sysarg_t a2, sysarg_t a3,
    122     sysarg_t a4, sysarg_t a5)
     111static void _event_set_unmask_callback(event_t *event, event_callback_t callback)
     112{
     113        spinlock_lock(&event->lock);
     114        event->unmask_callback = callback;
     115        spinlock_unlock(&event->lock);
     116}
     117
     118/** Define a callback function for the event unmask event.
     119 *
     120 * @param evno     Event type.
     121 * @param callback Callback function to be called when
     122 *                 the event is unmasked.
     123 *
     124 */
     125void event_set_unmask_callback(event_type_t evno, event_callback_t callback)
    123126{
    124127        ASSERT(evno < EVENT_END);
    125128       
    126         spinlock_lock(&events[evno].lock);
    127         if (events[evno].answerbox != NULL) {
    128                 call_t *call = ipc_call_alloc(FRAME_ATOMIC);
    129                 if (call) {
    130                         call->flags |= IPC_CALL_NOTIF;
    131                         call->priv = ++events[evno].counter;
    132                         IPC_SET_IMETHOD(call->data, events[evno].imethod);
    133                         IPC_SET_ARG1(call->data, a1);
    134                         IPC_SET_ARG2(call->data, a2);
    135                         IPC_SET_ARG3(call->data, a3);
    136                         IPC_SET_ARG4(call->data, a4);
    137                         IPC_SET_ARG5(call->data, a5);
     129        _event_set_unmask_callback(evno2event(evno, NULL), callback);
     130}
     131
     132void event_task_set_unmask_callback(task_t *task, event_task_type_t evno,
     133    event_callback_t callback)
     134{
     135        ASSERT(evno >= (int) EVENT_END);
     136        ASSERT(evno < EVENT_TASK_END);
     137               
     138        _event_set_unmask_callback(evno2event(evno, task), callback);
     139}
     140
     141static int event_enqueue(event_t *event, bool mask, sysarg_t a1, sysarg_t a2,
     142    sysarg_t a3, sysarg_t a4, sysarg_t a5)
     143{
     144        int res;
     145
     146        spinlock_lock(&event->lock);
     147       
     148        if (event->answerbox != NULL) {
     149                if (!event->masked) {
     150                        call_t *call = ipc_call_alloc(FRAME_ATOMIC);
    138151                       
    139                         irq_spinlock_lock(&events[evno].answerbox->irq_lock, true);
    140                         list_append(&call->link, &events[evno].answerbox->irq_notifs);
    141                         irq_spinlock_unlock(&events[evno].answerbox->irq_lock, true);
    142                        
    143                         waitq_wakeup(&events[evno].answerbox->wq, WAKEUP_FIRST);
    144                 }
    145         }
    146         spinlock_unlock(&events[evno].lock);
     152                        if (call) {
     153                                call->flags |= IPC_CALL_NOTIF;
     154                                call->priv = ++event->counter;
     155                               
     156                                IPC_SET_IMETHOD(call->data, event->imethod);
     157                                IPC_SET_ARG1(call->data, a1);
     158                                IPC_SET_ARG2(call->data, a2);
     159                                IPC_SET_ARG3(call->data, a3);
     160                                IPC_SET_ARG4(call->data, a4);
     161                                IPC_SET_ARG5(call->data, a5);
     162                               
     163                                call->data.task_id = TASK ? TASK->taskid : 0;
     164                               
     165                                irq_spinlock_lock(&event->answerbox->irq_lock, true);
     166                                list_append(&call->link, &event->answerbox->irq_notifs);
     167                                irq_spinlock_unlock(&event->answerbox->irq_lock, true);
     168                               
     169                                waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST);
     170                               
     171                                if (mask)
     172                                        event->masked = true;
     173                               
     174                                res = EOK;
     175                        } else
     176                                res = ENOMEM;
     177                } else
     178                        res = EBUSY;
     179        } else
     180                res = ENOENT;
     181       
     182        spinlock_unlock(&event->lock);
     183        return res;
     184}
     185
     186/** Send kernel notification event
     187 *
     188 * @param evno Event type.
     189 * @param mask Mask further notifications after a successful
     190 *             sending.
     191 * @param a1   First argument.
     192 * @param a2   Second argument.
     193 * @param a3   Third argument.
     194 * @param a4   Fourth argument.
     195 * @param a5   Fifth argument.
     196 *
     197 * @return EOK if notification was successfully sent.
     198 * @return ENOMEM if the notification IPC message failed to allocate.
     199 * @return EBUSY if the notifications of the given type are
     200 *         currently masked.
     201 * @return ENOENT if the notifications of the given type are
     202 *         currently not subscribed.
     203 *
     204 */
     205int event_notify(event_type_t evno, bool mask, sysarg_t a1, sysarg_t a2,
     206    sysarg_t a3, sysarg_t a4, sysarg_t a5)
     207{
     208        ASSERT(evno < EVENT_END);
     209       
     210        return event_enqueue(evno2event(evno, NULL), mask, a1, a2, a3, a4, a5);
     211}
     212
     213/** Send per-task kernel notification event
     214 *
     215 * @param task Destination task.
     216 * @param evno Event type.
     217 * @param mask Mask further notifications after a successful
     218 *             sending.
     219 * @param a1   First argument.
     220 * @param a2   Second argument.
     221 * @param a3   Third argument.
     222 * @param a4   Fourth argument.
     223 * @param a5   Fifth argument.
     224 *
     225 * @return EOK if notification was successfully sent.
     226 * @return ENOMEM if the notification IPC message failed to allocate.
     227 * @return EBUSY if the notifications of the given type are
     228 *         currently masked.
     229 * @return ENOENT if the notifications of the given type are
     230 *         currently not subscribed.
     231 *
     232 */
     233int event_task_notify(task_t *task, event_task_type_t evno, bool mask,
     234    sysarg_t a1, sysarg_t a2, sysarg_t a3, sysarg_t a4, sysarg_t a5)
     235{
     236        ASSERT(evno >= (int) EVENT_END);
     237        ASSERT(evno < EVENT_TASK_END);
     238       
     239        return event_enqueue(evno2event(evno, task), mask, a1, a2, a3, a4, a5);
     240}
     241
     242/** Subscribe event notifications
     243 *
     244 * @param evno      Event type.
     245 * @param imethod   IPC interface and method to be used for
     246 *                  the notifications.
     247 * @param answerbox Answerbox to send the notifications to.
     248 *
     249 * @return EOK if the subscription was successful.
     250 * @return EEXISTS if the notifications of the given type are
     251 *         already subscribed.
     252 *
     253 */
     254static int event_subscribe(event_t *event, sysarg_t imethod,
     255    answerbox_t *answerbox)
     256{
     257        int res;
     258
     259        spinlock_lock(&event->lock);
     260       
     261        if (event->answerbox == NULL) {
     262                event->answerbox = answerbox;
     263                event->imethod = imethod;
     264                event->counter = 0;
     265                event->masked = false;
     266                res = EOK;
     267        } else
     268                res = EEXISTS;
     269       
     270        spinlock_unlock(&event->lock);
     271       
     272        return res;
     273}
     274
     275/** Unmask event notifications
     276 *
     277 * @param evno Event type to unmask.
     278 *
     279 */
     280static void event_unmask(event_t *event)
     281{
     282        spinlock_lock(&event->lock);
     283        event->masked = false;
     284        event_callback_t callback = event->unmask_callback;
     285        spinlock_unlock(&event->lock);
     286       
     287        /*
     288         * Check if there is an unmask callback
     289         * function defined for this event.
     290         */
     291        if (callback != NULL)
     292                callback(event);
     293}
     294
     295/** Event notification syscall wrapper
     296 *
     297 * @param evno    Event type to subscribe.
     298 * @param imethod IPC interface and method to be used for
     299 *                the notifications.
     300 *
     301 * @return EOK on success.
     302 * @return ELIMIT on unknown event type.
     303 * @return EEXISTS if the notifications of the given type are
     304 *         already subscribed.
     305 *
     306 */
     307sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod)
     308{
     309        if (evno >= EVENT_TASK_END)
     310                return ELIMIT;
     311       
     312        return (sysarg_t) event_subscribe(evno2event(evno, TASK),
     313            (sysarg_t) imethod, &TASK->answerbox);
     314}
     315
     316/** Event notification unmask syscall wrapper
     317 *
     318 * Note that currently no tests are performed whether the calling
     319 * task is entitled to unmask the notifications. However, thanks
     320 * to the fact that notification masking is only a performance
     321 * optimization, this has probably no security implications.
     322 *
     323 * @param evno Event type to unmask.
     324 *
     325 * @return EOK on success.
     326 * @return ELIMIT on unknown event type.
     327 *
     328 */
     329sysarg_t sys_event_unmask(sysarg_t evno)
     330{
     331        if (evno >= EVENT_TASK_END)
     332                return ELIMIT;
     333       
     334        event_unmask(evno2event(evno, TASK));
     335
     336        return EOK;
    147337}
    148338
Note: See TracChangeset for help on using the changeset viewer.