00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
00064 static wchar_t *klog;
00065 static size_t klog_length;
00066
00067
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
00153
00154
00155
00156
00157
00158
00159
00160
00161
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
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