The Pedigree Project 0.1
PerProcessorScheduler.h
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#ifndef PERPROCESSORSCHEDULER_H
21#define PERPROCESSORSCHEDULER_H
22#include "pedigree/kernel/ActivityDiagnostics.h"
23#include "pedigree/kernel/Atomic.h"
24#include "pedigree/kernel/compiler.h"
25#include "pedigree/kernel/machine/SchedulerTimerHandler.h"
26#include "pedigree/kernel/process/ConditionVariable.h"
27#include "pedigree/kernel/process/DeferredThreadReap.h"
28#include "pedigree/kernel/process/DeferredTimeAccounting.h"
29#include "pedigree/kernel/process/Mutex.h"
30#include "pedigree/kernel/process/OwnedThread.h"
31#include "pedigree/kernel/process/SchedulerWorkerWake.h"
32#include "pedigree/kernel/process/Thread.h"
33#include "pedigree/kernel/process/WaitQueue.h"
34#include "pedigree/kernel/processor/UserReturnFrame.h"
35#include "pedigree/kernel/processor/state_forward.h"
36#include "pedigree/kernel/processor/types.h"
37#include "pedigree/kernel/utilities/IntrusiveMpscQueue.h"
38#include "pedigree/kernel/utilities/List.h"
39
40#include <config.h>
41
43class Spinlock;
44
45class EXPORTED_PUBLIC PerProcessorScheduler : public SchedulerTimerHandler {
46 public:
48 enum class StackDiscardReason {
49 EmergencyProcessKill,
50 HostedRegression,
51 LegacyAbiCall,
52 };
53
57
59
61 void initialise(Thread* pThread);
62
66 void checkEventState(uintptr_t userStack);
67
70 void eventHandlerReturned() NORETURN;
71
78 void addThread(Thread* pThread, Thread::ThreadStartFunc pStartFunction, void* pParam,
79 bool bUsermode, void* pStack);
80
84 void addThread(Thread* pThread, SyscallState& state);
85
93 void commitCurrentThreadExit(Spinlock* pLock = 0) NORETURN;
94
100 void abandonCurrentThreadStack(StackDiscardReason reason, Spinlock* pLock = 0) NORETURN;
101
103 static size_t stackDiscardCount();
104
106 static size_t stackDiscardCount(StackDiscardReason reason);
107
109 void requestCurrentThreadExitToIdle();
110
112 void timer(uint64_t delta, InterruptState& state);
113
115 void setClockDeadline(uint64_t deadline);
116
117 void removeThread(Thread* pThread);
118
119 void threadStatusChanged(Thread* pThread);
120
121 size_t logicalCpu() const {
122 return m_LogicalCpu;
123 }
124 bool isIdleThread(const Thread* thread) const {
125 return thread == __atomic_load_n(&m_pIdleThread, __ATOMIC_ACQUIRE);
126 }
127 uint64_t nominalQuantumNs() const {
128 return m_NominalQuantumNs;
129 }
130
132 void ringIrqWorkDoorbell();
133
135 void registerWorkerWake(SchedulerWorkerWake& worker, WaitQueue& waiters);
136
138 void unregisterWorkerWake(SchedulerWorkerWake& worker);
139
141 void ringIrqWorkDoorbell(SchedulerWorkerWake& worker, bool promptOwner = true);
142
147 void publishDeferredTimeAccounting();
148
150 void serviceIrqWorkDoorbell();
151
153 void servicePendingScheduling();
154
155 enum class ProcessStopGateMode {
156 StopOnly,
157 DirectUserTransition,
158 };
159
166 MUST_USE_RESULT bool serviceProcessStopAtUserReturn(
167 ProcessStopGateMode mode = ProcessStopGateMode::StopOnly);
168
173 MUST_USE_RESULT bool serviceUserReturnWork(
174 InterruptState& state, UserReturnFrame::Origin origin = UserReturnFrame::Origin::Interrupt,
175 bool diagnosticSample = false);
176
178 MUST_USE_RESULT bool serviceUserReturnWork(
179 SyscallState& state, UserReturnFrame::Origin origin = UserReturnFrame::Origin::Syscall,
180 bool diagnosticSample = false);
181
184#if PEDIGREE_ACTIVITY_DIAGNOSTICS
185 return (++m_UserReturnDiagnosticSequence % ActivityDiagnostics::UserReturnSamplePeriod) == 0;
186#else
187 return false;
188#endif
189 }
190
192 void commitUserReturnTerminalState();
193
195 void requestIdleThreadWakeup();
196
197 void setIdle(Thread* pThread);
198
200 void idleUntilInterrupt();
201
202#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
204 bool runHostedNewThreadWorkerRegressions();
205
206 static bool currentIrqWorkDoorbellPendingForTest();
207 static void serviceCurrentIrqWorkDoorbellForTest();
208#endif
209
210 private:
211 friend class Scheduler;
212 friend class Thread;
213 friend class ProcessorThreadAllocator;
214 friend class WaitQueue;
215
217 void killCurrentThread(Spinlock* pLock = 0) NORETURN;
218
220 void schedule(Thread::Status nextStatus = Thread::Ready, bool dispatchEvents = true);
221 void scheduleWithInterruptState(Thread::Status nextStatus, bool dispatchEvents,
222 bool previousInterruptState);
223
225 void blockCurrent();
226
228 void publishReadyFromWait(Thread* pThread);
229
230 void finishCurrentThreadExit(Spinlock* pLock, bool transferToIdle) NORETURN;
231
233 void serviceDeferredSubsystemException(InterruptState& state, bool diagnosticSample = false);
234
236 void checkEventState(uintptr_t userStack, Thread::EventSelection selection);
237
239 void checkEventState(uintptr_t userStack, Thread::EventSelection selection,
240 InterruptState* interruptState, SyscallState* syscallState);
241
248
253 static void deleteThreadThenRestoreState(Thread* pThread, SchedulerState& newState,
254 volatile uintptr_t* pLock = 0) NORETURN;
255
256 static void deleteThread(Thread* pThread);
257
258 void startNewThreadWorker(Process* pParent);
259 void stopNewThreadWorker();
260
261 void startTimeAccountingWorker(Process* pParent);
262 void stopTimeAccountingWorker();
263 static int timeAccountingWorkerEntry(void* instance);
264 int runTimeAccountingWorker();
265 void publishDeferredThreadReap(Thread* thread);
266 bool drainDeferredThreadReaps();
267 bool enqueueAffinity(Thread* thread, bool accepted = false);
268 void drainAffinityRequests();
269 void prompt(bool readyPublication = false);
270 void armLocalQuantumIfNeeded();
271 void updateOneShotTimer();
272 void programOneShotTimer();
273 Thread* selectNext(Thread* current);
274 void serviceWorkerWakeups();
275
277 SchedulingAlgorithm* m_pSchedulingAlgorithm;
278
279 Mutex m_NewThreadDataLock;
280 ConditionVariable m_NewThreadDataCondition;
281
282 List<void*> m_NewThreadData;
283 List<void*> m_DelayedNewThreadData;
284 bool m_NewThreadAdmissionOpen;
285 bool m_StopNewThreadWorker;
286 OwnedThread m_NewThreadWorker;
287 DeferredTimeAccountingWorkerState m_TimeAccountingState;
288 DeferredThreadReapNode m_DeferredThreadReapStub;
290 Atomic<size_t> m_nDeferredThreadReaps;
291 Atomic<size_t> m_DeferredThreadReapPublicationState;
292 Atomic<size_t> m_StopTimeAccountingWorker;
293 OwnedThread m_TimeAccountingWorker;
294 WaitQueue m_TimeAccountingWorkerWaiters;
295 SchedulerWorkerWake m_TimeAccountingWorkerWake;
296 Atomic<size_t> m_IrqWorkDoorbell;
297 Atomic<size_t> m_ReschedulePending;
298 Atomic<size_t> m_RemotePromptPending;
299 Atomic<uint64_t> m_ClockDeadline;
300 Spinlock m_IrqWorkLock;
301 SchedulerWorkerWake* m_pWorkerWakeHead = nullptr;
302 Spinlock m_AffinityQueueLock;
303 Thread* m_AffinityHead = nullptr;
304 Thread* m_AffinityTail = nullptr;
305 Atomic<size_t> m_AffinityRequests;
306 bool m_AffinityAdmissionOpen = false;
307 size_t m_LogicalCpu = ~size_t(0);
308 size_t m_PhysicalCpu = 0;
309 uint64_t m_NominalQuantumNs = 0;
310 uint64_t m_QuantumDeadline = 0;
311 uint64_t m_NextLoadSampleDeadline = 0;
312 bool m_OneShotTimer = false;
313
314#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
315 Atomic<size_t> m_nDeferredThreadReapCompletions;
316#endif
317
318 static constexpr size_t DeferredReapPublicationClosed = static_cast<size_t>(1)
319 << ((sizeof(size_t) * 8) - 1);
320 static constexpr size_t DeferredReapPublicationCountMask = ~DeferredReapPublicationClosed;
321
322 static int processorAddThread(void* instance);
323
324 Thread* m_pIdleThread;
325 bool m_IdleWakeRequested = false;
326 size_t m_SchedulerTickCounter = 0;
327 size_t m_UserReturnDiagnosticSequence = 0;
328};
329
330#endif
Definition List.h:61
Definition Mutex.h:56
This class manages how processes and threads are scheduled across processors.
Definition Scheduler.h:50