Changeset eb522e8 in mainline for uspace/app/klog/klog.c


Ignore:
Timestamp:
2011-06-01T08:43:42Z (15 years ago)
Author:
Lubos Slovak <lubos.slovak@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8d6c1f1
Parents:
9e2e715 (diff), e51a514 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Huuuuuge merge from development - all the work actually :)

File:
1 edited

Legend:

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

    r9e2e715 reb522e8  
    3636
    3737#include <stdio.h>
    38 #include <ipc/ipc.h>
    3938#include <async.h>
    40 #include <ipc/services.h>
    4139#include <as.h>
    42 #include <sysinfo.h>
     40#include <ddi.h>
    4341#include <event.h>
    4442#include <errno.h>
    4543#include <str_error.h>
    4644#include <io/klog.h>
     45#include <sysinfo.h>
     46#include <malloc.h>
     47#include <fibril_synch.h>
     48#include <adt/list.h>
     49#include <adt/prodcons.h>
    4750
    4851#define NAME       "klog"
    4952#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;
    5062
    5163/* Pointer to klog area */
     
    5365static size_t klog_length;
    5466
    55 static FILE *log;
    56 
    57 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
    58 {
     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       
    59166        size_t klog_start = (size_t) IPC_GET_ARG1(*call);
    60167        size_t klog_len = (size_t) IPC_GET_ARG2(*call);
    61168        size_t klog_stored = (size_t) IPC_GET_ARG3(*call);
    62         size_t i;
    63        
    64         for (i = klog_len - klog_stored; i < klog_len; i++) {
    65                 wchar_t ch = klog[(klog_start + i) % klog_length];
    66                
    67                 putchar(ch);
    68                
    69                 if (log != NULL)
    70                         fputc(ch, log);
    71         }
    72        
    73         if (log != NULL) {
    74                 fflush(log);
    75                 fsync(fileno(log));
    76         }
     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);
    77183}
    78184
    79185int main(int argc, char *argv[])
    80186{
    81         size_t klog_pages;
    82         if (sysinfo_get_value("klog.pages", &klog_pages) != EOK) {
    83                 printf("%s: Error getting klog address\n", NAME);
    84                 return -1;
    85         }
    86        
    87         size_t klog_size = klog_pages * PAGE_SIZE;
    88         klog_length = klog_size / sizeof(wchar_t);
    89        
    90         klog = (wchar_t *) as_get_mappable_page(klog_size);
     187        size_t pages;
     188        int rc = sysinfo_get_value("klog.pages", &pages);
     189        if (rc != EOK) {
     190                fprintf(stderr, "%s: Unable to get number of klog pages\n",
     191                    NAME);
     192                return rc;
     193        }
     194       
     195        uintptr_t faddr;
     196        rc = sysinfo_get_value("klog.faddr", &faddr);
     197        if (rc != EOK) {
     198                fprintf(stderr, "%s: Unable to get klog physical address\n",
     199                    NAME);
     200                return rc;
     201        }
     202       
     203        size_t size = pages * PAGE_SIZE;
     204        klog_length = size / sizeof(wchar_t);
     205       
     206        klog = (wchar_t *) as_get_mappable_page(size);
    91207        if (klog == NULL) {
    92                 printf("%s: Error allocating memory area\n", NAME);
    93                 return -1;
    94         }
    95        
    96         int res = async_share_in_start_1_0(PHONE_NS, (void *) klog,
    97             klog_size, SERVICE_MEM_KLOG);
    98         if (res != EOK) {
    99                 printf("%s: Error initializing memory area\n", NAME);
    100                 return -1;
    101         }
    102        
    103         if (event_subscribe(EVENT_KLOG, 0) != EOK) {
    104                 printf("%s: Error registering klog notifications\n", NAME);
    105                 return -1;
    106         }
    107        
    108         /*
    109          * Mode "a" would be definitively much better here, but it is
    110          * not well supported by the FAT driver.
    111          *
    112          */
    113         log = fopen(LOG_FNAME, "w");
    114         if (log == NULL)
    115                 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
    116                     str_error(errno));
    117        
    118         async_set_interrupt_received(interrupt_received);
     208                fprintf(stderr, "%s: Unable to allocate virtual memory area\n",
     209                    NAME);
     210                return ENOMEM;
     211        }
     212       
     213        rc = physmem_map((void *) faddr, (void *) klog, pages,
     214            AS_AREA_READ | AS_AREA_CACHEABLE);
     215        if (rc != EOK) {
     216                fprintf(stderr, "%s: Unable to map klog\n", NAME);
     217                return rc;
     218        }
     219       
     220        prodcons_initialize(&pc);
     221        async_set_interrupt_received(notification_received);
     222        rc = event_subscribe(EVENT_KLOG, 0);
     223        if (rc != EOK) {
     224                fprintf(stderr, "%s: Unable to register klog notifications\n",
     225                    NAME);
     226                return rc;
     227        }
     228       
     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);
    119238        klog_update();
     239       
     240        task_retval(0);
    120241        async_manager();
    121242       
Note: See TracChangeset for help on using the changeset viewer.