The Pedigree Project 0.1
Event.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/compiler.h"
23#include "pedigree/kernel/process/Event.h"
24#include "pedigree/kernel/process/Process.h"
25#include "pedigree/kernel/process/Scheduler.h"
26#include "pedigree/kernel/process/Thread.h"
27#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
28#include "pedigree/kernel/processor/Processor.h"
29#include "pedigree/kernel/processor/ProcessorInformation.h"
30#include "pedigree/kernel/processor/VirtualAddressSpace.h"
31#include "pedigree/kernel/utilities/Iterator.h"
32#include "pedigree/kernel/utilities/utility.h"
33
34Event::Event(uintptr_t handlerAddress, bool isDeletable, size_t specificNestingLevel,
35 HandlerPrivilege handlerPrivilege)
36 : m_HandlerAddress(handlerAddress),
37 m_HandlerPrivilege(handlerPrivilege),
38 m_bIsDeletable(isDeletable),
39 m_NestingLevel(specificNestingLevel),
40 m_Magic(EVENT_MAGIC),
41 m_Threads(),
42 m_Lock(false),
43 m_DeleteWhenUnused(false),
44 m_DeliveriesClosed(false),
45 m_DrainClaimed(false),
46 m_SendersInFlight(0),
47 m_pFirstActiveDelivery(nullptr),
48 m_DeliveryWaiters() {}
49
50Event::SendLease::SendLease() : m_pEvent(nullptr) {}
51
52Event::SendLease::SendLease(Event* event) : m_pEvent(event) {}
53
54Event::SendLease::SendLease(SendLease&& other) noexcept : m_pEvent(other.m_pEvent) {
55 other.m_pEvent = nullptr;
56}
57
58Event::SendLease::~SendLease() {
59 reset();
60}
61
62Event::SendLease& Event::SendLease::operator=(SendLease&& other) noexcept {
63 if (this != &other) {
64 reset();
65 m_pEvent = other.m_pEvent;
66 other.m_pEvent = nullptr;
67 }
68 return *this;
69}
70
71void Event::SendLease::reset() {
72 Event* event = m_pEvent;
73 m_pEvent = nullptr;
74 if (event) {
75 event->endSend();
76 }
77}
78
79Event::Retirement::Retirement() : m_pEvent(nullptr) {}
80
81Event::Retirement::Retirement(Event* event) : m_pEvent(event) {}
82
83Event::Retirement::Retirement(Retirement&& other) noexcept : m_pEvent(other.m_pEvent) {
84 other.m_pEvent = nullptr;
85}
86
87Event::Retirement::~Retirement() {
88 reset();
89}
90
91Event::Retirement& Event::Retirement::operator=(Retirement&& other) noexcept {
92 if (this != &other) {
93 reset();
94 m_pEvent = other.m_pEvent;
95 other.m_pEvent = nullptr;
96 }
97 return *this;
98}
99
100void Event::Retirement::reset() {
101 Event* event = m_pEvent;
102 m_pEvent = nullptr;
103 if (event) {
104 event->finishRetirement();
105 }
106}
107
108Event::Delivery::Delivery()
109 : m_pEvent(nullptr),
110 m_pThread(nullptr),
111 m_pPreviousActive(nullptr),
112 m_pNextActive(nullptr),
113 m_bActive(false) {}
114
115Event::Delivery::Delivery(Event* event, Thread* thread)
116 : m_pEvent(event),
117 m_pThread(thread),
118 m_pPreviousActive(nullptr),
119 m_pNextActive(nullptr),
120 m_bActive(false) {}
121
122Event::Delivery::Delivery(Delivery&& other) noexcept
123 : m_pEvent(other.m_pEvent),
124 m_pThread(other.m_pThread),
125 m_pPreviousActive(nullptr),
126 m_pNextActive(nullptr),
127 m_bActive(false) {
128 if (other.m_bActive) {
129 FATAL("Moving an active Event delivery.");
130 }
131 other.m_pEvent = nullptr;
132 other.m_pThread = nullptr;
133}
134
135Event::Delivery::~Delivery() {
136 reset();
137}
138
139Event::Delivery& Event::Delivery::operator=(Delivery&& other) noexcept {
140 if (this != &other) {
141 if (other.m_bActive) {
142 FATAL("Moving an active Event delivery.");
143 }
144 reset();
145 m_pEvent = other.m_pEvent;
146 m_pThread = other.m_pThread;
147 other.m_pEvent = nullptr;
148 other.m_pThread = nullptr;
149 }
150 return *this;
151}
152
153void Event::Delivery::beginDispatch() {
154 if (m_pEvent) {
155 m_pEvent->beginDispatch(this);
156 }
157}
158
160 Event* event = m_pEvent;
161 Thread* thread = m_pThread;
162 if (event) {
163 if (m_bActive) {
164 event->endDispatch(this);
165 }
166 m_pEvent = nullptr;
167 m_pThread = nullptr;
168 event->completeDelivery(thread);
169 }
170}
171
172Event::~Event() {
173 EMIT_IF(THREADS) {
174 if (m_DeliveryWaiters.waiterCount()) {
175 FATAL("Deleting an Event while delivery waiters are live.");
176 }
177
179
180 if (m_SendersInFlight) {
181 FATAL("Deleting an Event with admitted senders.");
182 }
183
185 FATAL("Deleting an Event with an active kernel delivery.");
186 }
187
188 if (m_Threads.count()) {
189 ERROR("UNSAFE EVENT DELETION");
190 for (auto it : m_Threads) {
191 ERROR(" => Pending delivery to thread " << it << " (" << it->getParent()->getId() << ":"
192 << it->getId() << ").");
193 }
194 FATAL("Unsafe event deletion: " << m_Threads.count() << " threads reference it!");
195
197 }
198 }
199}
200
202 EMIT_IF(THREADS) {
204 }
205
206 return 0;
207}
208
210 return getTrampoline() + 0x100;
211}
212
216
218 return handlerBufferSize(PhysicalMemoryManager::getPageSize());
219}
220
222 return getHandlerBuffer() + ((EVENT_TID_MAX * MAX_NESTED_EVENTS) * getHandlerBufferSize());
223}
224
226 return m_bIsDeletable;
227}
228
229bool Event::isValidHandlerMapping(size_t mappingFlags) const {
230 if (m_HandlerPrivilege == HandlerPrivilege::User) {
231 return !(mappingFlags & VirtualAddressSpace::KernelMode) &&
232 (mappingFlags & VirtualAddressSpace::Execute);
233 }
234
235 return mappingFlags & VirtualAddressSpace::KernelMode;
236}
237
238bool Event::unserialize(uint8_t* pBuffer, Event& event) {
239 ERROR("Event::unserialize is abstract, should never be called.");
240 return false;
241}
242
243size_t Event::getEventType(uint8_t* pBuffer) {
244 void* alignedBuffer = ASSUME_ALIGNMENT(pBuffer, sizeof(size_t));
245 size_t* pBufferSize_t = reinterpret_cast<size_t*>(alignedBuffer);
246 return pBufferSize_t[0];
247}
248
249Event::Event(const Event& other)
251 other.m_HandlerPrivilege) {
254}
255
256Event& Event::operator=(const Event& other) {
257 if (this == &other) {
258 return *this;
259 }
260
262 if (m_Threads.count()) {
263 FATAL("Cannot replace an Event while deliveries are live.");
264 }
266 FATAL("Cannot replace an Event while its lifetime is owned.");
267 }
268
269 m_HandlerAddress = other.m_HandlerAddress;
270 m_HandlerPrivilege = other.m_HandlerPrivilege;
271 m_bIsDeletable = other.m_bIsDeletable;
272 m_NestingLevel = other.m_NestingLevel;
273 m_DeleteWhenUnused = false;
274 m_DeliveriesClosed = false;
275 m_DrainClaimed = false;
277 return *this;
278}
279
281 auto deliveryGuard = m_DeliveryWaiters.acquire();
283 if (m_DeliveriesClosed) {
284 return SendLease();
285 }
287 return SendLease(this);
288}
289
290void Event::endSend() {
291 bool drained = false;
292 bool deleteNow = false;
293 {
294 auto deliveryGuard = m_DeliveryWaiters.acquire();
295 {
297 assert(m_SendersInFlight);
299 drained = !m_SendersInFlight && !m_Threads.count();
300 deleteNow = drained && m_DeleteWhenUnused;
301 }
302 if (drained) {
303 deliveryGuard.wakeAll(WaitQueue::WakeReason::Signalled, WaitQueue::Channel(this));
304 }
305 }
306
307 if (deleteNow) {
308 delete this;
309 }
310}
311
314 if (m_DeliveriesClosed) {
315 return false;
316 }
317 m_Threads.pushBack(thread);
318 return true;
319}
320
322 bool finalDelivery = false;
323 bool deleteNow = false;
324 {
325 auto deliveryGuard = m_DeliveryWaiters.acquire();
326 {
328
329 for (List<Thread*>::Iterator it = m_Threads.begin(); it != m_Threads.end(); ++it) {
330 if (*it == thread) {
331 m_Threads.erase(it);
332 finalDelivery = !m_Threads.count() && !m_SendersInFlight;
333 break;
334 }
335 }
336 deleteNow = finalDelivery && m_DeleteWhenUnused;
337 }
338 if (finalDelivery) {
339 deliveryGuard.wakeAll(WaitQueue::WakeReason::Signalled, WaitQueue::Channel(this));
340 }
341 }
342
343 if (deleteNow) {
344 delete this;
345 }
346}
347
349 bool deleteNow = false;
350 {
351 auto deliveryGuard = m_DeliveryWaiters.acquire();
352 bool finalDelivery = false;
353 {
355
356 bool found = false;
357 for (List<Thread*>::Iterator it = m_Threads.begin(); it != m_Threads.end(); ++it) {
358 if (*it == thread) {
359 m_Threads.erase(it);
360 found = true;
361 break;
362 }
363 }
364
365 if (!found) {
366 FATAL("Completing an event delivery with no registration.");
367 }
368
369 finalDelivery = !m_Threads.count() && !m_SendersInFlight;
370 if (m_bIsDeletable) {
371 m_DeleteWhenUnused = true;
372 }
373 deleteNow = finalDelivery && m_DeleteWhenUnused;
374 }
375
376 if (finalDelivery) {
377 deliveryGuard.wakeAll(WaitQueue::WakeReason::Signalled, WaitQueue::Channel(this));
378 }
379 }
380
381 if (deleteNow) {
382 delete this;
383 }
384}
385
388
389 return m_Threads.count();
390}
391
393 registration = beginSend();
394 return static_cast<bool>(registration);
395}
396
399 if (delivery->m_bActive || delivery->m_pEvent != this) {
400 FATAL("Invalid Event delivery activation.");
401 }
402
403 delivery->m_pPreviousActive = nullptr;
404 delivery->m_pNextActive = m_pFirstActiveDelivery;
406 m_pFirstActiveDelivery->m_pPreviousActive = delivery;
407 }
408 m_pFirstActiveDelivery = delivery;
409 delivery->m_bActive = true;
410}
411
412void Event::endDispatch(Delivery* delivery) {
414 if (!delivery->m_bActive || delivery->m_pEvent != this) {
415 FATAL("Invalid Event delivery deactivation.");
416 }
417
418 if (delivery->m_pPreviousActive) {
419 delivery->m_pPreviousActive->m_pNextActive = delivery->m_pNextActive;
420 } else {
421 assert(m_pFirstActiveDelivery == delivery);
422 m_pFirstActiveDelivery = delivery->m_pNextActive;
423 }
424 if (delivery->m_pNextActive) {
425 delivery->m_pNextActive->m_pPreviousActive = delivery->m_pPreviousActive;
426 }
427
428 delivery->m_pPreviousActive = nullptr;
429 delivery->m_pNextActive = nullptr;
430 delivery->m_bActive = false;
431}
432
434 // no-op if no threads
435 EMIT_IF(!THREADS) {
436 return;
437 }
438
439 if (m_bIsDeletable) {
440 FATAL("Cannot wait on a self-deleting Event.");
441 }
442
443 bool claimed = false;
444 while (true) {
445 auto guard = m_DeliveryWaiters.acquire();
446 {
447 LockGuard<Spinlock> deliveryGuard(m_Lock);
448 if (!claimed) {
449 if (m_DrainClaimed) {
450 FATAL(
451 "Event delivery drain attempted by more than one "
452 "owner.");
453 }
454 m_DrainClaimed = true;
455 claimed = true;
456 }
457 m_DeliveriesClosed = true;
458 Thread* current = Processor::information().getCurrentThread();
459 for (Delivery* delivery = m_pFirstActiveDelivery; delivery;
460 delivery = delivery->m_pNextActive) {
461 if (delivery->m_pThread == current) {
462 FATAL(
463 "Event handler attempted to drain its own active "
464 "delivery; use Event::retire for heap ownership.");
465 }
466 }
467 if (!m_Threads.count() && !m_SendersInFlight) {
468 return;
469 }
470 }
471
472 const WaitQueue::WakeReason wakeReason =
473 guard.waitForCompletion(WaitQueue::Channel(this), Thread::EventWait,
474 reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
475 (void)wakeReason;
476 }
477}
478
480 Retirement retirement;
481 beginRetirement(retirement);
482}
483
485 {
486 auto guard = m_DeliveryWaiters.acquire();
487 LockGuard<Spinlock> deliveryGuard(m_Lock);
488 if (m_bIsDeletable) {
489 FATAL("Explicitly retiring an already self-deleting Event.");
490 }
491 if (m_DrainClaimed) {
492 FATAL("Cannot retire an Event whose drain is already owned.");
493 }
494 m_DrainClaimed = true;
495 m_DeliveriesClosed = true;
497 }
498
499 retirement = Retirement(this);
500}
501
502void Event::finishRetirement() {
503 {
504 LockGuard<Spinlock> deliveryGuard(m_Lock);
506 FATAL("Completing an Event retirement without ownership.");
507 }
508 m_DeleteWhenUnused = true;
509 }
510
511 // The retirement pin prevents a concurrent final delivery from deleting
512 // the Event before this handoff completes.
513 endSend();
514}
void reset()
Definition Event.cc:159
Definition Event.h:49
static uintptr_t getTrampoline()
Definition Event.cc:201
WaitQueue m_DeliveryWaiters
Definition Event.h:389
void retire()
Definition Event.cc:479
Spinlock m_Lock
Definition Event.h:342
virtual bool isDeletable()
Definition Event.cc:225
static uintptr_t getSecondaryTrampoline()
Definition Event.cc:209
bool registerThread(Thread *thread)
Definition Event.cc:312
HandlerPrivilege m_HandlerPrivilege
Definition Event.h:327
HandlerPrivilege
Definition Event.h:52
bool m_DrainClaimed
Definition Event.h:380
void completeDelivery(Thread *thread)
Definition Event.cc:348
static size_t getHandlerBufferSize()
Definition Event.cc:217
void deregisterThread(Thread *thread)
Definition Event.cc:321
bool isValidHandlerMapping(size_t mappingFlags) const
Definition Event.cc:229
void beginDispatch(Delivery *delivery)
Definition Event.cc:397
virtual void waitForDeliveries()
Definition Event.cc:433
void beginRetirement(Retirement &retirement)
Definition Event.cc:484
bool m_DeleteWhenUnused
Definition Event.h:374
bool tryAcquireRegistration(SendLease &registration)
Definition Event.cc:392
size_t pendingCount()
Definition Event.cc:386
static uintptr_t getLastHandlerBuffer()
Definition Event.cc:221
static uintptr_t getHandlerBuffer()
Definition Event.cc:213
size_t m_SendersInFlight
Definition Event.h:383
SendLease beginSend()
Definition Event.cc:280
static size_t getEventType(uint8_t *pBuffer)
Definition Event.cc:243
bool m_DeliveriesClosed
Definition Event.h:377
Event(uintptr_t handlerAddress, bool isDeletable, size_t specificNestingLevel=~0UL, HandlerPrivilege handlerPrivilege=HandlerPrivilege::Kernel)
Definition Event.cc:34
List< Thread * > m_Threads
Definition Event.h:339
size_t m_NestingLevel
Definition Event.h:333
static bool unserialize(uint8_t *pBuffer, Event &event)
Definition Event.cc:238
Delivery * m_pFirstActiveDelivery
Definition Event.h:386
uintptr_t m_HandlerAddress
Definition Event.h:324
bool m_bIsDeletable
Definition Event.h:330
Iterator begin()
Definition List.h:122
::Iterator< T, node_t > Iterator
Definition List.h:67
Iterator end()
Definition List.h:132
static ProcessorInformation & information()
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual uintptr_t getKernelEventBlockStart() const =0
Iterator erase(Iterator &Iter)
Definition List.h:352
void clear()
Definition List.h:399
size_t count() const
Definition List.h:212
void pushBack(const T &value)
Definition List.h:216