summaryrefslogtreecommitdiff
path: root/Kernel/Thread.h
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2020-12-21 23:21:58 -0700
committerAndreas Kling <kling@serenityos.org>2021-01-17 20:30:31 +0100
commit1d621ab1725d1eba0fafef4575aef72682cd57ad (patch)
treeb30a1d63d09e70722fe04a45c6e96522d3a295bc /Kernel/Thread.h
parent7581b64705ed3c5b3711c956504f278c2ea3899e (diff)
downloadserenity-1d621ab1725d1eba0fafef4575aef72682cd57ad.zip
Kernel: Some futex improvements
This adds support for FUTEX_WAKE_OP, FUTEX_WAIT_BITSET, FUTEX_WAKE_BITSET, FUTEX_REQUEUE, and FUTEX_CMP_REQUEUE, as well well as global and private futex and absolute/relative timeouts against the appropriate clock. This also changes the implementation so that kernel resources are only used when a thread is blocked on a futex. Global futexes are implemented as offsets in VMObjects, so that different processes can share a futex against the same VMObject despite potentially being mapped at different virtual addresses.
Diffstat (limited to 'Kernel/Thread.h')
-rw-r--r--Kernel/Thread.h87
1 files changed, 84 insertions, 3 deletions
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index 8b05db83b5..210835c192 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -255,6 +255,7 @@ public:
enum class Type {
Unknown = 0,
File,
+ Futex,
Plan9FS,
Join,
Queue,
@@ -346,6 +347,10 @@ public:
}
bool set_block_condition(BlockCondition&, void* = nullptr);
+ void set_block_condition_raw_locked(BlockCondition* block_condition)
+ {
+ m_block_condition = block_condition;
+ }
mutable RecursiveSpinLock m_lock;
@@ -390,6 +395,12 @@ public:
});
}
+ bool is_empty() const
+ {
+ ScopedSpinLock lock(m_lock);
+ return is_empty_locked();
+ }
+
protected:
template<typename UnblockOne>
bool unblock(UnblockOne unblock_one)
@@ -417,15 +428,52 @@ public:
return did_unblock;
}
- virtual bool should_add_blocker(Blocker&, void*) { return true; }
+ bool is_empty_locked() const
+ {
+ ASSERT(m_lock.is_locked());
+ return m_blockers.is_empty();
+ }
- SpinLock<u8> m_lock;
+ virtual bool should_add_blocker(Blocker&, void*) { return true; }
- private:
struct BlockerInfo {
Blocker* blocker;
void* data;
};
+
+ Vector<BlockerInfo, 4> do_take_blockers(size_t count)
+ {
+ if (m_blockers.size() <= count)
+ return move(m_blockers);
+
+ size_t move_count = (count <= m_blockers.size()) ? count : m_blockers.size();
+ ASSERT(move_count > 0);
+
+ Vector<BlockerInfo, 4> taken_blockers;
+ taken_blockers.ensure_capacity(move_count);
+ for (size_t i = 0; i < move_count; i++)
+ taken_blockers.append(m_blockers.take(i));
+ m_blockers.remove(0, move_count);
+ return taken_blockers;
+ }
+
+ void do_append_blockers(Vector<BlockerInfo, 4>&& blockers_to_append)
+ {
+ if (blockers_to_append.is_empty())
+ return;
+ if (m_blockers.is_empty()) {
+ m_blockers = move(blockers_to_append);
+ return;
+ }
+ m_blockers.ensure_capacity(m_blockers.size() + blockers_to_append.size());
+ for (size_t i = 0; i < blockers_to_append.size(); i++)
+ m_blockers.append(blockers_to_append.take(i));
+ blockers_to_append.clear();
+ }
+
+ mutable SpinLock<u8> m_lock;
+
+ private:
Vector<BlockerInfo, 4> m_blockers;
};
@@ -471,6 +519,39 @@ public:
bool m_did_unblock { false };
};
+ class FutexBlocker : public Blocker {
+ public:
+ explicit FutexBlocker(FutexQueue&, u32);
+ virtual ~FutexBlocker();
+
+ virtual Type blocker_type() const override { return Type::Futex; }
+ virtual const char* state_string() const override { return "Futex"; }
+ virtual void not_blocking(bool) override { }
+
+ virtual bool should_block() override
+ {
+ return m_should_block;
+ }
+
+ u32 bitset() const { return m_bitset; }
+
+ void begin_requeue()
+ {
+ // We need to hold the lock until we moved it over
+ m_relock_flags = m_lock.lock();
+ }
+ void finish_requeue(FutexQueue&);
+
+ bool unblock_bitset(u32 bitset);
+ bool unblock(bool force = false);
+
+ protected:
+ u32 m_bitset;
+ u32 m_relock_flags { 0 };
+ bool m_should_block { true };
+ bool m_did_unblock { false };
+ };
+
class FileBlocker : public Blocker {
public:
enum class BlockFlags : u32 {