Changes in uspace/app/klog/klog.c [4e1a2f5:25bbaea] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/klog/klog.c
r4e1a2f5 r25bbaea 44 44 #include <io/klog.h> 45 45 #include <sysinfo.h> 46 #include <malloc.h>47 46 #include <fibril_synch.h> 48 #include <adt/list.h>49 #include <adt/prodcons.h>50 47 51 48 #define NAME "klog" 52 49 #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;62 50 63 51 /* Pointer to klog area */ … … 65 53 static size_t klog_length; 66 54 67 /* Notification mutex */ 68 static FIBRIL_MUTEX_INITIALIZE(mtx); 55 static FILE *log; 69 56 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). */ 59 static FIBRIL_MUTEX_INITIALIZE(log_mutex); 60 61 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call) 80 62 { 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); 165 64 166 65 size_t klog_start = (size_t) IPC_GET_ARG1(*call); 167 66 size_t klog_len = (size_t) IPC_GET_ARG2(*call); 168 67 size_t klog_stored = (size_t) IPC_GET_ARG3(*call); 68 size_t i; 169 69 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 } 171 78 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 } 180 83 181 event_unmask(EVENT_KLOG); 182 fibril_mutex_unlock(&mtx); 84 fibril_mutex_unlock(&log_mutex); 183 85 } 184 86 … … 218 120 } 219 121 220 prodcons_initialize(&pc);221 async_set_interrupt_received(notification_received);222 122 rc = event_subscribe(EVENT_KLOG, 0); 223 123 if (rc != EOK) { … … 227 127 } 228 128 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)); 235 137 236 fibril_add_ready(fid); 237 event_unmask(EVENT_KLOG); 138 async_set_interrupt_received(interrupt_received); 238 139 klog_update(); 239 240 task_retval(0);241 140 async_manager(); 242 141
Note:
See TracChangeset
for help on using the changeset viewer.