Commit graph

306 commits

Author SHA1 Message Date
Andreas Kling
4a9c18afb9 Kernel: Rename FileDescription => OpenFileDescription
Dr. POSIX really calls these "open file description", not just
"file description", so let's call them exactly that. :^)
2021-09-07 13:53:14 +02:00
Brian Gianforcaro
88c27fc38e Kernel: Specify a lock rank for Thread::m_lock 2021-09-07 13:16:01 +02:00
Brian Gianforcaro
066b0590ec Kernel/Locking: Add lock rank tracking per thread to find deadlocks
This change adds a static lock hierarchy / ranking to the Kernel with
the goal of reducing / finding deadlocks when running with SMP enabled.

We have seen quite a few lock ordering deadlocks (locks taken in a
different order, on two different code paths). As we properly annotate
locks in the system, then these facilities will find these locking
protocol violations automatically

The `LockRank` enum documents the various locks in the system and their
rank. The implementation guarantees that a thread holding one or more
locks of a lower rank cannot acquire an additional lock with rank that
is greater or equal to any of the currently held locks.
2021-09-07 13:16:01 +02:00
Brian Gianforcaro
0718afa773 Kernel: Track when a thread is in the middle of crashing
There are certain checks that we should skip if the system is crashing.
The system can avoid stack overflow during crash, or even triple
faulting while while handling issues that can causes recursive panics
or aborts.
2021-09-07 13:16:01 +02:00
Andreas Kling
7981422500 Kernel: Make Threads always have a name
We previously allowed Thread to exist in a state where its m_name was
null, and had to work around that in various places.

This patch removes that possibility and forces those who would create a
thread (or change the name of one) to provide a NonnullOwnPtr<KString>
with the name.
2021-09-06 13:06:05 +02:00
Brian Gianforcaro
bb58a4d943 Kernel: Make all Spinlocks use u8 for storage, remove template
The default template argument is only used in one place, and it
looks like it was probably just an oversight. The rest of the Kernel
code all uses u8 as the type. So lets make that the default and remove
the unused template argument, as there doesn't seem to be a reason to
allow the size to be customizable.
2021-09-05 20:46:02 +02:00
sin-ack
566c5d1e99 AK+Kernel: Move KResult.h to Kernel/API for userspace access
This commit moves the KResult and KResultOr objects to Kernel/API to
signify that they may now be freely used by userspace code at points
where a syscall-related error result is to be expected. It also exposes
KResult and KResultOr to the global namespace to make it nicer to use
for userspace code.
2021-09-05 12:54:48 +02:00
Brian Gianforcaro
9d1b27263f Kernel: Declare type aliases with "using" instead of "typedef"
This is the idiomatic way to declare type aliases in modern C++.
Flagged by Sonar Cloud as a "Code Smell", but I happen to agree
with this particular one. :^)
2021-09-05 09:48:43 +01:00
Andreas Kling
e851a77346 Kernel: Rename FileBlocker::unblock() => unblock_if_conditions_are_met()
Since this may not actually unblock, the old name was very confusing.
2021-09-05 01:10:56 +02:00
Andreas Kling
5d5a3708c4 Kernel: Rename Thread::clone() => try_clone() and propagate errors 2021-09-04 23:11:04 +02:00
Andreas Kling
68bf6db673 Kernel: Rename Spinlock::is_owned_by_current_thread()
...to is_owned_by_current_processor(). As Tom pointed out, this is
much more accurate. :^)
2021-08-29 22:19:42 +02:00
Andreas Kling
0b4671add7 Kernel: {Mutex,Spinlock}::own_lock() => is_locked_by_current_thread()
Rename these API's to make it more clear what they are checking.
2021-08-29 12:53:11 +02:00
Andrew Kaster
54161bf5b4 Kernel: Acquire reference to waitee before trying to block in sys$waitid
Previously, we would try to acquire a reference to the all processes
lock or other contended resources while holding both the scheduler lock
and the thread's blocker lock. This could lead to a deadlock if we
actually have to block on those other resources.
2021-08-28 20:53:38 +02:00
Andreas Kling
97f5383525 Kernel: Remove confusing nested scope in Thread::block()
There was a nested scope here that didn't actually scope anything
meaningfully, so just get rid of it.
2021-08-24 16:37:28 +02:00
Andreas Kling
a22634bb59 Kernel: Use TemporaryChange to update Thread::m_in_block
Let's use an RAII helper to avoid having to update this on every path
out of block().

Note that this extends the time under `m_in_block == true` by a little
but that should be harmless.
2021-08-24 16:37:28 +02:00
Andreas Kling
0c1d41cc8a Kernel: Simplify Blockers so they don't need a "should block" flag
The `m_should_block` member variable that many of the Thread::Blocker
subclasses had was really only used to carry state from the constructor
to the immediate-unblock-without-blocking escape hatch.

This patch refactors the blockers so that we don't need to hold on
to this flag after setup_blocker(), and instead the return value from
setup_blocker() is the authority on whether the unblock conditions
are already met.
2021-08-24 16:37:28 +02:00
Andreas Kling
adbf472ca7 Kernel: Remove unused BlockTimeout::m_should_block
This was assigned but never read.
2021-08-24 16:37:28 +02:00
Andreas Kling
cfd9045891 Kernel: Remove unused Thread::Blocker::should_block() virtual
This was previously used after construction to check for early unblock
conditions that couldn't be communicated from the constructor.

Now that we've moved early unblock checks from the constructor into
setup_blocker(), we don't need should_block() anymore.
2021-08-24 16:37:28 +02:00
Andreas Kling
82c3cc4640 Kernel: Move Blocker setup out from constructors into setup_blocker()
Instead of registering with blocker sets and whatnot in the various
Blocker subclass constructors, this patch moves such initialization
to a separate setup_blocker() virtual.

setup_blocker() returns false if there's no need to actually block
the thread. This allows us to bail earlier in Thread::block().
2021-08-24 16:37:28 +02:00
Andreas Kling
2c74533ba6 Kernel: Don't register thread as custom data for WaitQueueBlocker
When adding a WaitQueueBlocker to a WaitQueue, it stored the blocked
thread in the registration's custom "void* data" slot.
This was only used to print the Thread* in some debug logging.

Now that Blocker always knows its origin Thread, we can simply add
a Blocker::thread() accessor and then get the blocked Thread& from
there. No need to register custom data.
2021-08-24 01:57:11 +02:00
Andreas Kling
a58c4bbcf5 Kernel: Make Thread::Blocker::m_thread a NonnullRefPtr<Thread>
There's no harm in the blocker always knowing which thread it originated
from. It also simplifies some logic since we don't need to think about
it ever being null.
2021-08-24 01:57:11 +02:00
Andreas Kling
c351945474 Kernel: Simplify unregistering a Blocker from a BlockerSet
The BlockerSet stores its blockers along with a "void* data" that may
contain some blocker-specific context relevant to the specific blocker
registration (for example, SelectBlocker stores a pointer to the
relevant entry in an array of SelectBlocker::FDInfo structs.)

When unregistering a blocker from a set, we don't need to key the
blocker by both the Blocker* and the data. Just the Blocker* is enough,
since all registrations for that blocker need to be removed anyway as
the blocker is about to be destroyed.

So we stop passing the "void* data" to BlockerSet::remove_blocker(),
which also allows us to remove the now-unneeded Blocker::m_block_data.
2021-08-24 01:57:11 +02:00
Andreas Kling
96909f5200 Kernel: Make Thread::m_block_timer a NonnullRefPtr
Every thread has a block timer, so let's encode that in the type.
2021-08-23 18:07:58 +02:00
Andreas Kling
7006cb82bd Kernel: Rename Blocker::not_blocking(bool) to something more descriptive
Namely, will_unblock_immediately_without_blocking(Reason).

This virtual function is called on a blocker *before any block occurs*,
if it turns out that we don't need to block the thread after all.

This can happens for one of two reasons:

- UnblockImmediatelyReason::UnblockConditionAlreadyMet

    We don't need to block the thread because the condition for
    unblocking it is already met.

- UnblockImmediatelyReason::TimeoutInThePast

    We don't need to block the thread because a timeout was specified
    and that timeout is already in the past.

This patch does not introduce any behavior changes, it's only meant to
clarify this part of the blocking logic.
2021-08-23 02:13:04 +02:00
Andreas Kling
e51a5e2d5d Kernel: Rename some BlockerSets to foo_blocker_set
Cleanup after renaming BlockCondition to BlockerSet.
2021-08-23 01:42:04 +02:00
Andreas Kling
63f9b0d0dc Kernel: Make Thread::Blocker non-copyable and non-movable 2021-08-23 01:42:04 +02:00
Andreas Kling
40bc378d81 Kernel: Rename QueueBlocker => WaitQueueBlocker
This is a Thread::Blocker that blocks on a WaitQueue, so let's call it
a WaitQueueBlocker to improve clarity. :^)
2021-08-23 00:10:33 +02:00
Andreas Kling
b30081b49a Kernel: Rename BlockerSet::unblock() to something more accurate
Namely, unblock_all_blockers_whose_conditions_are_met().

The old name made it sound like things were getting unblocked no matter
what, but that's not actually the case.

What this actually does is iterate through the set of blockers,
unblocking those whose conditions are met. So give it a (very) verbose
name that errs on the side of descriptiveness.
2021-08-23 00:02:09 +02:00
Andreas Kling
928929bbe1 Kernel: VERIFY that nobody is holding lock in ~BlockerSet()
By the time we end up destroying a BlockerSet, we don't need to take
the internal spinlock. And nobody else should be holding it either.
So replace the SpinlockLocker with a VERIFY().
2021-08-23 00:02:09 +02:00
Andreas Kling
85546af417 Kernel: Rename Thread::BlockCondition to BlockerSet
This class represents a set of Thread::Blocker objects attached to
something that those blockers are waiting on.
2021-08-23 00:02:09 +02:00
Andreas Kling
8000e8a080 Kernel: Mark Thread::Blocker leaf subclasses final 2021-08-23 00:02:09 +02:00
Andreas Kling
53019f413c Kernel: Mark BlockCondition subclasses as final 2021-08-23 00:02:09 +02:00
Andreas Kling
0f03a8aece Kernel: Add VERIFY(!m_in_block) when entering Thread::block() 2021-08-23 00:02:09 +02:00
Andreas Kling
d60635cb9d Kernel: Convert Processor::in_irq() to static current_in_irq()
This closes the race window between Processor::current() and a context
switch happening before in_irq().
2021-08-23 00:02:09 +02:00
Andreas Kling
3e3f760808 Kernel: Fix some trivial clang-tidy warnings in Thread.{cpp,h} 2021-08-23 00:02:09 +02:00
Andreas Kling
c922a7da09 Kernel: Rename ScopedSpinlock => SpinlockLocker
This matches MutexLocker, and doesn't sound like it's a lock itself.
2021-08-22 03:34:10 +02:00
Andreas Kling
55adace359 Kernel: Rename SpinLock => Spinlock 2021-08-22 03:34:10 +02:00
Andreas Kling
ed6f84c2c9 Kernel: Rename SpinLockProtectedValue<T> => SpinLockProtected<T> 2021-08-22 03:34:09 +02:00
Andreas Kling
961f727448 Kernel: Consolidate a bunch of i386/x86_64 code paths
Add some arch-specific getters and setters that allow us to merge blocks
that were previously specific to either ARCH(I386) or ARCH(X86_64).
2021-08-19 23:22:02 +02:00
Andreas Kling
62719b85e0 Kernel: Port Thread to ListedRefCounted 2021-08-17 01:21:47 +02:00
Andreas Kling
37304203dd Kernel: Lock thread list while in Thread::unref()
This patch does three things:

- Convert the global thread list from a HashMap to an IntrusiveList
- Combine the thread list and its lock into a SpinLockProtectedValue
- Customize Thread::unref() so it locks the list while unreffing

This closes the same race window for Thread as @sin-ack's recent changes
did for Process.

Note that the HashMap->IntrusiveList conversion means that we lose O(1)
lookups, but the majority of clients of this list are doing traversal,
not lookup. Once we have an intrusive hashing solution, we should port
this to use that, but for now, this gets rid of heap allocations during
a sensitive time.
2021-08-15 12:44:35 +02:00
Brian Gianforcaro
464dc42640 Kernel: Convert lock debug APIs to east const 2021-08-13 20:42:39 +02:00
Brian Gianforcaro
bea74f4b77 Kernel: Reduce LOCK_DEBUG ifdefs by utilizing Kernel::LockLocation
The LOCK_DEBUG conditional code is pretty ugly for a feature that we
only use rarely. We can remove a significant amount of this code by
utilizing a zero sized fake type when not building in LOCK_DEBUG mode.

This lets us keep the same API, but just let the compiler optimize it
away when don't actually care about the location the caller came from.
2021-08-13 20:42:39 +02:00
Liav A
7ba991dc37 Kernel: Steer away from heap allocations for ProcFS process data
Instead, use more static patterns to acquire that sort of data.
2021-08-12 20:57:32 +02:00
Gunnar Beutner
3322efd4cd Kernel: Fix kernel panic when blocking on the process' big lock
Another thread might end up marking the blocking thread as holding
the lock before it gets a chance to finish invoking the scheduler.
2021-08-10 22:33:50 +02:00
Andreas Kling
364134ad4b Kernel/SMP: Skip thread registers in core dump if there is no trap frame
We can only get thread registers if there's a trap frame.
2021-08-10 02:49:37 +02:00
Andreas Kling
9babb92a4b Kernel/SMP: Make entering/leaving critical sections multi-processor safe
By making these functions static we close a window where we could get
preempted after calling Processor::current() and move to another
processor.

Co-authored-by: Tom <tomut@yahoo.com>
2021-08-10 02:49:37 +02:00
Andreas Kling
b197fc40a7 Kernel: Port process thread lists to SpinLockProtectedValue
I had to move the thread list out of the protected base area of Process
so that it could live with its lock (which needs to be mutable).
Ideally it would live in the protected area, so maybe we can figure out
a way to do that later.
2021-08-07 13:46:16 +02:00
Jean-Baptiste Boric
479b07339c Kernel: Move LockMode into Locking/ 2021-08-07 11:48:00 +02:00
Andreas Kling
cd5faf4e42 Kernel: Rename Range => VirtualRange
...and also RangeAllocator => VirtualRangeAllocator.

This clarifies that the ranges we're dealing with are *virtual* memory
ranges and not anything else.
2021-08-06 14:05:58 +02:00