| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef IO_SCHEDULER_STREAM_H_ |
| #define IO_SCHEDULER_STREAM_H_ |
| |
| #include <zircon/types.h> |
| |
| #include <fbl/intrusive_double_list.h> |
| #include <fbl/intrusive_wavl_tree.h> |
| #include <fbl/macros.h> |
| #include <fbl/mutex.h> |
| #include <fbl/ref_counted.h> |
| #include <fbl/ref_ptr.h> |
| #include <io-scheduler/scheduler-client.h> |
| #include <io-scheduler/stream-op.h> |
| |
| namespace ioscheduler { |
| |
| constexpr uint32_t kStreamFlagIsClosed = (1u << 0); |
| constexpr uint32_t kStreamFlagHasDeferred = (1u << 1); |
| |
| class Scheduler; |
| class Stream; |
| using StreamRef = fbl::RefPtr<Stream>; |
| |
| // Tag Types used to manage the different intrusive containers that a Stream can |
| // exist in. |
| namespace internal { |
| struct StreamMapTag {}; |
| struct StreamReadyListTag {}; |
| struct StreamDeferredListTag {}; |
| } // namespace internal |
| |
| // Stream - a logical sequence of ops. |
| // The Stream class is not thread safe, streams depend on the scheduler for synchronization. |
| class Stream : public fbl::RefCounted<Stream>, |
| public fbl::ContainableBaseClasses< |
| fbl::TaggedWAVLTreeContainable<StreamRef, internal::StreamMapTag>, |
| fbl::TaggedDoublyLinkedListable<StreamRef, internal::StreamReadyListTag>, |
| fbl::TaggedDoublyLinkedListable<StreamRef, internal::StreamDeferredListTag>> { |
| public: |
| struct KeyTraitsSortById { |
| static const uint32_t& GetKey(const Stream& s) { return s.id_; } |
| static bool LessThan(const uint32_t s1, const uint32_t s2) { return (s1 < s2); } |
| static bool EqualTo(const uint32_t s1, const uint32_t s2) { return (s1 == s2); } |
| }; |
| |
| using MapTag = internal::StreamMapTag; |
| using ReadyListTag = internal::StreamReadyListTag; |
| using DeferredListTag = internal::StreamDeferredListTag; |
| |
| using WAVLTreeSortById = fbl::TaggedWAVLTree<uint32_t, StreamRef, MapTag, KeyTraitsSortById>; |
| using ReadyStreamList = fbl::TaggedDoublyLinkedList<StreamRef, ReadyListTag>; |
| using DeferredStreamList = fbl::TaggedDoublyLinkedList<StreamRef, DeferredListTag>; |
| |
| Stream() = delete; |
| Stream(uint32_t id, uint32_t pri); |
| ~Stream(); |
| DISALLOW_COPY_ASSIGN_AND_MOVE(Stream); |
| |
| uint32_t id() { return id_; } |
| uint32_t priority() { return priority_; } |
| bool is_closed() { return (flags_ & kStreamFlagIsClosed); } |
| |
| inline uint32_t flags() { return flags_; } |
| inline void set_flags(uint32_t flags) { flags_ |= flags; } |
| inline void clear_flags(uint32_t flags) { flags_ &= ~flags; } |
| |
| inline bool IsEmpty() { return ready_ops_.is_empty() && issued_ops_.is_empty(); } |
| inline bool HasReady() { return !ready_ops_.is_empty(); } |
| inline bool HasDefered() { return !deferred_ops_.is_empty(); } |
| |
| // Close a stream. |
| // Returns: |
| // ZX_OK if stream is empty and ready for immediate release. |
| // ZX_ERR_SHOULD_WAIT is stream has pending operations. It will be released by worker threads |
| // or the shutdown routine. |
| zx_status_t Close(); |
| |
| // Insert an op into the tail of the stream (subject to reordering). |
| // On error op's error status is set and it is moved to |*op_err|. |
| zx_status_t Insert(UniqueOp op, UniqueOp* op_err); |
| |
| // Fetch a pointer to an op from the head of the stream. |
| // The stream maintains ownership of the op. All fetched op must be returned via ReleaseOp(). |
| void GetNext(UniqueOp* op_out); |
| |
| // Set an op as deferred for later completion. |
| void Defer(UniqueOp op); |
| |
| // Get an op pending completion. |
| void GetDeferred(UniqueOp* op_out); |
| |
| // Marks an op obtained via GetNext() or GetDeferred() as complete. |
| // Op is not consumed. |
| void Complete(StreamOp* op); |
| |
| private: |
| friend struct KeyTraitsSortById; |
| |
| uint32_t id_; |
| uint32_t priority_; |
| |
| uint32_t flags_ = 0; |
| StreamOp::OpList ready_ops_; // Ops ready to be issued. |
| StreamOp::OpList issued_ops_; // Issued ops pending completion. |
| StreamOp::DeferredList deferred_ops_; // Ops whose completion has been deferred. |
| }; |
| |
| } // namespace ioscheduler |
| |
| #endif // IO_SCHEDULER_STREAM_H_ |