blob: 6bba7fcc40108377cb8e7d195e6e73abe77c96ea [file] [log] [blame]
// Copyright 2018 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.
#pragma once
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <lib/async/cpp/wait.h>
#include <threads.h>
#include <lib/zx/event.h>
#include "id-map.h"
namespace display {
class FenceReference;
class Fence;
class FenceCallback {
public:
virtual void OnFenceFired(FenceReference* ref) = 0;
virtual void OnRefForFenceDead(Fence* fence) = 0;
};
// Class which wraps an event into a fence. A single Fence can have multiple FenceReference
// objects, which allows an event to be treated as a semaphore independently of it being
// imported/released (i.e. can be released while still in use).
class Fence : public fbl::RefCounted<Fence>, public IdMappable<fbl::RefPtr<Fence>> {
public:
Fence(FenceCallback* cb, async_dispatcher_t* dispatcher, uint64_t id, zx::event&& event);
~Fence();
// Creates a new FenceReference when an event is imported.
bool CreateRef();
// Clears a FenceReference when an event is released. Note that references to the cleared
// FenceReference might still exist within the driver.
void ClearRef();
// Decrements the reference count and returns true if the last ref died.
bool OnRefDead();
// Gets the fence reference for the current import. An individual fence reference cannot
// be used for multiple things simultaneously.
fbl::RefPtr<FenceReference> GetReference();
private:
void Signal();
void OnRefDied();
zx_status_t OnRefArmed(fbl::RefPtr<FenceReference>&& ref);
void OnRefDisarmed(FenceReference* ref);
// The fence reference corresponding to the current event import.
fbl::RefPtr<FenceReference> cur_ref_;
// A queue of fence references which are being waited upon. When the event is
// signaled, the signal will be cleared and the first fence ref will be marked ready.
fbl::DoublyLinkedList<fbl::RefPtr<FenceReference>> armed_refs_;
void OnReady(async_dispatcher_t* dispatcher, async::WaitBase* self,
zx_status_t status, const zx_packet_signal_t* signal);
async::WaitMethod<Fence, &Fence::OnReady> ready_wait_{this};
FenceCallback* cb_;
async_dispatcher_t* dispatcher_;
zx::event event_;
int ref_count_ = 0;
friend FenceReference;
DISALLOW_COPY_ASSIGN_AND_MOVE(Fence);
};
class FenceReference : public fbl::RefCounted<FenceReference>
, public fbl::DoublyLinkedListable<fbl::RefPtr<FenceReference>> {
public:
explicit FenceReference(fbl::RefPtr<Fence> fence);
~FenceReference();
void Signal();
zx_status_t StartReadyWait();
void ResetReadyWait();
// Sets the fence which will be signaled immediately when this fence is ready.
void SetImmediateRelease(fbl::RefPtr<FenceReference>&& fence);
void OnReady();
private:
fbl::RefPtr<Fence> fence_;
fbl::RefPtr<FenceReference> release_fence_;
DISALLOW_COPY_ASSIGN_AND_MOVE(FenceReference);
};
} // namespace display