Changes in kernel/generic/src/ipc/event.c [228e490:0fe52ef] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/ipc/event.c
r228e490 r0fe52ef 36 36 37 37 #include <ipc/event.h> 38 #include <ipc/event_types.h>39 38 #include <mm/slab.h> 40 39 #include <typedefs.h> 41 40 #include <synch/spinlock.h> 42 41 #include <console/console.h> 42 #include <proc/task.h> 43 43 #include <memstr.h> 44 44 #include <errno.h> … … 48 48 static event_t events[EVENT_END]; 49 49 50 /** Initialize kernel events. */ 50 static void event_initialize(event_t *event) 51 { 52 spinlock_initialize(&event->lock, "event.lock"); 53 event->answerbox = NULL; 54 event->counter = 0; 55 event->imethod = 0; 56 event->masked = false; 57 event->unmask_callback = NULL; 58 } 59 60 static event_t *evno2event(int evno, task_t *t) 61 { 62 ASSERT(evno < EVENT_TASK_END); 63 64 event_t *event; 65 66 if (evno < EVENT_END) 67 event = &events[(event_type_t) evno]; 68 else 69 event = &t->events[(event_task_type_t) evno - EVENT_END]; 70 71 return event; 72 } 73 74 /** Initialize kernel events. 75 * 76 */ 51 77 void event_init(void) 52 78 { 53 unsigned int i; 54 55 for (i = 0; i < EVENT_END; i++) { 56 spinlock_initialize(&events[i].lock, "event.lock"); 57 events[i].answerbox = NULL; 58 events[i].counter = 0; 59 events[i].imethod = 0; 60 } 61 } 62 63 static int event_subscribe(event_type_t evno, sysarg_t imethod, 64 answerbox_t *answerbox) 65 { 66 if (evno >= EVENT_END) 67 return ELIMIT; 68 69 spinlock_lock(&events[evno].lock); 70 71 int res; 72 73 if (events[evno].answerbox == NULL) { 74 events[evno].answerbox = answerbox; 75 events[evno].imethod = imethod; 76 events[evno].counter = 0; 77 res = EOK; 78 } else 79 res = EEXISTS; 80 81 spinlock_unlock(&events[evno].lock); 82 83 return res; 84 } 85 86 sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod) 87 { 88 return (sysarg_t) event_subscribe((event_type_t) evno, (sysarg_t) 89 imethod, &TASK->answerbox); 90 } 91 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 79 for (unsigned int i = 0; i < EVENT_END; i++) 80 event_initialize(evno2event(i, NULL)); 81 } 82 83 void event_task_init(task_t *task) 84 { 85 for (unsigned int i = EVENT_END; i < EVENT_TASK_END; i++) 86 event_initialize(evno2event(i, task)); 87 } 88 89 90 /** Unsubscribe kernel events associated with an answerbox 91 * 92 * @param answerbox Answerbox to be unsubscribed. 93 * 94 */ 106 95 void event_cleanup_answerbox(answerbox_t *answerbox) 107 96 { 108 unsigned int i; 109 110 for (i = 0; i < EVENT_END; i++) { 97 for (unsigned int i = 0; i < EVENT_END; i++) { 111 98 spinlock_lock(&events[i].lock); 99 112 100 if (events[i].answerbox == answerbox) { 113 101 events[i].answerbox = NULL; 114 102 events[i].counter = 0; 115 103 events[i].imethod = 0; 104 events[i].masked = false; 116 105 } 106 117 107 spinlock_unlock(&events[i].lock); 118 108 } 119 109 } 120 110 121 void event_notify(event_type_t evno, sysarg_t a1, sysarg_t a2, sysarg_t a3, 122 sysarg_t a4, sysarg_t a5) 111 static void _event_set_unmask_callback(event_t *event, event_callback_t callback) 112 { 113 spinlock_lock(&event->lock); 114 event->unmask_callback = callback; 115 spinlock_unlock(&event->lock); 116 } 117 118 /** Define a callback function for the event unmask event. 119 * 120 * @param evno Event type. 121 * @param callback Callback function to be called when 122 * the event is unmasked. 123 * 124 */ 125 void event_set_unmask_callback(event_type_t evno, event_callback_t callback) 123 126 { 124 127 ASSERT(evno < EVENT_END); 125 128 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); 129 _event_set_unmask_callback(evno2event(evno, NULL), callback); 130 } 131 132 void event_task_set_unmask_callback(task_t *task, event_task_type_t evno, 133 event_callback_t callback) 134 { 135 ASSERT(evno >= (int) EVENT_END); 136 ASSERT(evno < EVENT_TASK_END); 137 138 _event_set_unmask_callback(evno2event(evno, task), callback); 139 } 140 141 static int event_enqueue(event_t *event, bool mask, sysarg_t a1, sysarg_t a2, 142 sysarg_t a3, sysarg_t a4, sysarg_t a5) 143 { 144 int res; 145 146 spinlock_lock(&event->lock); 147 148 if (event->answerbox != NULL) { 149 if (!event->masked) { 150 call_t *call = ipc_call_alloc(FRAME_ATOMIC); 138 151 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); 152 if (call) { 153 call->flags |= IPC_CALL_NOTIF; 154 call->priv = ++event->counter; 155 156 IPC_SET_IMETHOD(call->data, event->imethod); 157 IPC_SET_ARG1(call->data, a1); 158 IPC_SET_ARG2(call->data, a2); 159 IPC_SET_ARG3(call->data, a3); 160 IPC_SET_ARG4(call->data, a4); 161 IPC_SET_ARG5(call->data, a5); 162 163 call->data.task_id = TASK ? TASK->taskid : 0; 164 165 irq_spinlock_lock(&event->answerbox->irq_lock, true); 166 list_append(&call->link, &event->answerbox->irq_notifs); 167 irq_spinlock_unlock(&event->answerbox->irq_lock, true); 168 169 waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST); 170 171 if (mask) 172 event->masked = true; 173 174 res = EOK; 175 } else 176 res = ENOMEM; 177 } else 178 res = EBUSY; 179 } else 180 res = ENOENT; 181 182 spinlock_unlock(&event->lock); 183 return res; 184 } 185 186 /** Send kernel notification event 187 * 188 * @param evno Event type. 189 * @param mask Mask further notifications after a successful 190 * sending. 191 * @param a1 First argument. 192 * @param a2 Second argument. 193 * @param a3 Third argument. 194 * @param a4 Fourth argument. 195 * @param a5 Fifth argument. 196 * 197 * @return EOK if notification was successfully sent. 198 * @return ENOMEM if the notification IPC message failed to allocate. 199 * @return EBUSY if the notifications of the given type are 200 * currently masked. 201 * @return ENOENT if the notifications of the given type are 202 * currently not subscribed. 203 * 204 */ 205 int event_notify(event_type_t evno, bool mask, sysarg_t a1, sysarg_t a2, 206 sysarg_t a3, sysarg_t a4, sysarg_t a5) 207 { 208 ASSERT(evno < EVENT_END); 209 210 return event_enqueue(evno2event(evno, NULL), mask, a1, a2, a3, a4, a5); 211 } 212 213 /** Send per-task kernel notification event 214 * 215 * @param task Destination task. 216 * @param evno Event type. 217 * @param mask Mask further notifications after a successful 218 * sending. 219 * @param a1 First argument. 220 * @param a2 Second argument. 221 * @param a3 Third argument. 222 * @param a4 Fourth argument. 223 * @param a5 Fifth argument. 224 * 225 * @return EOK if notification was successfully sent. 226 * @return ENOMEM if the notification IPC message failed to allocate. 227 * @return EBUSY if the notifications of the given type are 228 * currently masked. 229 * @return ENOENT if the notifications of the given type are 230 * currently not subscribed. 231 * 232 */ 233 int event_task_notify(task_t *task, event_task_type_t evno, bool mask, 234 sysarg_t a1, sysarg_t a2, sysarg_t a3, sysarg_t a4, sysarg_t a5) 235 { 236 ASSERT(evno >= (int) EVENT_END); 237 ASSERT(evno < EVENT_TASK_END); 238 239 return event_enqueue(evno2event(evno, task), mask, a1, a2, a3, a4, a5); 240 } 241 242 /** Subscribe event notifications 243 * 244 * @param evno Event type. 245 * @param imethod IPC interface and method to be used for 246 * the notifications. 247 * @param answerbox Answerbox to send the notifications to. 248 * 249 * @return EOK if the subscription was successful. 250 * @return EEXISTS if the notifications of the given type are 251 * already subscribed. 252 * 253 */ 254 static int event_subscribe(event_t *event, sysarg_t imethod, 255 answerbox_t *answerbox) 256 { 257 int res; 258 259 spinlock_lock(&event->lock); 260 261 if (event->answerbox == NULL) { 262 event->answerbox = answerbox; 263 event->imethod = imethod; 264 event->counter = 0; 265 event->masked = false; 266 res = EOK; 267 } else 268 res = EEXISTS; 269 270 spinlock_unlock(&event->lock); 271 272 return res; 273 } 274 275 /** Unmask event notifications 276 * 277 * @param evno Event type to unmask. 278 * 279 */ 280 static void event_unmask(event_t *event) 281 { 282 spinlock_lock(&event->lock); 283 event->masked = false; 284 event_callback_t callback = event->unmask_callback; 285 spinlock_unlock(&event->lock); 286 287 /* 288 * Check if there is an unmask callback 289 * function defined for this event. 290 */ 291 if (callback != NULL) 292 callback(event); 293 } 294 295 /** Event notification syscall wrapper 296 * 297 * @param evno Event type to subscribe. 298 * @param imethod IPC interface and method to be used for 299 * the notifications. 300 * 301 * @return EOK on success. 302 * @return ELIMIT on unknown event type. 303 * @return EEXISTS if the notifications of the given type are 304 * already subscribed. 305 * 306 */ 307 sysarg_t sys_event_subscribe(sysarg_t evno, sysarg_t imethod) 308 { 309 if (evno >= EVENT_TASK_END) 310 return ELIMIT; 311 312 return (sysarg_t) event_subscribe(evno2event(evno, TASK), 313 (sysarg_t) imethod, &TASK->answerbox); 314 } 315 316 /** Event notification unmask syscall wrapper 317 * 318 * Note that currently no tests are performed whether the calling 319 * task is entitled to unmask the notifications. However, thanks 320 * to the fact that notification masking is only a performance 321 * optimization, this has probably no security implications. 322 * 323 * @param evno Event type to unmask. 324 * 325 * @return EOK on success. 326 * @return ELIMIT on unknown event type. 327 * 328 */ 329 sysarg_t sys_event_unmask(sysarg_t evno) 330 { 331 if (evno >= EVENT_TASK_END) 332 return ELIMIT; 333 334 event_unmask(evno2event(evno, TASK)); 335 336 return EOK; 147 337 } 148 338
Note:
See TracChangeset
for help on using the changeset viewer.