My Project
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 : Sets an event to wake threads waiting on it.
20
21 Arguments:
22
23 Pointer to EVENT object.
24
25 Return Values:
26
27 Varuious MTSTATUS Codes.
28
29--*/
30
31{
32 if (!event) return MT_INVALID_ADDRESS;
33
34 IRQL flags;
35 MsAcquireSpinlock(&event->lock, &flags);
36
37 if (event->type == SynchronizationEvent) {
38 // Wake exactly one waiter (auto-reset)
39 PETHREAD waiter = MeDequeueThread(&event->waitingQueue); // safe under event->lock
40 if (waiter) {
41 event->signaled = false; // consumed by waking one waiter
42 MsReleaseSpinlock(&event->lock, flags);
43
45 MeEnqueueThreadWithLock(&MeGetCurrentProcessor()->readyQueue, waiter);
46 return MT_SUCCESS;
47 }
48 else {
49 // No waiter -> mark event signaled so next waiter won't block
50 event->signaled = true;
51 MsReleaseSpinlock(&event->lock, flags);
52 return MT_SUCCESS;
53 }
54 }
55
56 // NotificationEvent: drain waiters into local list while holding event lock
57 PETHREAD head = NULL;
58 PETHREAD tail = NULL;
59 PETHREAD t;
60
61 while ((t = MeDequeueThread(&event->waitingQueue)) != NULL) {
62 // 1. Detach the thread from any previous list by nulling its links
63 t->ThreadListEntry.Flink = NULL;
64 t->ThreadListEntry.Blink = NULL;
65
66 // 2. Build the local singly-linked list (head/tail) using Flink
67 if (tail) {
68 // Link the current tail to the new thread via Flink
70 // Optionally: Set the new thread's Blink to the old tail (for local list integrity)
72 }
73 else {
74 // First thread
75 head = t;
76 // First thread's Blink should be NULL
77 t->ThreadListEntry.Blink = NULL;
78 }
79
80 // The new tail is 't'
81 tail = t;
82 }
83
84 // Notification persists until reset
85 event->signaled = true;
86 MsReleaseSpinlock(&event->lock, flags);
87
88 // Enqueue drained threads to scheduler (after releasing event lock)
89 t = head;
90 while (t) {
91 // Get the next thread pointer by reading the Flink, then CONTAINING_RECORD
92 struct _DOUBLY_LINKED_LIST* nxtEntry = t->ThreadListEntry.Flink;
93
94 // Set thread state
96
97 // Enqueue
99
100 // Move to the next thread
101 if (nxtEntry) {
102 t = CONTAINING_RECORD(nxtEntry, ETHREAD, ThreadListEntry);
103 }
104 else {
105 t = NULL;
106 }
107 }
108
109 return MT_SUCCESS;
110}
111
114 IN PEVENT event
115)
116
117/*++
118
119 Routine description : Sleeps the current thread to wait on the specified event.
120
121 Arguments:
122
123 Pointer to EVENT Object.
124
125 Return Values:
126
127 MT_SUCCESS on wake, other MTSTATUS codes for failure.
128
129 Notes:
130
131 This function MUST NOT be called on IRQL higher or equal to DISPATCH_LEVEL, as this function is blocking or uses pageable memory.
132
133--*/
134
135{
136 if (!event) return MT_INVALID_ADDRESS;
137 assert((MeGetCurrentIrql() < DISPATCH_LEVEL), "Blocking function called with DISPATCH_LEVEL IRQL or Higher.");
138 IRQL flags;
140
141 // Acquire event lock to check signaled state atomically with enqueue.
142 MsAcquireSpinlock(&event->lock, &flags);
143
144 // If already signaled, consume or accept depending on type:
145 if (event->signaled) {
146 if (event->type == SynchronizationEvent) {
147 // consume the single-signaled state
148 event->signaled = false;
149 goto Continue;
150 }
151 // For NotificationEvent, leave event->signaled = true (notification persists)
152 MsReleaseSpinlock(&event->lock, flags);
153 return MT_SUCCESS;
154 }
155
156 Continue:
157 // Block the thread. When MtSetEvent wakes it, it will be placed on ready queue.
159 curr->CurrentEvent = event;
160 // Not signaled -> enqueue this thread into the event waiting queue (under event lock)
161 MeEnqueueThread(&event->waitingQueue, curr);
162 // Keep event lock held only for enqueue; after this we release and block.
163 MsReleaseSpinlock(&event->lock, flags);
164#ifdef DEBUG
165 gop_printf(COLOR_PURPLE, "Sleeping current thread: %p\n", PsGetCurrentThread());
166#endif
169
170 // When we resume here, the waker has already moved us to the ready queue, and we are now an active thread on the CPU.
171 return MT_SUCCESS;
172}
173
#define IN
Definition annotations.h:7
#define assert(...)
Definition assert.h:57
@ DISPATCH_LEVEL
Definition core.h:15
enum _IRQL IRQL
struct _ETHREAD ETHREAD
Definition core.h:41
ETHREAD * PETHREAD
Definition core.h:42
MTSTATUS MsWaitForEvent(IN PEVENT event)
Definition events.c:113
MTSTATUS MsSetEvent(IN PEVENT event)
Definition events.c:13
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
#define CONTAINING_RECORD(ptr, type, member)
Definition macros.h:11
FORCEINLINE IRQL MeGetCurrentIrql(void)
Definition me.h:402
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
#define COLOR_PURPLE
Definition mg.h:42
uint32_t flags
Definition mh.h:2
struct _EVENT * PEVENT
@ SynchronizationEvent
Definition ms.h:62
#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:306
FORCEINLINE void MeEnqueueThread(Queue *queue, PETHREAD thread)
Definition ps.h:371
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:394
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:28
struct _DOUBLY_LINKED_LIST * Flink
Definition core.h:29
struct _ITHREAD InternalThread
Definition ps.h:122
struct _EVENT * CurrentEvent
Definition ps.h:126
struct _DOUBLY_LINKED_LIST ThreadListEntry
Definition ps.h:128
uint32_t ThreadState
Definition me.h:263
struct _TRAP_FRAME TrapRegisters
Definition me.h:262
PETHREAD PsGetCurrentThread(void)
Definition thread.c:191