Changes in / [8d308b9:0d8a304] in mainline


Ignore:
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/ipc/event.h

    r8d308b9 r0d8a304  
    5151        /** Counter. */
    5252        size_t counter;
     53        /** Masked flag. */
     54        bool masked;
     55        /** Unmask callback. */
     56        void (*unmask_cb)(void);
    5357} event_t;
    5458
    5559extern void event_init(void);
     60extern void event_cleanup_answerbox(answerbox_t *);
     61extern void event_set_unmask_callback(event_type_t, void (*)(void));
     62
     63#define event_notify_0(e, m) \
     64        event_notify((e), (m), 0, 0, 0, 0, 0)
     65#define event_notify_1(e, m, a1) \
     66        event_notify((e), (m), (a1), 0, 0, 0, 0)
     67#define event_notify_2(e, m, a1, a2) \
     68        event_notify((e), (m), (a1), (a2), 0, 0, 0)
     69#define event_notify_3(e, m, a1, a2, a3) \
     70        event_notify((e), (m), (a1), (a2), (a3), 0, 0)
     71#define event_notify_4(e, m, a1, a2, a3, a4) \
     72        event_notify((e), (m), (a1), (a2), (a3), (a4), 0)
     73#define event_notify_5(e, m, a1, a2, a3, a4, a5) \
     74        event_notify((e), (m), (a1), (a2), (a3), (a4), (a5))
     75
     76extern int event_notify(event_type_t, bool, sysarg_t, sysarg_t, sysarg_t,
     77    sysarg_t, sysarg_t);
     78
    5679extern sysarg_t sys_event_subscribe(sysarg_t, sysarg_t);
    57 extern bool event_is_subscribed(event_type_t);
    58 extern void event_cleanup_answerbox(answerbox_t *);
    59 
    60 #define event_notify_0(e) \
    61         event_notify((e), 0, 0, 0, 0, 0)
    62 #define event_notify_1(e, a1) \
    63         event_notify((e), (a1), 0, 0, 0, 0)
    64 #define event_notify_2(e, a1, a2) \
    65         event_notify((e), (a1), (a2), 0, 0, 0)
    66 #define event_notify_3(e, a1, a2, a3) \
    67         event_notify((e), (a1), (a2), (a3), 0, 0)
    68 #define event_notify_4(e, a1, a2, a3, a4) \
    69         event_notify((e), (a1), (a2), (a3), (a4), 0)
    70 #define event_notify_5(e, a1, a2, a3, a4, a5) \
    71         event_notify((e), (a1), (a2), (a3), (a4), (a5))
    72 
    73 extern void event_notify(event_type_t, sysarg_t, sysarg_t, sysarg_t,
    74     sysarg_t, sysarg_t);
     80extern sysarg_t sys_event_unmask(sysarg_t);
    7581
    7682#endif
  • kernel/generic/include/ipc/event_types.h

    r8d308b9 r0d8a304  
    3939        /** New data available in kernel log */
    4040        EVENT_KLOG = 0,
    41         /** Returning from kernel console to userspace */
     41        /** Returning from kernel console to uspace */
    4242        EVENT_KCONSOLE,
    4343        /** A task/thread has faulted and will be terminated */
  • kernel/generic/include/syscall/syscall.h

    r8d308b9 r0d8a304  
    7575       
    7676        SYS_EVENT_SUBSCRIBE,
     77        SYS_EVENT_UNMASK,
    7778       
    7879        SYS_CAP_GRANT,
  • kernel/generic/src/console/cmd.c

    r8d308b9 r0d8a304  
    11071107        release_console();
    11081108       
    1109         event_notify_0(EVENT_KCONSOLE);
     1109        event_notify_0(EVENT_KCONSOLE, false);
    11101110        indev_pop_character(stdin);
    11111111       
  • kernel/generic/src/console/console.c

    r8d308b9 r0d8a304  
    5353#include <str.h>
    5454
    55 #define KLOG_PAGES    4
     55#define KLOG_PAGES    8
    5656#define KLOG_LENGTH   (KLOG_PAGES * PAGE_SIZE / sizeof(wchar_t))
    5757#define KLOG_LATENCY  8
     
    165165        sysinfo_set_item_val("klog.faddr", NULL, (sysarg_t) faddr);
    166166        sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
     167
     168        event_set_unmask_callback(EVENT_KLOG, klog_update);
    167169       
    168170        spinlock_lock(&klog_lock);
     
    265267        spinlock_lock(&klog_lock);
    266268       
    267         if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
    268                 event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
    269                 klog_uspace = 0;
     269        if ((klog_inited) && (klog_uspace > 0)) {
     270                if (event_notify_3(EVENT_KLOG, true, klog_start, klog_len,
     271                    klog_uspace) == EOK)
     272                        klog_uspace = 0;
    270273        }
    271274       
  • kernel/generic/src/ipc/event.c

    r8d308b9 r0d8a304  
    4848static event_t events[EVENT_END];
    4949
    50 /** Initialize kernel events. */
     50/** Initialize kernel events.
     51 *
     52 */
    5153void event_init(void)
    5254{
    53         unsigned int i;
    54        
    55         for (i = 0; i < EVENT_END; i++) {
     55        for (unsigned int i = 0; i < EVENT_END; i++) {
    5656                spinlock_initialize(&events[i].lock, "event.lock");
    5757                events[i].answerbox = NULL;
    5858                events[i].counter = 0;
    5959                events[i].imethod = 0;
     60                events[i].masked = false;
     61                events[i].unmask_cb = NULL;
    6062        }
    6163}
    6264
     65/** Unsubscribe kernel events associated with an answerbox
     66 *
     67 * @param answerbox Answerbox to be unsubscribed.
     68 *
     69 */
     70void event_cleanup_answerbox(answerbox_t *answerbox)
     71{
     72        for (unsigned int i = 0; i < EVENT_END; i++) {
     73                spinlock_lock(&events[i].lock);
     74               
     75                if (events[i].answerbox == answerbox) {
     76                        events[i].answerbox = NULL;
     77                        events[i].counter = 0;
     78                        events[i].imethod = 0;
     79                        events[i].masked = false;
     80                }
     81               
     82                spinlock_unlock(&events[i].lock);
     83        }
     84}
     85
     86/** Define a callback function for the event unmask event.
     87 *
     88 * @param evno Event type.
     89 * @param cb   Callback function to be called when the event is unmasked.
     90 *
     91 */
     92void event_set_unmask_callback(event_type_t evno, void (*cb)(void))
     93{
     94        ASSERT(evno < EVENT_END);
     95       
     96        spinlock_lock(&events[evno].lock);
     97        events[evno].unmask_cb = cb;
     98        spinlock_unlock(&events[evno].lock);
     99}
     100
     101/** Send kernel notification event
     102 *
     103 * @param evno Event type.
     104 * @param mask Mask further notifications after a successful
     105 *             sending.
     106 * @param a1   First argument.
     107 * @param a2   Second argument.
     108 * @param a3   Third argument.
     109 * @param a4   Fourth argument.
     110 * @param a5   Fifth argument.
     111 *
     112 * @return EOK if notification was successfully sent.
     113 * @return ENOMEM if the notification IPC message failed to allocate.
     114 * @return EBUSY if the notifications of the given type are
     115 *         currently masked.
     116 * @return ENOENT if the notifications of the given type are
     117 *         currently not subscribed.
     118 *
     119 */
     120int event_notify(event_type_t evno, bool mask, sysarg_t a1, sysarg_t a2,
     121    sysarg_t a3, sysarg_t a4, sysarg_t a5)
     122{
     123        ASSERT(evno < EVENT_END);
     124       
     125        spinlock_lock(&events[evno].lock);
     126       
     127        int ret;
     128       
     129        if (events[evno].answerbox != NULL) {
     130                if (!events[evno].masked) {
     131                        call_t *call = ipc_call_alloc(FRAME_ATOMIC);
     132                       
     133                        if (call) {
     134                                call->flags |= IPC_CALL_NOTIF;
     135                                call->priv = ++events[evno].counter;
     136                               
     137                                IPC_SET_IMETHOD(call->data, events[evno].imethod);
     138                                IPC_SET_ARG1(call->data, a1);
     139                                IPC_SET_ARG2(call->data, a2);
     140                                IPC_SET_ARG3(call->data, a3);
     141                                IPC_SET_ARG4(call->data, a4);
     142                                IPC_SET_ARG5(call->data, a5);
     143                               
     144                                irq_spinlock_lock(&events[evno].answerbox->irq_lock, true);
     145                                list_append(&call->link, &events[evno].answerbox->irq_notifs);
     146                                irq_spinlock_unlock(&events[evno].answerbox->irq_lock, true);
     147                               
     148                                waitq_wakeup(&events[evno].answerbox->wq, WAKEUP_FIRST);
     149                               
     150                                if (mask)
     151                                        events[evno].masked = true;
     152                               
     153                                ret = EOK;
     154                        } else
     155                                ret = ENOMEM;
     156                } else
     157                        ret = EBUSY;
     158        } else
     159                ret = ENOENT;
     160       
     161        spinlock_unlock(&events[evno].lock);
     162       
     163        return ret;
     164}
     165
     166/** Subscribe event notifications
     167 *
     168 * @param evno      Event type.
     169 * @param imethod   IPC interface and method to be used for
     170 *                  the notifications.
     171 * @param answerbox Answerbox to send the notifications to.
     172 *
     173 * @return EOK if the subscription was successful.
     174 * @return EEXISTS if the notifications of the given type are
     175 *         already subscribed.
     176 *
     177 */
    63178static int event_subscribe(event_type_t evno, sysarg_t imethod,
    64179    answerbox_t *answerbox)
    65180{
    66         if (evno >= EVENT_END)
    67                 return ELIMIT;
     181        ASSERT(evno < EVENT_END);
    68182       
    69183        spinlock_lock(&events[evno].lock);
     
    75189                events[evno].imethod = imethod;
    76190                events[evno].counter = 0;
     191                events[evno].masked = false;
    77192                res = EOK;
    78193        } else
     
    84199}
    85200
     201/** Unmask event notifications
     202 *
     203 * @param evno Event type to unmask.
     204 *
     205 */
     206static void event_unmask(event_type_t evno)
     207{
     208        void (*cb)(void);
     209        ASSERT(evno < EVENT_END);
     210       
     211        spinlock_lock(&events[evno].lock);
     212        events[evno].masked = false;
     213        cb = events[evno].unmask_cb;
     214        spinlock_unlock(&events[evno].lock);
     215       
     216        /*
     217         * Check if there is an unmask callback function defined for this event.
     218         */
     219        if (cb)
     220            cb();
     221}
     222
     223/** Event notification syscall wrapper
     224 *
     225 * @param evno    Event type to subscribe.
     226 * @param imethod IPC interface and method to be used for
     227 *                the notifications.
     228 *
     229 * @return EOK on success.
     230 * @return ELIMIT on unknown event type.
     231 * @return EEXISTS if the notifications of the given type are
     232 *         already subscribed.
     233 *
     234 */
    86235sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod)
    87236{
     237        if (evno >= EVENT_END)
     238                return ELIMIT;
     239       
    88240        return (sysarg_t) event_subscribe((event_type_t) evno, (sysarg_t)
    89241            imethod, &TASK->answerbox);
    90242}
    91243
    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 
    106 void event_cleanup_answerbox(answerbox_t *answerbox)
    107 {
    108         unsigned int i;
    109        
    110         for (i = 0; i < EVENT_END; i++) {
    111                 spinlock_lock(&events[i].lock);
    112                 if (events[i].answerbox == answerbox) {
    113                         events[i].answerbox = NULL;
    114                         events[i].counter = 0;
    115                         events[i].imethod = 0;
    116                 }
    117                 spinlock_unlock(&events[i].lock);
    118         }
    119 }
    120 
    121 void event_notify(event_type_t evno, sysarg_t a1, sysarg_t a2, sysarg_t a3,
    122     sysarg_t a4, sysarg_t a5)
    123 {
    124         ASSERT(evno < EVENT_END);
    125        
    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);
    138                        
    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);
     244/** Event notification unmask syscall wrapper
     245 *
     246 * Note that currently no tests are performed whether the calling
     247 * task is entitled to unmask the notifications. However, thanks
     248 * to the fact that notification masking is only a performance
     249 * optimization, this has probably no security implications.
     250 *
     251 * @param evno Event type to unmask.
     252 *
     253 * @return EOK on success.
     254 * @return ELIMIT on unknown event type.
     255 *
     256 */
     257sysarg_t sys_event_unmask(sysarg_t evno)
     258{
     259        if (evno >= EVENT_END)
     260                return ELIMIT;
     261       
     262        event_unmask((event_type_t) evno);
     263        return EOK;
    147264}
    148265
  • kernel/generic/src/proc/task.c

    r8d308b9 r0d8a304  
    534534        */
    535535        if (notify) {
    536                 if (event_is_subscribed(EVENT_FAULT)) {
    537                         /* Notify the subscriber that a fault occurred. */
    538                         event_notify_3(EVENT_FAULT, LOWER32(TASK->taskid),
    539                             UPPER32(TASK->taskid), (sysarg_t) THREAD);
    540                
     536                /* Notify the subscriber that a fault occurred. */
     537                if (event_notify_3(EVENT_FAULT, false, LOWER32(TASK->taskid),
     538                    UPPER32(TASK->taskid), (sysarg_t) THREAD) == EOK) {
    541539#ifdef CONFIG_UDEBUG
    542540                        /* Wait for a debugging session. */
  • kernel/generic/src/syscall/syscall.c

    r8d308b9 r0d8a304  
    161161        /* Event notification syscalls. */
    162162        (syshandler_t) sys_event_subscribe,
     163        (syshandler_t) sys_event_unmask,
    163164       
    164165        /* Capabilities related syscalls. */
  • uspace/app/klog/klog.c

    r8d308b9 r0d8a304  
    4444#include <io/klog.h>
    4545#include <sysinfo.h>
     46#include <malloc.h>
     47#include <fibril_synch.h>
     48#include <adt/list.h>
     49#include <adt/prodcons.h>
    4650
    4751#define NAME       "klog"
    4852#define LOG_FNAME  "/log/klog"
     53
     54/* Producer/consumer buffers */
     55typedef struct {
     56        link_t link;
     57        size_t length;
     58        wchar_t *data;
     59} item_t;
     60
     61static prodcons_t pc;
    4962
    5063/* Pointer to klog area */
     
    5265static size_t klog_length;
    5366
    54 static FILE *log;
    55 
    56 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    57 {
     67/* Notification mutex */
     68static FIBRIL_MUTEX_INITIALIZE(mtx);
     69
     70/** Klog producer
     71 *
     72 * Copies the contents of a character buffer to local
     73 * producer/consumer queue.
     74 *
     75 * @param length Number of characters to copy.
     76 * @param data   Pointer to the kernel klog buffer.
     77 *
     78 */
     79static void producer(size_t length, wchar_t *data)
     80{
     81        item_t *item = (item_t *) malloc(sizeof(item_t));
     82        if (item == NULL)
     83                return;
     84       
     85        size_t sz = sizeof(wchar_t) * length;
     86        wchar_t *buf = (wchar_t *) malloc(sz);
     87        if (data == NULL) {
     88                free(item);
     89                return;
     90        }
     91       
     92        memcpy(buf, data, sz);
     93       
     94        link_initialize(&item->link);
     95        item->length = length;
     96        item->data = buf;
     97        prodcons_produce(&pc, &item->link);
     98}
     99
     100/** Klog consumer
     101 *
     102 * Waits in an infinite loop for the character data created by
     103 * the producer and outputs them to stdout and optionally into
     104 * a file.
     105 *
     106 * @param data Unused.
     107 *
     108 * @return Always EOK (unreachable).
     109 *
     110 */
     111static int consumer(void *data)
     112{
     113        FILE *log = fopen(LOG_FNAME, "a");
     114        if (log == NULL)
     115                printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
     116                    str_error(errno));
     117       
     118        while (true) {
     119                link_t *link = prodcons_consume(&pc);
     120                item_t *item = list_get_instance(link, item_t, link);
     121               
     122                for (size_t i = 0; i < item->length; i++)
     123                        putchar(item->data[i]);
     124               
     125                if (log != NULL) {
     126                        for (size_t i = 0; i < item->length; i++)
     127                                fputc(item->data[i], log);
     128                       
     129                        fflush(log);
     130                        fsync(fileno(log));
     131                }
     132               
     133                free(item->data);
     134                free(item);
     135        }
     136       
     137        fclose(log);
     138        return EOK;
     139}
     140
     141/** Kernel notification handler
     142 *
     143 * Receives kernel klog notifications.
     144 *
     145 * @param callid IPC call ID.
     146 * @param call   IPC call structure.
     147 *
     148 */
     149static void notification_received(ipc_callid_t callid, ipc_call_t *call)
     150{
     151        /*
     152         * Make sure we process only a single notification
     153         * at any time to limit the chance of the consumer
     154         * starving.
     155         *
     156         * Note: Usually the automatic masking of the klog
     157         * notifications on the kernel side does the trick
     158         * of limiting the chance of accidentally copying
     159         * the same data multiple times. However, due to
     160         * the non-blocking architecture of klog notifications,
     161         * this possibility cannot be generally avoided.
     162         */
     163       
     164        fibril_mutex_lock(&mtx);
     165       
    58166        size_t klog_start = (size_t) IPC_GET_ARG1(*call);
    59167        size_t klog_len = (size_t) IPC_GET_ARG2(*call);
    60168        size_t klog_stored = (size_t) IPC_GET_ARG3(*call);
    61         size_t i;
    62        
    63         for (i = klog_len - klog_stored; i < klog_len; i++) {
    64                 wchar_t ch = klog[(klog_start + i) % klog_length];
    65                
    66                 putchar(ch);
    67                
    68                 if (log != NULL)
    69                         fputc(ch, log);
    70         }
    71        
    72         if (log != NULL) {
    73                 fflush(log);
    74                 fsync(fileno(log));
    75         }
     169       
     170        size_t offset = (klog_start + klog_len - klog_stored) % klog_length;
     171       
     172        /* Copy data from the ring buffer */
     173        if (offset + klog_stored >= klog_length) {
     174                size_t split = klog_length - offset;
     175               
     176                producer(split, klog + offset);
     177                producer(klog_stored - split, klog);
     178        } else
     179                producer(klog_stored, klog + offset);
     180       
     181        event_unmask(EVENT_KLOG);
     182        fibril_mutex_unlock(&mtx);
    76183}
    77184
     
    111218        }
    112219       
     220        prodcons_initialize(&pc);
     221        async_set_interrupt_received(notification_received);
    113222        rc = event_subscribe(EVENT_KLOG, 0);
    114223        if (rc != EOK) {
     
    118227        }
    119228       
    120         log = fopen(LOG_FNAME, "a");
    121         if (log == NULL)
    122                 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
    123                     str_error(errno));
    124        
    125         async_set_interrupt_received(interrupt_received);
     229        fid_t fid = fibril_create(consumer, NULL);
     230        if (!fid) {
     231                fprintf(stderr, "%s: Unable to create consumer fibril\n",
     232                    NAME);
     233                return ENOMEM;
     234        }
     235       
     236        fibril_add_ready(fid);
     237        event_unmask(EVENT_KLOG);
    126238        klog_update();
     239       
     240        task_retval(0);
    127241        async_manager();
    128242       
  • uspace/lib/c/Makefile

    r8d308b9 r0d8a304  
    108108        generic/adt/measured_strings.c \
    109109        generic/adt/char_map.c \
     110        generic/adt/prodcons.c \
    110111        generic/time.c \
    111112        generic/stdlib.c \
  • uspace/lib/c/generic/event.c

    r8d308b9 r0d8a304  
    4141#include <kernel/ipc/event_types.h>
    4242
    43 /** Subscribe for event notifications.
     43/** Subscribe event notifications.
    4444 *
    45  * @param evno   Event number.
    46  * @param method Use this method for notifying me.
     45 * @param evno    Event type to subscribe.
     46 * @param imethod Use this interface and method for notifying me.
    4747 *
    4848 * @return Value returned by the kernel.
     49 *
    4950 */
    50 int event_subscribe(event_type_t e, sysarg_t method)
     51int event_subscribe(event_type_t evno, sysarg_t imethod)
    5152{
    52         return __SYSCALL2(SYS_EVENT_SUBSCRIBE, (sysarg_t) e, (sysarg_t) method);
     53        return __SYSCALL2(SYS_EVENT_SUBSCRIBE, (sysarg_t) evno,
     54            (sysarg_t) imethod);
     55}
     56
     57/** Unmask event notifications.
     58 *
     59 * @param evno Event type to unmask.
     60 *
     61 * @return Value returned by the kernel.
     62 *
     63 */
     64int event_unmask(event_type_t evno)
     65{
     66        return __SYSCALL1(SYS_EVENT_UNMASK, (sysarg_t) evno);
    5367}
    5468
  • uspace/lib/c/include/event.h

    r8d308b9 r0d8a304  
    3939
    4040extern int event_subscribe(event_type_t, sysarg_t);
     41extern int event_unmask(event_type_t);
    4142
    4243#endif
Note: See TracChangeset for help on using the changeset viewer.