mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
Kernel: Introduce a EINTR-only error type
This class should be used instead of Error in code paths shared between kernel and user processes that cannot fail, but may be interrupted while running in a user process. This generally includes code that may block on a WaitQueue or a Mutex.
This commit is contained in:
1 parent
f330858208
commit
44658063c0
4 files changed
+43
-18
No files matched your search
@@ -220,13 +220,9 @@ ErrorOr<NonnullOwnPtr<KBuffer>> FUSEDevice::send_request_and_wait_for_a_reply(Op
|
||||
// Deal with that by just running the handler manually.
|
||||
set_timed_out();
|
||||
|
||||
auto wait_status = m_instance_queue.wait_until(m_instances, receive_reply);
|
||||
auto maybe_interrupted = m_instance_queue.wait_until(m_instances, receive_reply);
|
||||
TimerQueue::the().cancel_timer(*timer);
|
||||
|
||||
if (wait_status.is_error()) {
|
||||
VERIFY(wait_status.error().code() == EINTR);
|
||||
return wait_status.release_error();
|
||||
}
|
||||
TRY(maybe_interrupted);
|
||||
|
||||
if (reply_or_error.is_error())
|
||||
return reply_or_error.release_error();
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Lucas Chollet <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Error.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class [[nodiscard]] Interrupted {
|
||||
public:
|
||||
constexpr Interrupted() = default;
|
||||
constexpr operator Error() const
|
||||
{
|
||||
return Error::from_errno(EINTR);
|
||||
}
|
||||
};
|
||||
|
||||
// This class should be used instead of ErrorOr in code paths shared between
|
||||
// kernel and user processes that cannot fail, but may be interrupted while
|
||||
// running in a user process. This generally includes code that may block on
|
||||
// a WaitQueue or a Mutex.
|
||||
template<typename T>
|
||||
using InterruptedOr = ErrorOr<T, Interrupted>;
|
||||
|
||||
}
|
||||
@@ -48,16 +48,15 @@ void CadenceGEMNetworkAdapter::send_raw(ReadonlyBytes data)
|
||||
|
||||
auto* descriptor = tx_descriptor_entry(m_tx_enqueue_index);
|
||||
|
||||
ErrorOr<void> maybe_error {};
|
||||
InterruptedOr<void> maybe_interrupted {};
|
||||
do {
|
||||
maybe_error = m_wait_queue.wait_until([&descriptor]() {
|
||||
maybe_interrupted = m_wait_queue.wait_until([&descriptor]() {
|
||||
// Inform the compiler that the contents of DMA regions might have changed,
|
||||
// even if it didn't see any writes to them.
|
||||
optimizer_fence();
|
||||
return descriptor->is_software_owned;
|
||||
});
|
||||
} while (maybe_error.is_error() && maybe_error.error().code() == EINTR);
|
||||
VERIFY(!maybe_error.is_error());
|
||||
} while (maybe_interrupted.is_error());
|
||||
|
||||
// Ensure that the software owned check is done before writing the descriptor and buffer data.
|
||||
full_memory_fence();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <AK/IntrusiveList.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <Kernel/Forward.h>
|
||||
#include <Kernel/Library/Interrupted.h>
|
||||
#include <Kernel/Locking/Spinlock.h>
|
||||
#include <Kernel/Locking/SpinlockProtected.h>
|
||||
#include <Kernel/Tasks/Thread.h>
|
||||
@@ -20,20 +21,20 @@ class WaitQueue {
|
||||
class Waiter {
|
||||
public:
|
||||
template<CallableAs<bool> F>
|
||||
ErrorOr<void> wait_until(WaitQueue& wait_queue, F should_wake)
|
||||
InterruptedOr<void> wait_until(WaitQueue& wait_queue, F should_wake)
|
||||
{
|
||||
// LockRank::None is just a dummy value.
|
||||
return wait_until_impl<LockRank::None>(wait_queue, should_wake, OptionalNone {});
|
||||
}
|
||||
|
||||
template<LockRank Rank, CallableAs<bool> F>
|
||||
ErrorOr<void> wait_until(WaitQueue& wait_queue, Spinlock<Rank>& lock, F should_wake)
|
||||
InterruptedOr<void> wait_until(WaitQueue& wait_queue, Spinlock<Rank>& lock, F should_wake)
|
||||
{
|
||||
return wait_until_impl(wait_queue, should_wake, lock);
|
||||
}
|
||||
|
||||
template<typename T, LockRank Rank, CallableAs<bool, T&> F>
|
||||
ErrorOr<void> wait_until(WaitQueue& wait_queue, SpinlockProtected<T, Rank>& spinlock_protected, F should_wake)
|
||||
InterruptedOr<void> wait_until(WaitQueue& wait_queue, SpinlockProtected<T, Rank>& spinlock_protected, F should_wake)
|
||||
{
|
||||
return wait_until_impl<Rank>(wait_queue, [&spinlock_protected, &should_wake] { return should_wake(spinlock_protected.m_value); }, spinlock_protected.m_spinlock);
|
||||
}
|
||||
@@ -42,7 +43,7 @@ class WaitQueue {
|
||||
|
||||
private:
|
||||
template<LockRank Rank, CallableAs<bool> F>
|
||||
ErrorOr<void> wait_until_impl(WaitQueue& wait_queue, F should_wake, Optional<Spinlock<Rank>&> user_lock)
|
||||
InterruptedOr<void> wait_until_impl(WaitQueue& wait_queue, F should_wake, Optional<Spinlock<Rank>&> user_lock)
|
||||
{
|
||||
bool was_interrupted = false;
|
||||
|
||||
@@ -87,7 +88,7 @@ class WaitQueue {
|
||||
// but we still need to clear it.
|
||||
Thread::current()->clear_interrupted();
|
||||
if (was_interrupted) {
|
||||
return EINTR;
|
||||
return Interrupted {};
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -116,21 +117,21 @@ public:
|
||||
void notify_one();
|
||||
|
||||
template<CallableAs<bool> F>
|
||||
ErrorOr<void> wait_until(F should_wake)
|
||||
InterruptedOr<void> wait_until(F should_wake)
|
||||
{
|
||||
Waiter waiter;
|
||||
return waiter.wait_until(*this, move(should_wake));
|
||||
}
|
||||
|
||||
template<LockRank Rank, CallableAs<bool> F>
|
||||
ErrorOr<void> wait_until(Spinlock<Rank>& lock, F should_wake)
|
||||
InterruptedOr<void> wait_until(Spinlock<Rank>& lock, F should_wake)
|
||||
{
|
||||
Waiter waiter;
|
||||
return waiter.wait_until(*this, lock, move(should_wake));
|
||||
}
|
||||
|
||||
template<typename T, LockRank Rank, CallableAs<bool, T&> F>
|
||||
ErrorOr<void> wait_until(SpinlockProtected<T, Rank>& spinlock_protected, F should_wake)
|
||||
InterruptedOr<void> wait_until(SpinlockProtected<T, Rank>& spinlock_protected, F should_wake)
|
||||
{
|
||||
Waiter waiter;
|
||||
return waiter.wait_until(*this, spinlock_protected, move(should_wake));
|
||||
|
||||
Reference in new issue
Block a user