AsyncDeviceRequest.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2020, The SerenityOS developers.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #pragma once
  27. #include <AK/IntrusiveList.h>
  28. #include <AK/NonnullRefPtr.h>
  29. #include <Kernel/Process.h>
  30. #include <Kernel/Thread.h>
  31. #include <Kernel/UserOrKernelBuffer.h>
  32. #include <Kernel/VM/ProcessPagingScope.h>
  33. #include <Kernel/WaitQueue.h>
  34. namespace Kernel {
  35. class Device;
  36. extern WorkQueue* g_io_work;
  37. class AsyncDeviceRequest : public RefCounted<AsyncDeviceRequest> {
  38. AK_MAKE_NONCOPYABLE(AsyncDeviceRequest);
  39. AK_MAKE_NONMOVABLE(AsyncDeviceRequest);
  40. public:
  41. enum [[nodiscard]] RequestResult {
  42. Pending = 0,
  43. Started,
  44. Success,
  45. Failure,
  46. MemoryFault,
  47. Cancelled
  48. };
  49. class RequestWaitResult {
  50. friend class AsyncDeviceRequest;
  51. public:
  52. RequestResult request_result() const { return m_request_result; }
  53. Thread::BlockResult wait_result() const { return m_wait_result; }
  54. private:
  55. RequestWaitResult(RequestResult request_result, Thread::BlockResult wait_result)
  56. : m_request_result(request_result)
  57. , m_wait_result(wait_result)
  58. {
  59. }
  60. RequestResult m_request_result;
  61. Thread::BlockResult m_wait_result;
  62. };
  63. virtual ~AsyncDeviceRequest();
  64. virtual const char* name() const = 0;
  65. virtual void start() = 0;
  66. void add_sub_request(NonnullRefPtr<AsyncDeviceRequest>);
  67. [[nodiscard]] RequestWaitResult wait(Time* = nullptr);
  68. void do_start(ScopedSpinLock<SpinLock<u8>>&& requests_lock)
  69. {
  70. if (is_completed_result(m_result))
  71. return;
  72. m_result = Started;
  73. requests_lock.unlock();
  74. start();
  75. }
  76. void complete(RequestResult result);
  77. void set_private(void* priv)
  78. {
  79. VERIFY(!m_private || !priv);
  80. m_private = priv;
  81. }
  82. void* get_private() const { return m_private; }
  83. template<typename... Args>
  84. [[nodiscard]] bool write_to_buffer(UserOrKernelBuffer& buffer, Args... args)
  85. {
  86. if (in_target_context(buffer))
  87. return buffer.write(forward<Args>(args)...);
  88. ProcessPagingScope paging_scope(m_process);
  89. return buffer.write(forward<Args>(args)...);
  90. }
  91. template<size_t BUFFER_BYTES, typename... Args>
  92. [[nodiscard]] bool write_to_buffer_buffered(UserOrKernelBuffer& buffer, Args... args)
  93. {
  94. if (in_target_context(buffer))
  95. return buffer.write_buffered<BUFFER_BYTES>(forward<Args>(args)...);
  96. ProcessPagingScope paging_scope(m_process);
  97. return buffer.write_buffered<BUFFER_BYTES>(forward<Args>(args)...);
  98. }
  99. template<typename... Args>
  100. [[nodiscard]] bool read_from_buffer(const UserOrKernelBuffer& buffer, Args... args)
  101. {
  102. if (in_target_context(buffer))
  103. return buffer.read(forward<Args>(args)...);
  104. ProcessPagingScope paging_scope(m_process);
  105. return buffer.read(forward<Args>(args)...);
  106. }
  107. template<size_t BUFFER_BYTES, typename... Args>
  108. [[nodiscard]] bool read_from_buffer_buffered(const UserOrKernelBuffer& buffer, Args... args)
  109. {
  110. if (in_target_context(buffer))
  111. return buffer.read_buffered<BUFFER_BYTES>(forward<Args>(args)...);
  112. ProcessPagingScope paging_scope(m_process);
  113. return buffer.read_buffered<BUFFER_BYTES>(forward<Args>(args)...);
  114. }
  115. protected:
  116. AsyncDeviceRequest(Device&);
  117. RequestResult get_request_result() const;
  118. private:
  119. void sub_request_finished(AsyncDeviceRequest&);
  120. void request_finished();
  121. [[nodiscard]] bool in_target_context(const UserOrKernelBuffer& buffer) const
  122. {
  123. if (buffer.is_kernel_buffer())
  124. return true;
  125. return m_process == Process::current();
  126. }
  127. [[nodiscard]] static bool is_completed_result(RequestResult result)
  128. {
  129. return result > Started;
  130. }
  131. Device& m_device;
  132. AsyncDeviceRequest* m_parent_request { nullptr };
  133. RequestResult m_result { Pending };
  134. IntrusiveListNode<AsyncDeviceRequest, RefPtr<AsyncDeviceRequest>> m_list_node;
  135. typedef IntrusiveList<AsyncDeviceRequest, RefPtr<AsyncDeviceRequest>, &AsyncDeviceRequest::m_list_node> AsyncDeviceSubRequestList;
  136. AsyncDeviceSubRequestList m_sub_requests_pending;
  137. AsyncDeviceSubRequestList m_sub_requests_complete;
  138. WaitQueue m_queue;
  139. NonnullRefPtr<Process> m_process;
  140. void* m_private { nullptr };
  141. mutable SpinLock<u8> m_lock;
  142. };
  143. }