Changes in uspace/app/klog/klog.c [382cd26:3815efb] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/klog/klog.c
r382cd26 r3815efb 44 44 #include <io/klog.h> 45 45 #include <sysinfo.h> 46 #include <malloc.h> 47 #include <fibril_synch.h> 48 #include <adt/list.h> 49 #include <adt/prodcons.h> 46 50 47 51 #define NAME "klog" 48 52 #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; 49 62 50 63 /* Pointer to klog area */ … … 52 65 static size_t klog_length; 53 66 54 static FILE *log; 55 56 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call) 57 { 67 /* Notification mutex */ 68 static 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 */ 79 static 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 */ 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 58 167 size_t klog_start = (size_t) IPC_GET_ARG1(*call); 59 168 size_t klog_len = (size_t) IPC_GET_ARG2(*call); 60 169 size_t klog_stored = (size_t) IPC_GET_ARG3(*call); 61 size_t i; 62 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 } 71 72 if (log != NULL) { 73 fflush(log); 74 fsync(fileno(log)); 75 } 170 171 size_t offset = (klog_start + klog_len - klog_stored) % klog_length; 172 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); 76 184 } 77 185 … … 111 219 } 112 220 221 prodcons_initialize(&pc); 222 async_set_interrupt_received(notification_received); 113 223 rc = event_subscribe(EVENT_KLOG, 0); 114 224 if (rc != EOK) { … … 118 228 } 119 229 120 log = fopen(LOG_FNAME, "a"); 121 if (log == NULL) 122 printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME, 123 str_error(errno)); 124 125 async_set_interrupt_received(interrupt_received); 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 } 236 237 fibril_add_ready(fid); 238 event_unmask(EVENT_KLOG); 126 239 klog_update(); 240 241 task_retval(0); 127 242 async_manager(); 128 243
Note:
See TracChangeset
for help on using the changeset viewer.