1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/intrusive_double_list.h>
8 #include <fbl/ref_counted.h>
9 #include <fbl/ref_ptr.h>
10 #include <lib/async/cpp/wait.h>
11 #include <threads.h>
12 #include <lib/zx/event.h>
13 
14 #include "id-map.h"
15 
16 namespace display {
17 
18 class FenceReference;
19 class Fence;
20 
21 class FenceCallback {
22 public:
23     virtual void OnFenceFired(FenceReference* ref) = 0;
24     virtual void OnRefForFenceDead(Fence* fence) = 0;
25 };
26 
27 // Class which wraps an event into a fence. A single Fence can have multiple FenceReference
28 // objects, which allows an event to be treated as a semaphore independently of it being
29 // imported/released (i.e. can be released while still in use).
30 class Fence : public fbl::RefCounted<Fence>, public IdMappable<fbl::RefPtr<Fence>> {
31 public:
32     Fence(FenceCallback* cb, async_dispatcher_t* dispatcher, uint64_t id, zx::event&& event);
33     ~Fence();
34 
35     // Creates a new FenceReference when an event is imported.
36     bool CreateRef();
37     // Clears a FenceReference when an event is released. Note that references to the cleared
38     // FenceReference might still exist within the driver.
39     void ClearRef();
40     // Decrements the reference count and returns true if the last ref died.
41     bool OnRefDead();
42 
43     // Gets the fence reference for the current import. An individual fence reference cannot
44     // be used for multiple things simultaniously.
45     fbl::RefPtr<FenceReference> GetReference();
46 private:
47     void Signal();
48     void OnRefDied();
49     zx_status_t OnRefArmed(fbl::RefPtr<FenceReference>&& ref);
50     void OnRefDisarmed(FenceReference* ref);
51 
52     // The fence reference corresponding to the current event import.
53     fbl::RefPtr<FenceReference> cur_ref_;
54 
55     // A queue of fence references which are being waited upon. When the event is
56     // signaled, the signal will be cleared and the first fence ref will be marked ready.
57     fbl::DoublyLinkedList<fbl::RefPtr<FenceReference>> armed_refs_;
58 
59     void OnReady(async_dispatcher_t* dispatcher, async::WaitBase* self,
60                  zx_status_t status, const zx_packet_signal_t* signal);
61     async::WaitMethod<Fence, &Fence::OnReady> ready_wait_{this};
62 
63     FenceCallback* cb_;
64     async_dispatcher_t* dispatcher_;
65     zx::event event_;
66     int ref_count_ = 0;
67 
68     friend FenceReference;
69 
70     DISALLOW_COPY_ASSIGN_AND_MOVE(Fence);
71 };
72 
73 class FenceReference : public fbl::RefCounted<FenceReference>
74                      , public fbl::DoublyLinkedListable<fbl::RefPtr<FenceReference>> {
75 public:
76     explicit FenceReference(fbl::RefPtr<Fence> fence);
77     ~FenceReference();
78 
79     void Signal();
80 
81     zx_status_t StartReadyWait();
82     void ResetReadyWait();
83     // Sets the fence which will be signaled immedately when this fence is ready.
84     void SetImmediateRelease(fbl::RefPtr<FenceReference>&& fence);
85 
86     void OnReady();
87 private:
88     fbl::RefPtr<Fence> fence_;
89 
90     fbl::RefPtr<FenceReference> release_fence_;
91 
92     DISALLOW_COPY_ASSIGN_AND_MOVE(FenceReference);
93 };
94 
95 } // namespace display
96