/* * Copyright (c) 2020, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include namespace Kernel { class Device; extern WorkQueue* g_io_work; class AsyncDeviceRequest : public RefCounted { AK_MAKE_NONCOPYABLE(AsyncDeviceRequest); AK_MAKE_NONMOVABLE(AsyncDeviceRequest); public: enum [[nodiscard]] RequestResult { Pending = 0, Started, Success, Failure, MemoryFault, Cancelled }; class RequestWaitResult { friend class AsyncDeviceRequest; public: RequestResult request_result() const { return m_request_result; } Thread::BlockResult wait_result() const { return m_wait_result; } private: RequestWaitResult(RequestResult request_result, Thread::BlockResult wait_result) : m_request_result(request_result) , m_wait_result(wait_result) { } RequestResult m_request_result; Thread::BlockResult m_wait_result; }; virtual ~AsyncDeviceRequest(); virtual StringView name() const = 0; virtual void start() = 0; void add_sub_request(NonnullRefPtr); [[nodiscard]] RequestWaitResult wait(Time* = nullptr); void do_start(ScopedSpinLock>&& requests_lock) { if (is_completed_result(m_result)) return; m_result = Started; requests_lock.unlock(); start(); } void complete(RequestResult result); void set_private(void* priv) { VERIFY(!m_private || !priv); m_private = priv; } void* get_private() const { return m_private; } template [[nodiscard]] bool write_to_buffer(UserOrKernelBuffer& buffer, Args... args) { if (in_target_context(buffer)) return buffer.write(forward(args)...); ProcessPagingScope paging_scope(m_process); return buffer.write(forward(args)...); } template [[nodiscard]] KResultOr write_to_buffer_buffered(UserOrKernelBuffer& buffer, Args... args) { if (in_target_context(buffer)) return buffer.write_buffered(forward(args)...); ProcessPagingScope paging_scope(m_process); return buffer.write_buffered(forward(args)...); } template [[nodiscard]] bool read_from_buffer(const UserOrKernelBuffer& buffer, Args... args) { if (in_target_context(buffer)) return buffer.read(forward(args)...); ProcessPagingScope paging_scope(m_process); return buffer.read(forward(args)...); } template [[nodiscard]] KResultOr read_from_buffer_buffered(const UserOrKernelBuffer& buffer, Args... args) { if (in_target_context(buffer)) return buffer.read_buffered(forward(args)...); ProcessPagingScope paging_scope(m_process); return buffer.read_buffered(forward(args)...); } protected: AsyncDeviceRequest(Device&); RequestResult get_request_result() const; private: void sub_request_finished(AsyncDeviceRequest&); void request_finished(); [[nodiscard]] bool in_target_context(const UserOrKernelBuffer& buffer) const { if (buffer.is_kernel_buffer()) return true; return m_process == Process::current(); } [[nodiscard]] static bool is_completed_result(RequestResult result) { return result > Started; } Device& m_device; AsyncDeviceRequest* m_parent_request { nullptr }; RequestResult m_result { Pending }; IntrusiveListNode> m_list_node; typedef IntrusiveList, &AsyncDeviceRequest::m_list_node> AsyncDeviceSubRequestList; AsyncDeviceSubRequestList m_sub_requests_pending; AsyncDeviceSubRequestList m_sub_requests_complete; WaitQueue m_queue; NonnullRefPtr m_process; void* m_private { nullptr }; mutable SpinLock m_lock; }; }