summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/KernelKit/BinaryMutex.h3
-rw-r--r--src/kernel/KernelKit/UserProcessScheduler.h5
-rw-r--r--src/kernel/src/BinaryMutex.cpp45
-rw-r--r--src/kernel/src/UserProcessScheduler.cpp15
4 files changed, 47 insertions, 21 deletions
diff --git a/src/kernel/KernelKit/BinaryMutex.h b/src/kernel/KernelKit/BinaryMutex.h
index 2fb390d3..d97ab854 100644
--- a/src/kernel/KernelKit/BinaryMutex.h
+++ b/src/kernel/KernelKit/BinaryMutex.h
@@ -8,12 +8,14 @@
#include <CompilerKit/CompilerKit.h>
#include <KernelKit/Timer.h>
+#include <KernelKit/CoreProcessScheduler.h>
#include <NeKit/Config.h>
namespace Kernel {
class UserProcess;
/// @brief Access control class, which locks a task until one is done.
+/// Implements priority inheritance to prevent priority inversion.
class BinaryMutex final {
public:
using LockedPtr = UserProcess*;
@@ -37,6 +39,7 @@ class BinaryMutex final {
private:
LockedPtr fLockingProcess{nullptr};
+ AffinityKind fOwnerOriginalAffinity{AffinityKind::kInvalid}; // for priority inheritance
};
} // namespace Kernel
diff --git a/src/kernel/KernelKit/UserProcessScheduler.h b/src/kernel/KernelKit/UserProcessScheduler.h
index 5018f1f6..8c7a4afa 100644
--- a/src/kernel/KernelKit/UserProcessScheduler.h
+++ b/src/kernel/KernelKit/UserProcessScheduler.h
@@ -83,9 +83,10 @@ class UserProcess final {
kExecutableKindCount,
};
- ProcessTime PTime{0}; //! @brief Process allocated tine.
+ ProcessTime PTime{0}; //! @brief Process allocated time.
ProcessTime RTime{0}; //! @brief Process run time.
- ProcessTime UTime{0}; //! #brief Process used time.
+ ProcessTime UTime{0}; //! @brief Process used time.
+ ProcessTime STime{0}; //! @brief Process sleep time (for dynamic priority boost).
ProcessID ProcessId{kCPSInvalidPID};
ExecutableKind Kind{ExecutableKind::kExecutableKind};
diff --git a/src/kernel/src/BinaryMutex.cpp b/src/kernel/src/BinaryMutex.cpp
index c5fd6a50..a83f031a 100644
--- a/src/kernel/src/BinaryMutex.cpp
+++ b/src/kernel/src/BinaryMutex.cpp
@@ -7,23 +7,15 @@
#include <KernelKit/ProcessScheduler.h>
namespace Kernel {
-/***********************************************************************************/
-/// @brief Unlocks the binary mutex.
-/***********************************************************************************/
-
-#ifndef __NE_TIMEOUT_CONFIG__
-#define __NE_TIMEOUT_CONFIG__ 10000
-#endif
Bool BinaryMutex::Unlock() {
- auto timeout = 0UL;
- constexpr auto kTimoutLimit = __NE_TIMEOUT_CONFIG__;
+ if (!fLockingProcess)
+ return No;
- while (fLockingProcess->Status == ProcessStatusKind::kRunning) {
- ++timeout;
-
- if (timeout > kTimoutLimit)
- return No;
+ // restore original priority if we boosted the owner
+ if (fOwnerOriginalAffinity != AffinityKind::kInvalid) {
+ fLockingProcess->Affinity = fOwnerOriginalAffinity;
+ fOwnerOriginalAffinity = AffinityKind::kInvalid;
}
fLockingProcess = nullptr;
@@ -35,9 +27,20 @@ Bool BinaryMutex::Unlock() {
/***********************************************************************************/
Bool BinaryMutex::Lock(BinaryMutex::LockedPtr process) {
- if (!process || this->IsLocked()) return No;
+ if (!process) return No;
+
+ // if already locked, implement priority inheritance
+ if (this->IsLocked() && fLockingProcess) {
+ // boost owner to waiter's priority if waiter is higher priority (lower value = higher priority)
+ if (process->Affinity < fLockingProcess->Affinity) {
+ fOwnerOriginalAffinity = fLockingProcess->Affinity;
+ fLockingProcess->Affinity = process->Affinity;
+ }
+ return No; // lock not acquired, but owner boosted
+ }
this->fLockingProcess = process;
+ fOwnerOriginalAffinity = AffinityKind::kInvalid;
return Yes;
}
@@ -51,15 +54,19 @@ Bool BinaryMutex::IsLocked() const {
}
/***********************************************************************************/
-/// @brief Try lock or wait.
+/// @brief Try lock, waiting until timeout if already locked.
/***********************************************************************************/
Bool BinaryMutex::LockAndWait(BinaryMutex::LockedPtr process, ITimer* timer) {
- if (timer == nullptr) return No;
+ if (timer == nullptr || !process) return No;
+
+ // try to acquire lock immediately
+ if (this->Lock(process))
+ return Yes;
+ // wait and retry
timer->Wait();
- this->Lock(process);
- return this->Unlock();
+ return this->Lock(process);
}
/***********************************************************************************/
diff --git a/src/kernel/src/UserProcessScheduler.cpp b/src/kernel/src/UserProcessScheduler.cpp
index 8c048f07..a4b328ac 100644
--- a/src/kernel/src/UserProcessScheduler.cpp
+++ b/src/kernel/src/UserProcessScheduler.cpp
@@ -406,6 +406,7 @@ ProcessID UserProcessScheduler::Spawn(const Char* name, VoidPtr code, VoidPtr im
process.PTime = 0;
process.UTime = 0;
process.RTime = 0;
+ process.STime = 0;
if (!process.FileTree) {
process.FileTree = new ProcessFileTree<VoidPtr>();
@@ -501,6 +502,16 @@ SizeT UserProcessScheduler::Run() {
++process.UTime;
}
+ //! boost priority for processes that slept (interactive boost)
+ if (process.STime > 0) {
+ // the longer it slept, the bigger the boost (capped at kVeryHigh level)
+ ProcessTime boost = process.STime / 10;
+ if (boost > (Int32)AffinityKind::kHigh)
+ boost = (Int32)AffinityKind::kHigh;
+ process.PTime += boost;
+ process.STime = 0; // reset sleep counter after boost
+ }
+
this->TheCurrentProcess() = process;
if (UserProcessHelper::Switch(process.StackFrame, process.ProcessId)) {
@@ -520,6 +531,10 @@ SizeT UserProcessScheduler::Run() {
}
}
} else {
+ //! track sleep time for processes that are blocked/waiting
+ if (process.Status == ProcessStatusKind::kFrozen) {
+ ++process.STime;
+ }
++process.RTime;
--process.PTime;
}