Changes in / [8d308b9:0d8a304] in mainline
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/include/ipc/event.h
r8d308b9 r0d8a304 51 51 /** Counter. */ 52 52 size_t counter; 53 /** Masked flag. */ 54 bool masked; 55 /** Unmask callback. */ 56 void (*unmask_cb)(void); 53 57 } event_t; 54 58 55 59 extern void event_init(void); 60 extern void event_cleanup_answerbox(answerbox_t *); 61 extern void event_set_unmask_callback(event_type_t, void (*)(void)); 62 63 #define event_notify_0(e, m) \ 64 event_notify((e), (m), 0, 0, 0, 0, 0) 65 #define event_notify_1(e, m, a1) \ 66 event_notify((e), (m), (a1), 0, 0, 0, 0) 67 #define event_notify_2(e, m, a1, a2) \ 68 event_notify((e), (m), (a1), (a2), 0, 0, 0) 69 #define event_notify_3(e, m, a1, a2, a3) \ 70 event_notify((e), (m), (a1), (a2), (a3), 0, 0) 71 #define event_notify_4(e, m, a1, a2, a3, a4) \ 72 event_notify((e), (m), (a1), (a2), (a3), (a4), 0) 73 #define event_notify_5(e, m, a1, a2, a3, a4, a5) \ 74 event_notify((e), (m), (a1), (a2), (a3), (a4), (a5)) 75 76 extern int event_notify(event_type_t, bool, sysarg_t, sysarg_t, sysarg_t, 77 sysarg_t, sysarg_t); 78 56 79 extern sysarg_t sys_event_subscribe(sysarg_t, sysarg_t); 57 extern bool event_is_subscribed(event_type_t); 58 extern void event_cleanup_answerbox(answerbox_t *); 59 60 #define event_notify_0(e) \ 61 event_notify((e), 0, 0, 0, 0, 0) 62 #define event_notify_1(e, a1) \ 63 event_notify((e), (a1), 0, 0, 0, 0) 64 #define event_notify_2(e, a1, a2) \ 65 event_notify((e), (a1), (a2), 0, 0, 0) 66 #define event_notify_3(e, a1, a2, a3) \ 67 event_notify((e), (a1), (a2), (a3), 0, 0) 68 #define event_notify_4(e, a1, a2, a3, a4) \ 69 event_notify((e), (a1), (a2), (a3), (a4), 0) 70 #define event_notify_5(e, a1, a2, a3, a4, a5) \ 71 event_notify((e), (a1), (a2), (a3), (a4), (a5)) 72 73 extern void event_notify(event_type_t, sysarg_t, sysarg_t, sysarg_t, 74 sysarg_t, sysarg_t); 80 extern sysarg_t sys_event_unmask(sysarg_t); 75 81 76 82 #endif -
kernel/generic/include/ipc/event_types.h
r8d308b9 r0d8a304 39 39 /** New data available in kernel log */ 40 40 EVENT_KLOG = 0, 41 /** Returning from kernel console to us erspace */41 /** Returning from kernel console to uspace */ 42 42 EVENT_KCONSOLE, 43 43 /** A task/thread has faulted and will be terminated */ -
kernel/generic/include/syscall/syscall.h
r8d308b9 r0d8a304 75 75 76 76 SYS_EVENT_SUBSCRIBE, 77 SYS_EVENT_UNMASK, 77 78 78 79 SYS_CAP_GRANT, -
kernel/generic/src/console/cmd.c
r8d308b9 r0d8a304 1107 1107 release_console(); 1108 1108 1109 event_notify_0(EVENT_KCONSOLE );1109 event_notify_0(EVENT_KCONSOLE, false); 1110 1110 indev_pop_character(stdin); 1111 1111 -
kernel/generic/src/console/console.c
r8d308b9 r0d8a304 53 53 #include <str.h> 54 54 55 #define KLOG_PAGES 455 #define KLOG_PAGES 8 56 56 #define KLOG_LENGTH (KLOG_PAGES * PAGE_SIZE / sizeof(wchar_t)) 57 57 #define KLOG_LATENCY 8 … … 165 165 sysinfo_set_item_val("klog.faddr", NULL, (sysarg_t) faddr); 166 166 sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES); 167 168 event_set_unmask_callback(EVENT_KLOG, klog_update); 167 169 168 170 spinlock_lock(&klog_lock); … … 265 267 spinlock_lock(&klog_lock); 266 268 267 if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) { 268 event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace); 269 klog_uspace = 0; 269 if ((klog_inited) && (klog_uspace > 0)) { 270 if (event_notify_3(EVENT_KLOG, true, klog_start, klog_len, 271 klog_uspace) == EOK) 272 klog_uspace = 0; 270 273 } 271 274 -
kernel/generic/src/ipc/event.c
r8d308b9 r0d8a304 48 48 static event_t events[EVENT_END]; 49 49 50 /** Initialize kernel events. */ 50 /** Initialize kernel events. 51 * 52 */ 51 53 void event_init(void) 52 54 { 53 unsigned int i; 54 55 for (i = 0; i < EVENT_END; i++) { 55 for (unsigned int i = 0; i < EVENT_END; i++) { 56 56 spinlock_initialize(&events[i].lock, "event.lock"); 57 57 events[i].answerbox = NULL; 58 58 events[i].counter = 0; 59 59 events[i].imethod = 0; 60 events[i].masked = false; 61 events[i].unmask_cb = NULL; 60 62 } 61 63 } 62 64 65 /** Unsubscribe kernel events associated with an answerbox 66 * 67 * @param answerbox Answerbox to be unsubscribed. 68 * 69 */ 70 void event_cleanup_answerbox(answerbox_t *answerbox) 71 { 72 for (unsigned int i = 0; i < EVENT_END; i++) { 73 spinlock_lock(&events[i].lock); 74 75 if (events[i].answerbox == answerbox) { 76 events[i].answerbox = NULL; 77 events[i].counter = 0; 78 events[i].imethod = 0; 79 events[i].masked = false; 80 } 81 82 spinlock_unlock(&events[i].lock); 83 } 84 } 85 86 /** Define a callback function for the event unmask event. 87 * 88 * @param evno Event type. 89 * @param cb Callback function to be called when the event is unmasked. 90 * 91 */ 92 void event_set_unmask_callback(event_type_t evno, void (*cb)(void)) 93 { 94 ASSERT(evno < EVENT_END); 95 96 spinlock_lock(&events[evno].lock); 97 events[evno].unmask_cb = cb; 98 spinlock_unlock(&events[evno].lock); 99 } 100 101 /** Send kernel notification event 102 * 103 * @param evno Event type. 104 * @param mask Mask further notifications after a successful 105 * sending. 106 * @param a1 First argument. 107 * @param a2 Second argument. 108 * @param a3 Third argument. 109 * @param a4 Fourth argument. 110 * @param a5 Fifth argument. 111 * 112 * @return EOK if notification was successfully sent. 113 * @return ENOMEM if the notification IPC message failed to allocate. 114 * @return EBUSY if the notifications of the given type are 115 * currently masked. 116 * @return ENOENT if the notifications of the given type are 117 * currently not subscribed. 118 * 119 */ 120 int event_notify(event_type_t evno, bool mask, sysarg_t a1, sysarg_t a2, 121 sysarg_t a3, sysarg_t a4, sysarg_t a5) 122 { 123 ASSERT(evno < EVENT_END); 124 125 spinlock_lock(&events[evno].lock); 126 127 int ret; 128 129 if (events[evno].answerbox != NULL) { 130 if (!events[evno].masked) { 131 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 132 133 if (call) { 134 call->flags |= IPC_CALL_NOTIF; 135 call->priv = ++events[evno].counter; 136 137 IPC_SET_IMETHOD(call->data, events[evno].imethod); 138 IPC_SET_ARG1(call->data, a1); 139 IPC_SET_ARG2(call->data, a2); 140 IPC_SET_ARG3(call->data, a3); 141 IPC_SET_ARG4(call->data, a4); 142 IPC_SET_ARG5(call->data, a5); 143 144 irq_spinlock_lock(&events[evno].answerbox->irq_lock, true); 145 list_append(&call->link, &events[evno].answerbox->irq_notifs); 146 irq_spinlock_unlock(&events[evno].answerbox->irq_lock, true); 147 148 waitq_wakeup(&events[evno].answerbox->wq, WAKEUP_FIRST); 149 150 if (mask) 151 events[evno].masked = true; 152 153 ret = EOK; 154 } else 155 ret = ENOMEM; 156 } else 157 ret = EBUSY; 158 } else 159 ret = ENOENT; 160 161 spinlock_unlock(&events[evno].lock); 162 163 return ret; 164 } 165 166 /** Subscribe event notifications 167 * 168 * @param evno Event type. 169 * @param imethod IPC interface and method to be used for 170 * the notifications. 171 * @param answerbox Answerbox to send the notifications to. 172 * 173 * @return EOK if the subscription was successful. 174 * @return EEXISTS if the notifications of the given type are 175 * already subscribed. 176 * 177 */ 63 178 static int event_subscribe(event_type_t evno, sysarg_t imethod, 64 179 answerbox_t *answerbox) 65 180 { 66 if (evno >= EVENT_END) 67 return ELIMIT; 181 ASSERT(evno < EVENT_END); 68 182 69 183 spinlock_lock(&events[evno].lock); … … 75 189 events[evno].imethod = imethod; 76 190 events[evno].counter = 0; 191 events[evno].masked = false; 77 192 res = EOK; 78 193 } else … … 84 199 } 85 200 201 /** Unmask event notifications 202 * 203 * @param evno Event type to unmask. 204 * 205 */ 206 static void event_unmask(event_type_t evno) 207 { 208 void (*cb)(void); 209 ASSERT(evno < EVENT_END); 210 211 spinlock_lock(&events[evno].lock); 212 events[evno].masked = false; 213 cb = events[evno].unmask_cb; 214 spinlock_unlock(&events[evno].lock); 215 216 /* 217 * Check if there is an unmask callback function defined for this event. 218 */ 219 if (cb) 220 cb(); 221 } 222 223 /** Event notification syscall wrapper 224 * 225 * @param evno Event type to subscribe. 226 * @param imethod IPC interface and method to be used for 227 * the notifications. 228 * 229 * @return EOK on success. 230 * @return ELIMIT on unknown event type. 231 * @return EEXISTS if the notifications of the given type are 232 * already subscribed. 233 * 234 */ 86 235 sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod) 87 236 { 237 if (evno >= EVENT_END) 238 return ELIMIT; 239 88 240 return (sysarg_t) event_subscribe((event_type_t) evno, (sysarg_t) 89 241 imethod, &TASK->answerbox); 90 242 } 91 243 92 bool event_is_subscribed(event_type_t evno) 93 { 94 bool res; 95 96 ASSERT(evno < EVENT_END); 97 98 spinlock_lock(&events[evno].lock); 99 res = events[evno].answerbox != NULL; 100 spinlock_unlock(&events[evno].lock); 101 102 return res; 103 } 104 105 106 void event_cleanup_answerbox(answerbox_t *answerbox) 107 { 108 unsigned int i; 109 110 for (i = 0; i < EVENT_END; i++) { 111 spinlock_lock(&events[i].lock); 112 if (events[i].answerbox == answerbox) { 113 events[i].answerbox = NULL; 114 events[i].counter = 0; 115 events[i].imethod = 0; 116 } 117 spinlock_unlock(&events[i].lock); 118 } 119 } 120 121 void event_notify(event_type_t evno, sysarg_t a1, sysarg_t a2, sysarg_t a3, 122 sysarg_t a4, sysarg_t a5) 123 { 124 ASSERT(evno < EVENT_END); 125 126 spinlock_lock(&events[evno].lock); 127 if (events[evno].answerbox != NULL) { 128 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 129 if (call) { 130 call->flags |= IPC_CALL_NOTIF; 131 call->priv = ++events[evno].counter; 132 IPC_SET_IMETHOD(call->data, events[evno].imethod); 133 IPC_SET_ARG1(call->data, a1); 134 IPC_SET_ARG2(call->data, a2); 135 IPC_SET_ARG3(call->data, a3); 136 IPC_SET_ARG4(call->data, a4); 137 IPC_SET_ARG5(call->data, a5); 138 139 irq_spinlock_lock(&events[evno].answerbox->irq_lock, true); 140 list_append(&call->link, &events[evno].answerbox->irq_notifs); 141 irq_spinlock_unlock(&events[evno].answerbox->irq_lock, true); 142 143 waitq_wakeup(&events[evno].answerbox->wq, WAKEUP_FIRST); 144 } 145 } 146 spinlock_unlock(&events[evno].lock); 244 /** Event notification unmask syscall wrapper 245 * 246 * Note that currently no tests are performed whether the calling 247 * task is entitled to unmask the notifications. However, thanks 248 * to the fact that notification masking is only a performance 249 * optimization, this has probably no security implications. 250 * 251 * @param evno Event type to unmask. 252 * 253 * @return EOK on success. 254 * @return ELIMIT on unknown event type. 255 * 256 */ 257 sysarg_t sys_event_unmask(sysarg_t evno) 258 { 259 if (evno >= EVENT_END) 260 return ELIMIT; 261 262 event_unmask((event_type_t) evno); 263 return EOK; 147 264 } 148 265 -
kernel/generic/src/proc/task.c
r8d308b9 r0d8a304 534 534 */ 535 535 if (notify) { 536 if (event_is_subscribed(EVENT_FAULT)) { 537 /* Notify the subscriber that a fault occurred. */ 538 event_notify_3(EVENT_FAULT, LOWER32(TASK->taskid), 539 UPPER32(TASK->taskid), (sysarg_t) THREAD); 540 536 /* Notify the subscriber that a fault occurred. */ 537 if (event_notify_3(EVENT_FAULT, false, LOWER32(TASK->taskid), 538 UPPER32(TASK->taskid), (sysarg_t) THREAD) == EOK) { 541 539 #ifdef CONFIG_UDEBUG 542 540 /* Wait for a debugging session. */ -
kernel/generic/src/syscall/syscall.c
r8d308b9 r0d8a304 161 161 /* Event notification syscalls. */ 162 162 (syshandler_t) sys_event_subscribe, 163 (syshandler_t) sys_event_unmask, 163 164 164 165 /* Capabilities related syscalls. */ -
uspace/app/klog/klog.c
r8d308b9 r0d8a304 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 * 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); 165 58 166 size_t klog_start = (size_t) IPC_GET_ARG1(*call); 59 167 size_t klog_len = (size_t) IPC_GET_ARG2(*call); 60 168 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 } 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); 76 183 } 77 184 … … 111 218 } 112 219 220 prodcons_initialize(&pc); 221 async_set_interrupt_received(notification_received); 113 222 rc = event_subscribe(EVENT_KLOG, 0); 114 223 if (rc != EOK) { … … 118 227 } 119 228 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); 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); 126 238 klog_update(); 239 240 task_retval(0); 127 241 async_manager(); 128 242 -
uspace/lib/c/Makefile
r8d308b9 r0d8a304 108 108 generic/adt/measured_strings.c \ 109 109 generic/adt/char_map.c \ 110 generic/adt/prodcons.c \ 110 111 generic/time.c \ 111 112 generic/stdlib.c \ -
uspace/lib/c/generic/event.c
r8d308b9 r0d8a304 41 41 #include <kernel/ipc/event_types.h> 42 42 43 /** Subscribe forevent notifications.43 /** Subscribe event notifications. 44 44 * 45 * @param evno Event number.46 * @param method Use thismethod for notifying me.45 * @param evno Event type to subscribe. 46 * @param imethod Use this interface and method for notifying me. 47 47 * 48 48 * @return Value returned by the kernel. 49 * 49 50 */ 50 int event_subscribe(event_type_t e , sysarg_tmethod)51 int event_subscribe(event_type_t evno, sysarg_t imethod) 51 52 { 52 return __SYSCALL2(SYS_EVENT_SUBSCRIBE, (sysarg_t) e, (sysarg_t) method); 53 return __SYSCALL2(SYS_EVENT_SUBSCRIBE, (sysarg_t) evno, 54 (sysarg_t) imethod); 55 } 56 57 /** Unmask event notifications. 58 * 59 * @param evno Event type to unmask. 60 * 61 * @return Value returned by the kernel. 62 * 63 */ 64 int event_unmask(event_type_t evno) 65 { 66 return __SYSCALL1(SYS_EVENT_UNMASK, (sysarg_t) evno); 53 67 } 54 68 -
uspace/lib/c/include/event.h
r8d308b9 r0d8a304 39 39 40 40 extern int event_subscribe(event_type_t, sysarg_t); 41 extern int event_unmask(event_type_t); 41 42 42 43 #endif
Note:
See TracChangeset
for help on using the changeset viewer.