blob: d45a4ab7eb0547e88791ddfe4620fc01e0dff1ad [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.
#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 {
class Scheduler;
class Stream;
using StreamRef = fbl::RefPtr<Stream>;
// 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:
Stream(uint32_t id, uint32_t pri, Scheduler* sched);
~Stream();
DISALLOW_COPY_ASSIGN_AND_MOVE(Stream);
uint32_t id() { return id_; }
uint32_t priority() { return priority_; }
// 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) __TA_EXCLUDES(lock_);
// 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) __TA_EXCLUDES(lock_);
// Releases an op obtained via GetNext().
void ReleaseOp(UniqueOp op, SchedulerClient* client);
// WAVL Tree support.
using WAVLTreeNodeState = fbl::WAVLTreeNodeState<StreamRef>;
struct WAVLTreeNodeTraitsSortById {
static WAVLTreeNodeState& node_state(Stream& s) { return s.map_node_; }
};
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 WAVLTreeSortById =
fbl::WAVLTree<uint32_t, StreamRef, KeyTraitsSortById, WAVLTreeNodeTraitsSortById>;
// List support.
using ListNodeState = fbl::DoublyLinkedListNodeState<StreamRef>;
struct ListTraitsUnsorted {
static ListNodeState& node_state(Stream& s) { return s.list_node_; }
};
using ListUnsorted = fbl::DoublyLinkedList<StreamRef, ListTraitsUnsorted>;
private:
friend struct WAVLTreeNodeTraitsSortById;
friend struct KeyTraitsSortById;
bool IsEmptyLocked() __TA_REQUIRES(lock_);
uint32_t id_;
uint32_t priority_;
// Used by the scheduler's stream maps. Access is protected by the scheduler lock.
WAVLTreeNodeState map_node_;
// Used by the queue's priority list. Access is protected by the queue lock.
ListNodeState list_node_;
// Pointer to the scheduler. Streams may not exist beyond the lifetime of the scheduler, so
// this pointer must always be valid.
Scheduler* sched_ = nullptr;
fbl::Mutex lock_;
bool open_ __TA_GUARDED(lock_) = true; // Stream is open, can accept more ops.
StreamOp::ActiveList in_list_ __TA_GUARDED(lock_); // Input list - ops yet to be issued.
StreamOp::ActiveList issued_list_ __TA_GUARDED(lock_); // Issued ops.
};
} // namespace ioscheduler
#endif // IO_SCHEDULER_STREAM_H_