Changes in uspace/app/klog/klog.c [3815efb:6119f24] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/klog/klog.c

    r3815efb r6119f24  
    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>
    5046
    5147#define NAME       "klog"
    5248#define LOG_FNAME  "/log/klog"
    53 
    54 /* Producer/consumer buffers */
    55 typedef struct {
    56         link_t link;
    57         size_t length;
    58         wchar_t *data;
    59 } item_t;
    60 
    61 static prodcons_t pc;
    6249
    6350/* Pointer to klog area */
     
    6552static size_t klog_length;
    6653
    67 /* Notification mutex */
    68 static FIBRIL_MUTEX_INITIALIZE(mtx);
     54static FILE *log;
    6955
    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  */
    79 static void producer(size_t length, wchar_t *data)
     56static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    8057{
    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  */
    111 static 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  * @param arg    Local argument
    148  *
    149  */
    150 static void notification_received(ipc_callid_t callid, ipc_call_t *call)
    151 {
    152         /*
    153          * Make sure we process only a single notification
    154          * at any time to limit the chance of the consumer
    155          * starving.
    156          *
    157          * Note: Usually the automatic masking of the klog
    158          * notifications on the kernel side does the trick
    159          * of limiting the chance of accidentally copying
    160          * the same data multiple times. However, due to
    161          * the non-blocking architecture of klog notifications,
    162          * this possibility cannot be generally avoided.
    163          */
    164        
    165         fibril_mutex_lock(&mtx);
    166        
    16758        size_t klog_start = (size_t) IPC_GET_ARG1(*call);
    16859        size_t klog_len = (size_t) IPC_GET_ARG2(*call);
    16960        size_t klog_stored = (size_t) IPC_GET_ARG3(*call);
     61        size_t i;
    17062       
    171         size_t offset = (klog_start + klog_len - klog_stored) % klog_length;
     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        }
    17271       
    173         /* Copy data from the ring buffer */
    174         if (offset + klog_stored >= klog_length) {
    175                 size_t split = klog_length - offset;
    176                
    177                 producer(split, klog + offset);
    178                 producer(klog_stored - split, klog);
    179         } else
    180                 producer(klog_stored, klog + offset);
    181        
    182         event_unmask(EVENT_KLOG);
    183         fibril_mutex_unlock(&mtx);
     72        if (log != NULL) {
     73                fflush(log);
     74                fsync(fileno(log));
     75        }
    18476}
    18577
     
    219111        }
    220112       
    221         prodcons_initialize(&pc);
    222         async_set_interrupt_received(notification_received);
    223113        rc = event_subscribe(EVENT_KLOG, 0);
    224114        if (rc != EOK) {
     
    228118        }
    229119       
    230         fid_t fid = fibril_create(consumer, NULL);
    231         if (!fid) {
    232                 fprintf(stderr, "%s: Unable to create consumer fibril\n",
    233                     NAME);
    234                 return ENOMEM;
    235         }
     120        /*
     121         * Mode "a" would be definitively much better here, but it is
     122         * not well supported by the FAT driver.
     123         */
     124        log = fopen(LOG_FNAME, "w");
     125        if (log == NULL)
     126                printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
     127                    str_error(errno));
    236128       
    237         fibril_add_ready(fid);
    238         event_unmask(EVENT_KLOG);
     129        async_set_interrupt_received(interrupt_received);
    239130        klog_update();
    240        
    241         task_retval(0);
    242131        async_manager();
    243132       
Note: See TracChangeset for help on using the changeset viewer.