AK+Kernel: Handle allocation failures in Device::try_make_request

This adds try_* methods to AK::DoublyLinkedList and updates the Device
class to use those to gracefully handle allocation failures.

Refs #6369.
This commit is contained in:
Gunnar Beutner 2022-11-01 10:17:26 +01:00 committed by Linus Groh
parent b33834ca3a
commit ab8b043684
Notes: sideshowbarker 2024-07-17 20:33:50 +09:00
2 changed files with 28 additions and 7 deletions

View file

@ -7,6 +7,7 @@
#pragma once #pragma once
#include <AK/Assertions.h> #include <AK/Assertions.h>
#include <AK/Error.h>
#include <AK/Find.h> #include <AK/Find.h>
#include <AK/StdLibExtras.h> #include <AK/StdLibExtras.h>
@ -91,42 +92,62 @@ public:
} }
template<typename U> template<typename U>
void append(U&& value) ErrorOr<void> try_append(U&& value)
{ {
static_assert( static_assert(
requires { T(value); }, "Conversion operator is missing."); requires { T(value); }, "Conversion operator is missing.");
auto* node = new Node(forward<U>(value)); auto* node = new (nothrow) Node(forward<U>(value));
if (!node)
return Error::from_errno(ENOMEM);
if (!m_head) { if (!m_head) {
VERIFY(!m_tail); VERIFY(!m_tail);
m_head = node; m_head = node;
m_tail = node; m_tail = node;
return; return {};
} }
VERIFY(m_tail); VERIFY(m_tail);
VERIFY(!node->next); VERIFY(!node->next);
m_tail->next = node; m_tail->next = node;
node->prev = m_tail; node->prev = m_tail;
m_tail = node; m_tail = node;
return {};
} }
template<typename U> template<typename U>
void prepend(U&& value) ErrorOr<void> try_prepend(U&& value)
{ {
static_assert(IsSame<T, U>); static_assert(IsSame<T, U>);
auto* node = new Node(forward<U>(value)); auto* node = new (nothrow) Node(forward<U>(value));
if (!node)
return Error::from_errno(ENOMEM);
if (!m_head) { if (!m_head) {
VERIFY(!m_tail); VERIFY(!m_tail);
m_head = node; m_head = node;
m_tail = node; m_tail = node;
return; return {};
} }
VERIFY(m_tail); VERIFY(m_tail);
VERIFY(!node->prev); VERIFY(!node->prev);
m_head->prev = node; m_head->prev = node;
node->next = m_head; node->next = m_head;
m_head = node; m_head = node;
return {};
} }
#ifndef KERNEL
template<typename U>
void append(U&& value)
{
MUST(try_append(forward<U>(value)));
}
template<typename U>
void prepend(U&& value)
{
MUST(try_prepend(forward<U>(value)));
}
#endif
[[nodiscard]] bool contains_slow(const T& value) const [[nodiscard]] bool contains_slow(const T& value) const
{ {
return find(value) != end(); return find(value) != end();

View file

@ -58,7 +58,7 @@ public:
auto request = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) AsyncRequestType(*this, forward<Args>(args)...))); auto request = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) AsyncRequestType(*this, forward<Args>(args)...)));
SpinlockLocker lock(m_requests_lock); SpinlockLocker lock(m_requests_lock);
bool was_empty = m_requests.is_empty(); bool was_empty = m_requests.is_empty();
m_requests.append(request); TRY(m_requests.try_append(request));
if (was_empty) if (was_empty)
request->do_start(move(lock)); request->do_start(move(lock));
return request; return request;