klog.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006 Ondrej Palkovsky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00037 #include <stdio.h>
00038 #include <async.h>
00039 #include <as.h>
00040 #include <ddi.h>
00041 #include <event.h>
00042 #include <errno.h>
00043 #include <str_error.h>
00044 #include <io/klog.h>
00045 #include <sysinfo.h>
00046 #include <malloc.h>
00047 #include <fibril_synch.h>
00048 #include <adt/list.h>
00049 #include <adt/prodcons.h>
00050 
00051 #define NAME       "klog"
00052 #define LOG_FNAME  "/log/klog"
00053 
00054 /* Producer/consumer buffers */
00055 typedef struct {
00056         link_t link;
00057         size_t length;
00058         wchar_t *data;
00059 } item_t;
00060 
00061 static prodcons_t pc;
00062 
00063 /* Pointer to klog area */
00064 static wchar_t *klog;
00065 static size_t klog_length;
00066 
00067 /* Notification mutex */
00068 static FIBRIL_MUTEX_INITIALIZE(mtx);
00069 
00079 static void producer(size_t length, wchar_t *data)
00080 {
00081         item_t *item = (item_t *) malloc(sizeof(item_t));
00082         if (item == NULL)
00083                 return;
00084         
00085         size_t sz = sizeof(wchar_t) * length;
00086         wchar_t *buf = (wchar_t *) malloc(sz);
00087         if (data == NULL) {
00088                 free(item);
00089                 return;
00090         }
00091         
00092         memcpy(buf, data, sz);
00093         
00094         link_initialize(&item->link);
00095         item->length = length;
00096         item->data = buf;
00097         prodcons_produce(&pc, &item->link);
00098 }
00099 
00111 static int consumer(void *data)
00112 {
00113         FILE *log = fopen(LOG_FNAME, "a");
00114         if (log == NULL)
00115                 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
00116                     str_error(errno));
00117         
00118         while (true) {
00119                 link_t *link = prodcons_consume(&pc);
00120                 item_t *item = list_get_instance(link, item_t, link);
00121                 
00122                 for (size_t i = 0; i < item->length; i++)
00123                         putchar(item->data[i]);
00124                 
00125                 if (log != NULL) {
00126                         for (size_t i = 0; i < item->length; i++)
00127                                 fputc(item->data[i], log);
00128                         
00129                         fflush(log);
00130                         fsync(fileno(log));
00131                 }
00132                 
00133                 free(item->data);
00134                 free(item);
00135         }
00136         
00137         fclose(log);
00138         return EOK;
00139 }
00140 
00149 static void notification_received(ipc_callid_t callid, ipc_call_t *call)
00150 {
00151         /*
00152          * Make sure we process only a single notification
00153          * at any time to limit the chance of the consumer
00154          * starving.
00155          *
00156          * Note: Usually the automatic masking of the klog
00157          * notifications on the kernel side does the trick
00158          * of limiting the chance of accidentally copying
00159          * the same data multiple times. However, due to
00160          * the non-blocking architecture of klog notifications,
00161          * this possibility cannot be generally avoided.
00162          */
00163         
00164         fibril_mutex_lock(&mtx);
00165         
00166         size_t klog_start = (size_t) IPC_GET_ARG1(*call);
00167         size_t klog_len = (size_t) IPC_GET_ARG2(*call);
00168         size_t klog_stored = (size_t) IPC_GET_ARG3(*call);
00169         
00170         size_t offset = (klog_start + klog_len - klog_stored) % klog_length;
00171         
00172         /* Copy data from the ring buffer */
00173         if (offset + klog_stored >= klog_length) {
00174                 size_t split = klog_length - offset;
00175                 
00176                 producer(split, klog + offset);
00177                 producer(klog_stored - split, klog);
00178         } else
00179                 producer(klog_stored, klog + offset);
00180         
00181         event_unmask(EVENT_KLOG);
00182         fibril_mutex_unlock(&mtx);
00183 }
00184 
00185 int main(int argc, char *argv[])
00186 {
00187         size_t pages;
00188         int rc = sysinfo_get_value("klog.pages", &pages);
00189         if (rc != EOK) {
00190                 fprintf(stderr, "%s: Unable to get number of klog pages\n",
00191                     NAME);
00192                 return rc;
00193         }
00194         
00195         uintptr_t faddr;
00196         rc = sysinfo_get_value("klog.faddr", &faddr);
00197         if (rc != EOK) {
00198                 fprintf(stderr, "%s: Unable to get klog physical address\n",
00199                     NAME);
00200                 return rc;
00201         }
00202         
00203         size_t size = pages * PAGE_SIZE;
00204         klog_length = size / sizeof(wchar_t);
00205         
00206         klog = (wchar_t *) as_get_mappable_page(size);
00207         if (klog == NULL) {
00208                 fprintf(stderr, "%s: Unable to allocate virtual memory area\n",
00209                     NAME);
00210                 return ENOMEM;
00211         }
00212         
00213         rc = physmem_map((void *) faddr, (void *) klog, pages,
00214             AS_AREA_READ | AS_AREA_CACHEABLE);
00215         if (rc != EOK) {
00216                 fprintf(stderr, "%s: Unable to map klog\n", NAME);
00217                 return rc;
00218         }
00219         
00220         prodcons_initialize(&pc);
00221         async_set_interrupt_received(notification_received);
00222         rc = event_subscribe(EVENT_KLOG, 0);
00223         if (rc != EOK) {
00224                 fprintf(stderr, "%s: Unable to register klog notifications\n",
00225                     NAME);
00226                 return rc;
00227         }
00228         
00229         fid_t fid = fibril_create(consumer, NULL);
00230         if (!fid) {
00231                 fprintf(stderr, "%s: Unable to create consumer fibril\n",
00232                     NAME);
00233                 return ENOMEM;
00234         }
00235         
00236         fibril_add_ready(fid);
00237         event_unmask(EVENT_KLOG);
00238         klog_update();
00239         
00240         task_retval(0);
00241         async_manager();
00242         
00243         return 0;
00244 }
00245 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7