blob: 81f00a9ebb270030b9334d944468f368ebb320a8 [file] [log] [blame]
// 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.
#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>> {
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);
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);
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