kernel
Loading...
Searching...
No Matches
events.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: GPLv3
4 * PURPOSE: Events Implementation (see KeSetEvent and KMUTANT in MSDN)
5 */
6
7#include "../../includes/me.h"
8#include "../../includes/ps.h"
9#include "../../includes/mg.h"
10#include "../../assert.h"
11
14 IN PEVENT event
15)
16
17/*++
18
19 Routine description :
20
21 Sets an event to wake threads waiting on it.
22
23 Arguments:
24
25 Pointer to EVENT object.
26
27 Return Values:
28
29 Varuious MTSTATUS Codes.
30
31--*/
32
33{
34 if (!event) return MT_INVALID_ADDRESS;
35
36 // NOTE: (TODO) Can we use push locks here? Events should only be used in PASSIVE_LEVEL to APC_LEVEL IRQL contexts,
37 // holding a lock to raise to DISPATCH_LEVEL just delays us furthermore..
38 IRQL flags;
39 MsAcquireSpinlock(&event->lock, &flags);
40
41 if (event->type == SynchronizationEvent) {
42 // Wake exactly one waiter (auto-reset)
43 PETHREAD waiter = MeDequeueThread(&event->waitingQueue); // safe under event->lock
44 if (waiter) {
45 event->signaled = false; // consumed by waking one waiter
46 MsReleaseSpinlock(&event->lock, flags);
47
49 MeEnqueueThreadWithLock(&MeGetCurrentProcessor()->readyQueue, waiter);
50 return MT_SUCCESS;
51 }
52 else {
53 // No waiter -> mark event signaled so next waiter won't block
54 event->signaled = true;
55 MsReleaseSpinlock(&event->lock, flags);
56 return MT_SUCCESS;
57 }
58 }
59
60 // NotificationEvent: drain waiters into local list while holding event lock
61 PETHREAD head = NULL;
62 PETHREAD tail = NULL;
63 PETHREAD t;
64
65 while ((t = MeDequeueThread(&event->waitingQueue)) != NULL) {
66 // Detach the thread from any previous list by nulling its links
67 t->ThreadListEntry.Flink = NULL;
68 t->ThreadListEntry.Blink = NULL;
69
70 // Build the local singly-linked list (head/tail) using Flink
71 if (tail) {
72 // Link the current tail to the new thread via Flink
74 // Set the new thread's Blink to the old tail (for local list integrity)
76 }
77 else {
78 // First thread
79 head = t;
80 // First thread's Blink should be NULL
81 t->ThreadListEntry.Blink = NULL;
82 }
83
84 // The new tail is 't'
85 tail = t;
86 }
87
88 // Notification persists until reset
89 event->signaled = true;
90 MsReleaseSpinlock(&event->lock, flags);
91
92 // Enqueue drained threads to scheduler (after releasing event lock)
93 t = head;
94 while (t) {
95 // Get the next thread pointer by reading the Flink, then CONTAINING_RECORD
96 struct _DOUBLY_LINKED_LIST* nxtEntry = t->ThreadListEntry.Flink;
97
98 // Set thread state
100
101 // Enqueue
103
104 // Move to the next thread
105 if (nxtEntry) {
106 t = CONTAINING_RECORD(nxtEntry, ETHREAD, ThreadListEntry);
107 }
108 else {
109 t = NULL;
110 }
111 }
112
113 return MT_SUCCESS;
114}
115
118 IN PEVENT event
119)
120
121/*++
122
123 Routine description :
124
125 Sleeps the current thread to wait on the specified event.
126
127 Arguments:
128
129 Pointer to EVENT Object.
130
131 Return Values:
132
133 MT_SUCCESS on wake, other MTSTATUS codes for failure.
134
135 Notes:
136
137 This function MUST NOT be called on IRQL higher or equal to DISPATCH_LEVEL, as this function is blocking or uses pageable memory.
138
139--*/
140
141{
142 if (!event) return MT_INVALID_ADDRESS;
143 assert((MeGetCurrentIrql() < DISPATCH_LEVEL), "Blocking function called with DISPATCH_LEVEL IRQL or Higher.");
144 IRQL flags;
146
147 // Acquire event lock to check signaled state atomically with enqueue.
148 MsAcquireSpinlock(&event->lock, &flags);
149
150 // If already signaled, consume or accept depending on type:
151 if (event->signaled) {
152 if (event->type == SynchronizationEvent) {
153 // consume the single-signaled state
154 event->signaled = false;
155 }
156 // For NotificationEvent, leave event->signaled = true (notification persists)
157 MsReleaseSpinlock(&event->lock, flags);
158 return MT_SUCCESS;
159 }
160
161 // Block the thread. When MtSetEvent wakes it, it will be placed on ready queue.
163 curr->CurrentEvent = event;
164 // Not signaled -> enqueue this thread into the event waiting queue (under event lock)
165 MeEnqueueThread(&event->waitingQueue, curr);
166 // Keep event lock held only for enqueue; after this we release and block.
167 MsReleaseSpinlock(&event->lock, flags);
168#ifdef DEBUG
169 gop_printf(COLOR_PURPLE, "Sleeping current thread: %p\n", PsGetCurrentThread());
170#endif
173
174 // When we resume here, the waker has already moved us to the ready queue, and we are now an active thread on the CPU.
175 return MT_SUCCESS;
176}
177
#define IN
Definition annotations.h:8
#define assert(...)
Definition assert.h:57
@ DISPATCH_LEVEL
Definition core.h:17
enum _IRQL IRQL
struct _ETHREAD ETHREAD
Definition core.h:43
ETHREAD * PETHREAD
Definition core.h:44
MTSTATUS MsWaitForEvent(IN PEVENT event)
Definition events.c:117
MTSTATUS MsSetEvent(IN PEVENT event)
Definition events.c:13
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:633
#define CONTAINING_RECORD(ptr, type, member)
Definition macros.h:11
FORCEINLINE IRQL MeGetCurrentIrql(void)
Definition me.h:415
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:369
#define COLOR_PURPLE
Definition mg.h:43
uint32_t flags
Definition mh.h:2
struct _EVENT * PEVENT
@ SynchronizationEvent
Definition ms.h:63
#define MT_SUCCESS
Definition mtstatus.h:22
#define MT_INVALID_ADDRESS
Definition mtstatus.h:46
int32_t MTSTATUS
Definition mtstatus.h:12
FORCEINLINE void MeEnqueueThreadWithLock(Queue *queue, PETHREAD thread)
Definition ps.h:385
FORCEINLINE void MeEnqueueThread(Queue *queue, PETHREAD thread)
Definition ps.h:452
void MsYieldExecution(PTRAP_FRAME threadRegisters)
@ THREAD_BLOCKED
Definition ps.h:40
@ THREAD_READY
Definition ps.h:39
FORCEINLINE PETHREAD MeDequeueThread(Queue *q)
Definition ps.h:475
void MsAcquireSpinlock(IN PSPINLOCK lock, IN PIRQL OldIrql)
Definition spinlock.c:13
void MsReleaseSpinlock(IN PSPINLOCK lock, IN IRQL OldIrql)
Definition spinlock.c:45
struct _DOUBLY_LINKED_LIST * Blink
Definition core.h:30
struct _DOUBLY_LINKED_LIST * Flink
Definition core.h:31
struct _ITHREAD InternalThread
Definition ps.h:183
struct _EVENT * CurrentEvent
Definition ps.h:189
struct _DOUBLY_LINKED_LIST ThreadListEntry
Definition ps.h:191
uint32_t ThreadState
Definition me.h:268
struct _TRAP_FRAME TrapRegisters
Definition me.h:267
PETHREAD PsGetCurrentThread(void)
Definition thread.c:279