Ignore:
File:
1 edited

Legend:

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

    r0fe52ef r228e490  
    3636
    3737#include <ipc/event.h>
     38#include <ipc/event_types.h>
    3839#include <mm/slab.h>
    3940#include <typedefs.h>
    4041#include <synch/spinlock.h>
    4142#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 static void event_initialize(event_t *event)
     50/** Initialize kernel events. */
     51void event_init(void)
    5152{
    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;
     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        }
    5861}
    5962
    60 static event_t *evno2event(int evno, task_t *t)
     63static int event_subscribe(event_type_t evno, sysarg_t imethod,
     64    answerbox_t *answerbox)
    6165{
    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;
     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;
    7284}
    7385
    74 /** Initialize kernel events.
    75  *
    76  */
    77 void event_init(void)
     86sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod)
    7887{
    79         for (unsigned int i = 0; i < EVENT_END; i++)
    80                 event_initialize(evno2event(i, NULL));
     88        return (sysarg_t) event_subscribe((event_type_t) evno, (sysarg_t)
     89            imethod, &TASK->answerbox);
    8190}
    8291
    83 void event_task_init(task_t *task)
     92bool event_is_subscribed(event_type_t evno)
    8493{
    85         for (unsigned int i = EVENT_END; i < EVENT_TASK_END; i++)
    86                 event_initialize(evno2event(i, task));
     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;
    87103}
    88104
    89105
    90 /** Unsubscribe kernel events associated with an answerbox
    91  *
    92  * @param answerbox Answerbox to be unsubscribed.
    93  *
    94  */
    95106void event_cleanup_answerbox(answerbox_t *answerbox)
    96107{
    97         for (unsigned int i = 0; i < EVENT_END; i++) {
     108        unsigned int i;
     109       
     110        for (i = 0; i < EVENT_END; i++) {
    98111                spinlock_lock(&events[i].lock);
    99                
    100112                if (events[i].answerbox == answerbox) {
    101113                        events[i].answerbox = NULL;
    102114                        events[i].counter = 0;
    103115                        events[i].imethod = 0;
    104                         events[i].masked = false;
    105116                }
    106                
    107117                spinlock_unlock(&events[i].lock);
    108118        }
    109119}
    110120
    111 static 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  */
    125 void event_set_unmask_callback(event_type_t evno, event_callback_t callback)
     121void event_notify(event_type_t evno, sysarg_t a1, sysarg_t a2, sysarg_t a3,
     122    sysarg_t a4, sysarg_t a5)
    126123{
    127124        ASSERT(evno < EVENT_END);
    128125       
    129         _event_set_unmask_callback(evno2event(evno, NULL), callback);
    130 }
    131 
    132 void 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 
    141 static 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);
     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);
    151138                       
    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  */
    205 int 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  */
    233 int 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  */
    254 static 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  */
    280 static 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  */
    307 sysarg_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  */
    329 sysarg_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;
     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);
    337147}
    338148
Note: See TracChangeset for help on using the changeset viewer.