source: mainline/kernel/generic/src/ipc/event.c@ f1380b7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1380b7 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Copyright (c) 2009 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup generic
30 * @{
31 */
32/**
33 * @file
34 * @brief Kernel event notifications.
35 */
36
37#include <assert.h>
38#include <ipc/event.h>
39#include <mm/slab.h>
40#include <typedefs.h>
41#include <synch/spinlock.h>
42#include <console/console.h>
43#include <proc/task.h>
44#include <errno.h>
45#include <arch.h>
46
47/** The events array. */
48static event_t events[EVENT_END];
49
50static 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
60static event_t *evno2event(int evno, task_t *task)
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 = &task->events[(event_task_type_t) evno - EVENT_END];
70
71 return event;
72}
73
74/** Initialize kernel events.
75 *
76 */
77void event_init(void)
78{
79 for (unsigned int i = 0; i < EVENT_END; i++)
80 event_initialize(evno2event(i, NULL));
81}
82
83void 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/** Unsubscribe kernel events associated with an answerbox
90 *
91 * @param answerbox Answerbox to be unsubscribed.
92 *
93 */
94void event_cleanup_answerbox(answerbox_t *answerbox)
95{
96 for (unsigned int i = 0; i < EVENT_END; i++) {
97 spinlock_lock(&events[i].lock);
98
99 if (events[i].answerbox == answerbox) {
100 events[i].answerbox = NULL;
101 events[i].counter = 0;
102 events[i].imethod = 0;
103 events[i].masked = false;
104 }
105
106 spinlock_unlock(&events[i].lock);
107 }
108}
109
110static void _event_set_unmask_callback(event_t *event, event_callback_t callback)
111{
112 spinlock_lock(&event->lock);
113 event->unmask_callback = callback;
114 spinlock_unlock(&event->lock);
115}
116
117/** Define a callback function for the event unmask event.
118 *
119 * @param evno Event type.
120 * @param callback Callback function to be called when
121 * the event is unmasked.
122 *
123 */
124void event_set_unmask_callback(event_type_t evno, event_callback_t callback)
125{
126 assert(evno < EVENT_END);
127
128 _event_set_unmask_callback(evno2event(evno, NULL), callback);
129}
130
131void event_task_set_unmask_callback(task_t *task, event_task_type_t evno,
132 event_callback_t callback)
133{
134 assert(evno >= (int) EVENT_END);
135 assert(evno < EVENT_TASK_END);
136
137 _event_set_unmask_callback(evno2event(evno, task), callback);
138}
139
140static errno_t event_enqueue(event_t *event, bool mask, sysarg_t a1, sysarg_t a2,
141 sysarg_t a3, sysarg_t a4, sysarg_t a5)
142{
143 errno_t res;
144
145 spinlock_lock(&event->lock);
146
147 if (event->answerbox != NULL) {
148 if (!event->masked) {
149 call_t *call = ipc_call_alloc(FRAME_ATOMIC);
150
151 if (call) {
152 call->flags |= IPC_CALL_NOTIF;
153 call->priv = ++event->counter;
154
155 IPC_SET_IMETHOD(call->data, event->imethod);
156 IPC_SET_ARG1(call->data, a1);
157 IPC_SET_ARG2(call->data, a2);
158 IPC_SET_ARG3(call->data, a3);
159 IPC_SET_ARG4(call->data, a4);
160 IPC_SET_ARG5(call->data, a5);
161
162 call->data.task_id = TASK ? TASK->taskid : 0;
163
164 irq_spinlock_lock(&event->answerbox->irq_lock,
165 true);
166 list_append(&call->ab_link,
167 &event->answerbox->irq_notifs);
168 irq_spinlock_unlock(&event->answerbox->irq_lock,
169 true);
170
171 waitq_wakeup(&event->answerbox->wq,
172 WAKEUP_FIRST);
173
174 if (mask)
175 event->masked = true;
176
177 res = EOK;
178 } else
179 res = ENOMEM;
180 } else
181 res = EBUSY;
182 } else
183 res = ENOENT;
184
185 spinlock_unlock(&event->lock);
186 return res;
187}
188
189/** Send kernel notification event
190 *
191 * @param evno Event type.
192 * @param mask Mask further notifications after a successful
193 * sending.
194 * @param a1 First argument.
195 * @param a2 Second argument.
196 * @param a3 Third argument.
197 * @param a4 Fourth argument.
198 * @param a5 Fifth argument.
199 *
200 * @return EOK if notification was successfully sent.
201 * @return ENOMEM if the notification IPC message failed to allocate.
202 * @return EBUSY if the notifications of the given type are
203 * currently masked.
204 * @return ENOENT if the notifications of the given type are
205 * currently not subscribed.
206 *
207 */
208errno_t event_notify(event_type_t evno, bool mask, sysarg_t a1, sysarg_t a2,
209 sysarg_t a3, sysarg_t a4, sysarg_t a5)
210{
211 assert(evno < EVENT_END);
212
213 return event_enqueue(evno2event(evno, NULL), mask, a1, a2, a3, a4, a5);
214}
215
216/** Send per-task kernel notification event
217 *
218 * @param task Destination task.
219 * @param evno Event type.
220 * @param mask Mask further notifications after a successful
221 * sending.
222 * @param a1 First argument.
223 * @param a2 Second argument.
224 * @param a3 Third argument.
225 * @param a4 Fourth argument.
226 * @param a5 Fifth argument.
227 *
228 * @return EOK if notification was successfully sent.
229 * @return ENOMEM if the notification IPC message failed to allocate.
230 * @return EBUSY if the notifications of the given type are
231 * currently masked.
232 * @return ENOENT if the notifications of the given type are
233 * currently not subscribed.
234 *
235 */
236errno_t event_task_notify(task_t *task, event_task_type_t evno, bool mask,
237 sysarg_t a1, sysarg_t a2, sysarg_t a3, sysarg_t a4, sysarg_t a5)
238{
239 assert(evno >= (int) EVENT_END);
240 assert(evno < EVENT_TASK_END);
241
242 return event_enqueue(evno2event(evno, task), mask, a1, a2, a3, a4, a5);
243}
244
245/** Subscribe event notifications
246 *
247 * @param evno Event type.
248 * @param imethod IPC interface and method to be used for
249 * the notifications.
250 * @param answerbox Answerbox to send the notifications to.
251 *
252 * @return EOK if the subscription was successful.
253 * @return EEXIST if the notifications of the given type are
254 * already subscribed.
255 *
256 */
257static errno_t event_subscribe(event_t *event, sysarg_t imethod,
258 answerbox_t *answerbox)
259{
260 errno_t res;
261
262 spinlock_lock(&event->lock);
263
264 if (event->answerbox == NULL) {
265 event->answerbox = answerbox;
266 event->imethod = imethod;
267 event->counter = 0;
268 event->masked = false;
269 res = EOK;
270 } else
271 res = EEXIST;
272
273 spinlock_unlock(&event->lock);
274
275 return res;
276}
277
278/** Unsubscribe event notifications
279 *
280 * @param evno Event type.
281 * @param answerbox Answerbox used to send the notifications to.
282 *
283 * @return EOK if the subscription was successful.
284 * @return EEXIST if the notifications of the given type are
285 * already subscribed.
286 *
287 */
288static errno_t event_unsubscribe(event_t *event, answerbox_t *answerbox)
289{
290 errno_t res;
291
292 spinlock_lock(&event->lock);
293
294 if (event->answerbox == answerbox) {
295 event->answerbox = NULL;
296 event->counter = 0;
297 event->imethod = 0;
298 event->masked = false;
299 res = EOK;
300 } else
301 res = ENOENT;
302
303 spinlock_unlock(&event->lock);
304
305 return res;
306}
307
308/** Unmask event notifications
309 *
310 * @param evno Event type to unmask.
311 *
312 */
313static void event_unmask(event_t *event)
314{
315 spinlock_lock(&event->lock);
316 event->masked = false;
317 event_callback_t callback = event->unmask_callback;
318 spinlock_unlock(&event->lock);
319
320 /*
321 * Check if there is an unmask callback
322 * function defined for this event.
323 */
324 if (callback != NULL)
325 callback(event);
326}
327
328/** Event notification subscription syscall wrapper
329 *
330 * @param evno Event type to subscribe.
331 * @param imethod IPC interface and method to be used for
332 * the notifications.
333 *
334 * @return EOK on success.
335 * @return ELIMIT on unknown event type.
336 * @return EEXIST if the notifications of the given type are
337 * already subscribed.
338 *
339 */
340sys_errno_t sys_ipc_event_subscribe(sysarg_t evno, sysarg_t imethod)
341{
342 if (evno >= EVENT_TASK_END)
343 return ELIMIT;
344
345 return (sys_errno_t) event_subscribe(evno2event(evno, TASK),
346 (sysarg_t) imethod, &TASK->answerbox);
347}
348
349/** Event notification unsubscription syscall wrapper
350 *
351 * @param evno Event type to unsubscribe.
352 *
353 * @return EOK on success.
354 * @return ELIMIT on unknown event type.
355 * @return ENOENT if the notification of the given type is not
356 subscribed.
357 *
358 */
359sys_errno_t sys_ipc_event_unsubscribe(sysarg_t evno)
360{
361 if (evno >= EVENT_TASK_END)
362 return ELIMIT;
363
364 return (sys_errno_t) event_unsubscribe(evno2event(evno, TASK),
365 &TASK->answerbox);
366}
367
368/** Event notification unmask syscall wrapper
369 *
370 * Note that currently no tests are performed whether the calling
371 * task is entitled to unmask the notifications. However, thanks
372 * to the fact that notification masking is only a performance
373 * optimization, this has probably no security implications.
374 *
375 * @param evno Event type to unmask.
376 *
377 * @return EOK on success.
378 * @return ELIMIT on unknown event type.
379 *
380 */
381sys_errno_t sys_ipc_event_unmask(sysarg_t evno)
382{
383 if (evno >= EVENT_TASK_END)
384 return ELIMIT;
385
386 event_unmask(evno2event(evno, TASK));
387
388 return EOK;
389}
390
391/** @}
392 */
Note: See TracBrowser for help on using the repository browser.