1 // Copyright (c) 2008-2014 Travis Geiselbrecht
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 #pragma once
7 
8 #include <kernel/thread.h>
9 #include <lk/compiler.h>
10 #include <stdbool.h>
11 #include <sys/types.h>
12 #include <stdint.h>
13 
14 // This file defines the kernel event, which is a synchronization primitive
15 // that allows threads to wait for an event to be signaled. It is primarily used
16 // for inter-thread communication and synchronization.
17 
18 __BEGIN_CDECLS
19 
20 // Rules for Events:
21 // - Events may be signaled from interrupt context *but* the reschedule
22 //   parameter must be false in that case.
23 // - Events may not be waited upon from interrupt context.
24 // - Events without FLAG_AUTOUNSIGNAL:
25 //   - Wake up any waiting threads when signaled.
26 //   - Continue to do so (no threads will wait) until unsignaled.
27 // - Events with FLAG_AUTOUNSIGNAL:
28 //   - If one or more threads are waiting when signaled, one thread will
29 //     be woken up and return.  The signaled state will not be set.
30 //   - If no threads are waiting when signaled, the Event will remain
31 //     in the signaled state until a thread attempts to wait (at which
32 //     time it will unsignal atomicly and return immediately) or
33 //     event_unsignal() is called.
34 
35 #define EVENT_MAGIC (0x65766E74)  // "evnt"
36 
37 typedef struct event {
38     uint32_t magic;
39     bool signaled;
40     uint flags;
41     wait_queue_t wait;
42 } event_t;
43 
44 #define EVENT_FLAG_AUTOUNSIGNAL 1
45 
46 // Initializer for an event structure. Events may be initialized with a
47 // non-signaled state, or a signaled state. The flags parameter can be used
48 // to specify additional behavior, such as FLAG_AUTOUNSIGNAL.
49 #define EVENT_INITIAL_VALUE(e, initial, _flags) \
50 { \
51     .magic = EVENT_MAGIC, \
52     .signaled = (initial), \
53     .flags = (_flags), \
54     .wait = WAIT_QUEUE_INITIAL_VALUE((e).wait), \
55 }
56 
57 // Dynamically initialize an event structure.
58 void event_init(event_t *, bool initial, uint flags);
59 
60 // Check if an event is initialized.
event_initialized(event_t * e)61 static inline bool event_initialized(event_t *e) {
62     return e->magic == EVENT_MAGIC;
63 }
64 
65 // Destroy an event. Any threads waiting on the event will be woken up
66 // with an error status.
67 void event_destroy(event_t *);
68 
69 // Wait on the event until it is signaled or a timeout occurs.
70 // If timeout is INFINITE_TIME, it will wait indefinitely.
71 // If timeout is 0, it will return immediately if it is unable to acquire the event.
72 // Returns an error status if the event is not signaled within the timeout period.
73 // If the event is signaled, it will return NO_ERROR.
74 status_t event_wait_timeout(event_t *, lk_time_t);
75 
76 // Signal the event, waking up any threads waiting on it.
77 // If reschedule is true, it will reschedule the thread that was waiting.
78 // May be called during interrupt context, but in that case reschedule must be false.
79 status_t event_signal(event_t *, bool reschedule);
80 
81 // Unsignal the event, clearing its signaled state.
82 status_t event_unsignal(event_t *);
83 
84 // Shortcut for waiting for an event indefinitely.
event_wait(event_t * e)85 static inline status_t event_wait(event_t *e) {
86     return event_wait_timeout(e, INFINITE_TIME);
87 }
88 
89 __END_CDECLS
90