1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef STAGEFRIGHT_CODEC2_SURFACE_SYNC_OBJ_H_
18 #define STAGEFRIGHT_CODEC2_SURFACE_SYNC_OBJ_H_
19 
20 #include <cutils/native_handle.h>
21 #include <memory>
22 #include <atomic>
23 
24 #include <C2Buffer.h>
25 
26 /**
27  * Futex based lock / wait implementation for sharing output buffer allocation
28  * information between Framework and HAL.
29  */
30 struct C2SyncVariables {
31     enum SyncStatus : uint32_t {
32            STATUS_INIT = 0,         // When surface configuration starts.
33            STATUS_ACTIVE = 1,       // When surface configuration finishs.
34                                     // STATUS_INIT -> STATUS_ACTIVE
35            STATUS_SWITCHING = 2,    // When the surface is replaced by a new surface
36                                     // during surface configuration.
37                                     // STATUS_ACTIVE -> STATUS_SWITCHING
38     };
39 
40     /**
41      * Lock the memory region
42      */
43     int lock();
44 
45     /**
46      * Unlock the memory region
47      */
48     int unlock();
49 
50     /**
51      * Set initial dequeued buffer count.
52      *
53      * \param maxDequeueCount           Initial value of # of max dequeued buffer count
54      * \param curDequeueCount           Initial value of # of current dequeued buffer count
55      */
56     void setInitialDequeueCountLocked(int32_t maxDequeueCount, int32_t curDequeueCount);
57 
58     /**
59      * Get a waitId which will be used to implement fence.
60      */
61     uint32_t getWaitIdLocked();
62 
63     /**
64      * Return whether the upcoming dequeue operation is not blocked.
65      * if it's blocked and waitId is non-null, waitId is returned to be used for waiting.
66      *
67      * \retval false    dequeue operation is blocked now.
68      * \retval true     dequeue operation is possible.
69      */
70     bool isDequeueableLocked(uint32_t *waitId = nullptr);
71 
72     /**
73      * Notify a buffer is queued. Return whether the upcoming dequeue operation
74      * is not blocked. if it's blocked and waitId is non-null, waitId is returned
75      * to be used for waiting. Notify(wake-up) waitors only when 'notify' is
76      * true.
77      *
78      * \retval false    dequeue operation is blocked now.
79      * \retval true     dequeue operation is possible.
80      */
81     bool notifyQueuedLocked(uint32_t *waitId = nullptr, bool notify = true);
82 
83     /**
84      * Notify a buffer is dequeued.
85      */
86     void notifyDequeuedLocked();
87 
88     /**
89      * Set sync status.
90      */
91     void setSyncStatusLocked(SyncStatus status);
92 
93     /**
94      * Get sync status.
95      */
96     C2SyncVariables::SyncStatus getSyncStatusLocked();
97 
98     /**
99      * Update current max dequeue count.
100      */
101     void updateMaxDequeueCountLocked(int32_t maxDequeueCount);
102 
103     /**
104      * Wait until status is no longer equal to waitId, or until timeout.
105      *
106      * \param waitId            internal status for waiting until it is changed.
107      * \param timeousNs         nano seconds to timeout.
108      *
109      * \retval C2_TIMEDOUT      change does not happen during waiting.
110      * \retval C2_BAD_VALUE     invalid event waiting.
111      * \retval C2_OK            change was signalled.
112      */
113     c2_status_t waitForChange(uint32_t waitId, c2_nsecs_t timeoutNs);
114 
115     /**
116      * Wake up and expire all waitors.
117      */
118     void notifyAll();
119 
120     /**
121      * Invalide current sync variables on the death of the other process.
122      */
123     void invalidate();
124 
125     /**
126      * If a dead process holds the lock, clear the lock.
127      */
128     void clearLockIfNecessary();
129 
C2SyncVariablesC2SyncVariables130     C2SyncVariables() {}
131 
132 private:
133     /**
134      * signal one waiter to wake up.
135      */
136     int signal();
137 
138     /**
139      * signal all waiter to wake up.
140      */
141     int broadcast();
142 
143     /**
144      * wait for signal or broadcast.
145      */
146     int wait();
147 
148     /**
149      * try lock for the specified duration.
150      */
151     bool tryLockFor(size_t ms);
152 
153     std::atomic<uint32_t> mLock;
154     std::atomic<uint32_t> mCond;
155     int32_t mMaxDequeueCount;
156     int32_t mCurDequeueCount;
157     SyncStatus mStatus;
158 };
159 
160 /**
161  * Shared memory in order to synchronize information for Surface(IGBP)
162  * based output buffer allocation.
163  */
164 class C2SurfaceSyncMemory {
165 public:
166     /**
167      * Shared memory handle in order to synchronize information for
168      * Surface based output buffer allocation.
169      */
170     struct HandleSyncMem : public native_handle_t {
HandleSyncMemHandleSyncMem171         HandleSyncMem(int fd, size_t size) :
172             native_handle_t(cHeader),
173             mFds{fd},
174             mInts{int(size & 0xFFFFFFFF),
175                 int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic} {}
176 
177         /** Returns a file descriptor of the shared memory
178          * \return a file descriptor representing the shared memory
179          */
memFdHandleSyncMem180         int memFd() const {return mFds.mMem;}
181 
182         /** Returns the size of the shared memory */
sizeHandleSyncMem183         size_t size() const {
184             return size_t(unsigned(mInts.mSizeLo))
185                     | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
186         }
187 
188         /** Check whether the native handle is in the form of HandleSyncMem
189          *
190          * \return whether the native handle is compatible
191          */
192         static bool isValid(const native_handle_t * const o);
193 
194     protected:
195         struct {
196             int mMem;
197         } mFds;
198         struct {
199             int mSizeLo;
200             int mSizeHi;
201             int mMagic;
202         } mInts;
203     private:
204         enum {
205             kMagic = 'ssm\x00',
206             numFds = sizeof(mFds) / sizeof(int),
207             numInts = sizeof(mInts) / sizeof(int),
208             version = sizeof(native_handle_t)
209         };
210         const static native_handle_t cHeader;
211     };
212 
213     /**
214      * Imports a shared memory object from a native handle(The shared memory is already existing).
215      * This is usually used after native_handle_t is passed via RPC.
216      *
217      * \param handle        handle representing shared memory for output buffer allocation.
218      */
219     static std::shared_ptr<C2SurfaceSyncMemory> Import(native_handle_t *handle);
220 
221     /**
222      * Creats a shared memory object for synchronization of output buffer allocation.
223      * Shared memory creation should be done explicitly.
224      *
225      * \param fd            file descriptor to shared memory
226      * \param size          size of the shared memory
227      */
228     static std::shared_ptr<C2SurfaceSyncMemory> Create(int fd, size_t size);
229 
230     /**
231      * Returns a handle representing the shread memory for synchronization of
232      * output buffer allocation.
233      */
234     native_handle_t *handle();
235 
236     /**
237      * Returns synchronization object which will provide synchronization primitives.
238      *
239      * \return a ptr to synchronization primitive class
240      */
241     C2SyncVariables *mem();
242 
243     ~C2SurfaceSyncMemory();
244 
245 private:
246     bool mInit;
247     HandleSyncMem *mHandle;
248     C2SyncVariables *mMem;
249 
250     C2SurfaceSyncMemory();
251 };
252 
253 #endif // STAGEFRIGHT_CODEC2_SURFACE_SYNC_OBJ_H_
254