My Project
Loading...
Searching...
No Matches
mutex.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: GPLv3
4 * PURPOSE: Mutex Implementation.
5 */
6
7#include "../../includes/me.h"
8#include "../../includes/ps.h"
9#include "../../includes/mg.h"
10#include "../../assert.h"
11
14 IN PMUTEX mut
15)
16
17/*++
18
19 Routine description :
20
21 Initializes a MUTEX object, the MUTEX must be in resident memory.
22
23 Arguments:
24
25 Pointer to MUTEX object.
26
27 Return Values:
28
29 Various MTSTATUS Codes.
30
31--*/
32
33{
34
35 // Start of function
36 if (!mut) return MT_INVALID_ADDRESS;
37
38 bool isValid = MmIsAddressPresent((uintptr_t)mut);
39 assert((isValid) == 1, "MUTEX Pointer given to function isn't paged in.");
40 if (!isValid) {
41 return MT_INVALID_ADDRESS;
42 }
43
44 IRQL oldirql;
45 MsAcquireSpinlock(&mut->lock, &oldirql);
46
47 assert((mut->ownerTid) == 0, "Mutex must not be owned already in initialization.");
48 if (mut->ownerTid) {
49 MsReleaseSpinlock(&mut->lock, oldirql);
51 }
52
53 mut->ownerTid = 0;
54 mut->locked = false;
55 mut->ownerThread = NULL;
56
57 // Initialize the event state (event->lock is separate and must be preallocated)
58 // Initialize waiting queue under event lock for safety
59 {
60 IRQL eflags;
61 MsAcquireSpinlock(&mut->SynchEvent.lock, &eflags);
62 mut->SynchEvent.type = SynchronizationEvent;
63 mut->SynchEvent.signaled = false;
64 mut->SynchEvent.waitingQueue.head = mut->SynchEvent.waitingQueue.tail = NULL;
65 MsReleaseSpinlock(&mut->SynchEvent.lock, eflags);
66 }
67
68 MsReleaseSpinlock(&mut->lock, oldirql);
69 return MT_SUCCESS;
70}
71
74 IN PMUTEX mut
75)
76
77/*++
78
79 Routine description : Acquires a MUTEX for the current thread.
80
81 Arguments:
82
83 Pointer to MUTEX object.
84
85 Return Values:
86
87 MTSTATUS Code.
88
89 Note:
90
91 This function MUST NOT be called when IRQL is equal or higher than DISPATCH_LEVEL.
92
93--*/
94
95{
96 // Check parameter.
97 if (!mut) return MT_INVALID_ADDRESS;
98 // Check if address is currently non pageable in memory.
99 if (!MmIsAddressPresent((uintptr_t)mut)) {
100 return MT_INVALID_ADDRESS;
101 }
102
103 IRQL mflags;
104 assert((MeGetCurrentIrql() < DISPATCH_LEVEL), "Blocking code called at DISPATCH_LEVEL or higher IRQL.");
105
106 for (;;) {
107 MsAcquireSpinlock(&mut->lock, &mflags);
108 PETHREAD currThread = PsGetCurrentThread();
109
110 if (!mut->locked) {
111 mut->locked = true;
112 mut->ownerTid = currThread->TID;
113 mut->ownerThread = currThread;
114 MsReleaseSpinlock(&mut->lock, mflags);
115#ifdef DEBUG
116 gop_printf(COLOR_RED, "[MUTEX-DEBUG] Mutex successfully acquired by: %p. MUT: %p\n", currThread, mut);
117#endif
118 return MT_SUCCESS;
119 }
120
121 /* mutex is locked -> enqueue/wait */
122#ifdef DEBUG
123 gop_printf(COLOR_RED, "[MUTEX-DEBUG] Mutex busy, enqueuing: MUT: %p\n", mut);
124#endif
125 /* Enqueue under the event lock inside MsWaitForEvent; release mut->lock first */
126 MsReleaseSpinlock(&mut->lock, mflags);
127
128 MsWaitForEvent(&mut->SynchEvent);
129
130 /* When MsWaitForEvent returns we loop and try again atomically */
131 }
132}
133
136 IN PMUTEX mut
137)
138
139/*++
140
141 Routine description : Releases a MUTEX object, wakes all threads waiting on it (nonblocking).
142
143 Arguments:
144
145 Pointer to MUTEX object.
146
147 Return Values:
148
149 MTSTATUS Code.
150
151--*/
152
153{
154
155 // Start of function
156 if (!mut) return MT_INVALID_ADDRESS;
157
158 // FOLLOW LOCK ORDER: acquire mut->lock then event->lock
159 IRQL mflags;
160 MsAcquireSpinlock(&mut->lock, &mflags);
161
162 assert((mut->ownerTid) != 0, "Attempted release of mutex when it has no owner.");
163 if (!mut->ownerTid) {
164 MsReleaseSpinlock(&mut->lock, mflags);
165 return MT_MUTEX_NOT_OWNED;
166 }
167
168 // Clear ownership while still holding the spinlock
169 mut->ownerTid = 0;
170 mut->locked = false;
171 mut->ownerThread = NULL;
172
173 MsReleaseSpinlock(&mut->lock, mflags);
174
175 // Wake the selected thread by setting an event.
176 MsSetEvent(&mut->SynchEvent);
177
178 return MT_SUCCESS;
179}
#define IN
Definition annotations.h:7
#define assert(...)
Definition assert.h:57
@ DISPATCH_LEVEL
Definition core.h:15
enum _IRQL IRQL
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
bool MmIsAddressPresent(IN uintptr_t VirtualAddress)
Definition map.c:488
FORCEINLINE IRQL MeGetCurrentIrql(void)
Definition me.h:402
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:29
struct _MUTEX * PMUTEX
@ SynchronizationEvent
Definition ms.h:62
#define MT_SUCCESS
Definition mtstatus.h:22
#define MT_MUTEX_ALREADY_OWNED
Definition mtstatus.h:109
#define MT_INVALID_ADDRESS
Definition mtstatus.h:46
#define MT_MUTEX_NOT_OWNED
Definition mtstatus.h:110
int32_t MTSTATUS
Definition mtstatus.h:12
MTSTATUS MsReleaseMutexObject(IN PMUTEX mut)
Definition mutex.c:135
MTSTATUS MsInitializeMutexObject(IN PMUTEX mut)
Definition mutex.c:13
MTSTATUS MsAcquireMutexObject(IN PMUTEX mut)
Definition mutex.c:73
void MsAcquireSpinlock(IN PSPINLOCK lock, IN PIRQL OldIrql)
Definition spinlock.c:13
void MsReleaseSpinlock(IN PSPINLOCK lock, IN IRQL OldIrql)
Definition spinlock.c:45
HANDLE TID
Definition ps.h:125
PETHREAD PsGetCurrentThread(void)
Definition thread.c:191