Changes in uspace/app/klog/klog.c [4e1a2f5:25bbaea] in mainline


Ignore:
File:
1 edited

Legend:

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

    r4e1a2f5 r25bbaea  
    4444#include <io/klog.h>
    4545#include <sysinfo.h>
    46 #include <malloc.h>
    4746#include <fibril_synch.h>
    48 #include <adt/list.h>
    49 #include <adt/prodcons.h>
    5047
    5148#define NAME       "klog"
    5249#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;
    6250
    6351/* Pointer to klog area */
     
    6553static size_t klog_length;
    6654
    67 /* Notification mutex */
    68 static FIBRIL_MUTEX_INITIALIZE(mtx);
     55static FILE *log;
    6956
    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)
     57/* Serialize the output a bit. This will not avoid messed-up log completely
     58   but chances for are pretty high (experimentally confirmed). */
     59static FIBRIL_MUTEX_INITIALIZE(log_mutex);
     60
     61static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    8062{
    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  *
    148  */
    149 static 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);
     63        fibril_mutex_lock(&log_mutex);
    16564       
    16665        size_t klog_start = (size_t) IPC_GET_ARG1(*call);
    16766        size_t klog_len = (size_t) IPC_GET_ARG2(*call);
    16867        size_t klog_stored = (size_t) IPC_GET_ARG3(*call);
     68        size_t i;
    16969       
    170         size_t offset = (klog_start + klog_len - klog_stored) % klog_length;
     70        for (i = klog_len - klog_stored; i < klog_len; i++) {
     71                wchar_t ch = klog[(klog_start + i) % klog_length];
     72               
     73                putchar(ch);
     74               
     75                if (log != NULL)
     76                        fputc(ch, log);
     77        }
    17178       
    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);
     79        if (log != NULL) {
     80                fflush(log);
     81                fsync(fileno(log));
     82        }
    18083       
    181         event_unmask(EVENT_KLOG);
    182         fibril_mutex_unlock(&mtx);
     84        fibril_mutex_unlock(&log_mutex);
    18385}
    18486
     
    218120        }
    219121       
    220         prodcons_initialize(&pc);
    221         async_set_interrupt_received(notification_received);
    222122        rc = event_subscribe(EVENT_KLOG, 0);
    223123        if (rc != EOK) {
     
    227127        }
    228128       
    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         }
     129        /*
     130         * Mode "a" would be definitively much better here, but it is
     131         * not well supported by the FAT driver.
     132         */
     133        log = fopen(LOG_FNAME, "w");
     134        if (log == NULL)
     135                printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
     136                    str_error(errno));
    235137       
    236         fibril_add_ready(fid);
    237         event_unmask(EVENT_KLOG);
     138        async_set_interrupt_received(interrupt_received);
    238139        klog_update();
    239        
    240         task_retval(0);
    241140        async_manager();
    242141       
Note: See TracChangeset for help on using the changeset viewer.