• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "buffer_loop_tracking.h"
17 #include "buffer_manager.h"
18 
19 namespace OHOS::Camera {
TrackingNode(std::string name)20 TrackingNode::TrackingNode(std::string name)
21 {
22     nodeName_ = name;
23 }
24 
~TrackingNode()25 TrackingNode::~TrackingNode()
26 {
27     {
28         std::lock_guard<std::mutex> l(lock_);
29         trackingBufferList_.clear();
30     }
31 }
32 
GetNodeName() const33 std::string TrackingNode::GetNodeName() const
34 {
35     return nodeName_;
36 }
37 
FindTrackingBuffer(const std::shared_ptr<TrackingBuffer> & buffer)38 std::shared_ptr<TrackingBuffer> TrackingNode::FindTrackingBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
39 {
40     if (buffer == nullptr) {
41         return nullptr;
42     }
43 
44     std::lock_guard<std::mutex> l(lock_);
45     auto it = std::find_if(trackingBufferList_.begin(), trackingBufferList_.end(),
46         [&buffer](const std::shared_ptr<TrackingBuffer>& b) {
47             return b->GetFrameNumber() == buffer->GetFrameNumber();
48         });
49     if (it == trackingBufferList_.end()) {
50         return nullptr;
51     }
52     return *it;
53 }
54 
AttachTrackingBuffer(const std::shared_ptr<TrackingBuffer> & buffer)55 void TrackingNode::AttachTrackingBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
56 {
57     {
58         std::lock_guard<std::mutex> l(lock_);
59         trackingBufferList_.emplace_back(buffer);
60     }
61 
62     return;
63 }
64 
DetachTrackingBuffer(const std::shared_ptr<TrackingBuffer> & buffer)65 void TrackingNode::DetachTrackingBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
66 {
67     {
68         std::lock_guard<std::mutex> l(lock_);
69         auto it = std::find_if(trackingBufferList_.begin(), trackingBufferList_.end(),
70             [&buffer](const std::shared_ptr<TrackingBuffer>& b) {
71                 return b->GetFrameNumber() == buffer->GetFrameNumber();
72             });
73         if (it != trackingBufferList_.end()) {
74             trackingBufferList_.erase(it);
75         }
76     }
77 
78     return;
79 }
80 
IsEmpty()81 bool TrackingNode::IsEmpty()
82 {
83     std::lock_guard<std::mutex> l(lock_);
84     return trackingBufferList_.empty();
85 }
86 
TrackingStream(const int32_t id)87 TrackingStream::TrackingStream(const int32_t id)
88 {
89     trackingId_ = id;
90 }
91 
~TrackingStream()92 TrackingStream::~TrackingStream()
93 {
94     {
95         std::lock_guard<std::mutex> l(lock_);
96         trackingNodeList_.clear();
97     }
98 }
99 
GetTrackingStreamId() const100 int32_t TrackingStream::GetTrackingStreamId() const
101 {
102     return trackingId_;
103 }
104 
FindTrackingNode(const std::string node)105 std::shared_ptr<TrackingNode> TrackingStream::FindTrackingNode(const std::string node)
106 {
107     std::lock_guard<std::mutex> l(lock_);
108     auto it = std::find_if(trackingNodeList_.begin(), trackingNodeList_.end(),
109                            [&node](const std::shared_ptr<TrackingNode>& n) { return n->GetNodeName() == node; });
110     if (it != trackingNodeList_.end()) {
111         return *it;
112     }
113 
114     return nullptr;
115 }
116 
AttachTrackingNode(const std::shared_ptr<TrackingNode> & node)117 void TrackingStream::AttachTrackingNode(const std::shared_ptr<TrackingNode>& node)
118 {
119     if (FindTrackingNode(node->GetNodeName()) != nullptr) {
120         return;
121     }
122 
123     {
124         std::lock_guard<std::mutex> l(lock_);
125         trackingNodeList_.emplace_back(node);
126     }
127 
128     return;
129 }
130 
DetachTrackingNode(const std::shared_ptr<TrackingNode> & node)131 void TrackingStream::DetachTrackingNode(const std::shared_ptr<TrackingNode>& node)
132 {
133     auto n = FindTrackingNode(node->GetNodeName());
134     if (n == nullptr) {
135         return;
136     }
137 
138     {
139         std::lock_guard<std::mutex> l(lock_);
140         auto it = std::find(trackingNodeList_.begin(), trackingNodeList_.end(), node);
141         if (it != trackingNodeList_.end()) {
142             trackingNodeList_.erase(it);
143         }
144     }
145 
146     return;
147 }
148 
LocateBuffer(const std::shared_ptr<TrackingBuffer> & buffer)149 std::shared_ptr<TrackingNode> TrackingStream::LocateBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
150 {
151     {
152         std::lock_guard<std::mutex> l(lock_);
153         for (auto& n : trackingNodeList_) {
154             if (n == nullptr) {
155                 CAMERA_LOGE("fatal error, tracking node list is corrupt.");
156                 return nullptr;
157             }
158             if (n->IsEmpty()) {
159                 continue;
160             }
161             if (n->FindTrackingBuffer(buffer) != nullptr) {
162                 return n;
163             }
164         }
165         return nullptr;
166     }
167 }
168 
MoveBuffer(std::shared_ptr<TrackingBuffer> & buffer,std::shared_ptr<TrackingNode> & node)169 void TrackingStream::MoveBuffer(std::shared_ptr<TrackingBuffer>& buffer, std::shared_ptr<TrackingNode>& node)
170 {
171     if (node == nullptr) {
172         CAMERA_LOGE("node is null, cannot track");
173         return;
174     }
175     auto dest = FindTrackingNode(node->GetNodeName());
176     if (dest == nullptr) {
177         CAMERA_LOGE("node %{public}s doesn't being tracked", node->GetNodeName().c_str());
178         return;
179     }
180 
181     {
182         std::lock_guard<std::mutex> tl(traceLock_);
183         auto src = LocateBuffer(buffer);
184         if (src != nullptr) {
185             src->DetachTrackingBuffer(buffer);
186         }
187 
188         dest->AttachTrackingBuffer(buffer);
189     }
190     return;
191 }
192 
RemoveBuffer(std::shared_ptr<TrackingBuffer> & buffer)193 void TrackingStream::RemoveBuffer(std::shared_ptr<TrackingBuffer>& buffer)
194 {
195     std::lock_guard<std::mutex> tl(traceLock_);
196     auto src = LocateBuffer(buffer);
197     if (src != nullptr) {
198         src->DetachTrackingBuffer(buffer);
199     }
200 
201     return;
202 }
203 
DumpTrace(BufferTraceGraph & graph)204 void TrackingStream::DumpTrace(BufferTraceGraph& graph)
205 {
206     graph.clear();
207     std::lock_guard<std::mutex> tl(traceLock_);
208     std::lock_guard<std::mutex> l(lock_);
209     for (auto& n : trackingNodeList_) {
210         if (n == nullptr) {
211             graph.clear();
212             return;
213         }
214         std::list<TrackingBuffer> buffers = {};
215         auto bufferList = n->GetTrackingBuffer();
216         for (const auto& b : bufferList) {
217             if (b == nullptr) {
218                 graph.clear();
219                 return;
220             }
221             buffers.emplace_back(*b);
222         }
223         graph.emplace_back(std::make_pair(n->GetNodeName(), buffers));
224     }
225 
226     return;
227 }
228 
FindTrackingNodePath(const std::string beginNode,const std::string endNode)229 std::list<std::shared_ptr<TrackingNode>> TrackingStream::FindTrackingNodePath(const std::string beginNode,
230                                                                               const std::string endNode)
231 {
232     std::lock_guard<std::mutex> l(lock_);
233     std::list<std::shared_ptr<TrackingNode>> nodePath = {};
234     bool isInPath = false;
235     for (auto& n : trackingNodeList_) {
236         if (n == nullptr) {
237             return {};
238         }
239         if (n->GetNodeName() == beginNode || n->GetNodeName() == endNode) {
240             if (nodePath.empty()) {
241                 isInPath = true;
242             } else {
243                 isInPath = false;
244             }
245             nodePath.emplace_back(n);
246             continue;
247         }
248         if (isInPath) {
249             nodePath.emplace_back(n);
250         }
251     }
252     return nodePath;
253 }
254 
GetInstance()255 BufferLoopTracking& BufferLoopTracking::GetInstance()
256 {
257     static BufferLoopTracking stalker;
258     return stalker;
259 }
260 
~BufferLoopTracking()261 BufferLoopTracking::~BufferLoopTracking()
262 {
263     {
264         std::lock_guard<std::mutex> l(lock_);
265         trackingStreamList_.clear();
266         handler_ = nullptr;
267     }
268 }
269 
FindTrackingStream(const int32_t id)270 std::shared_ptr<TrackingStream> BufferLoopTracking::FindTrackingStream(const int32_t id)
271 {
272     std::lock_guard<std::mutex> l(lock_);
273     auto it = std::find_if(
274         trackingStreamList_.begin(), trackingStreamList_.end(),
275         [&id](const std::shared_ptr<TrackingStream>& stream) { return stream->GetTrackingStreamId() == id; });
276     if (it != trackingStreamList_.end()) {
277         return *it;
278     }
279 
280     return nullptr;
281 }
282 
AddTrackingStreamBegin(const int32_t trackingId,const int64_t poolId)283 void BufferLoopTracking::AddTrackingStreamBegin(const int32_t trackingId, const int64_t poolId)
284 {
285     auto stream = FindTrackingStream(trackingId);
286     if (stream != nullptr) {
287         return;
288     }
289 
290     {
291         std::lock_guard<std::mutex> l(lock_);
292         stream = std::make_shared<TrackingStream>(trackingId);
293         if (stream == nullptr) {
294             CAMERA_LOGE("stream is nullptr");
295             return;
296         }
297         trackingStreamList_.emplace_back(stream);
298         CAMERA_LOGD("add tracking stream %{public}d begin", trackingId);
299     }
300 
301     auto manager = BufferManager::GetInstance();
302     if (manager == nullptr) {
303         CAMERA_LOGE("can't get buffer manager");
304         return;
305     }
306 
307     auto pool = manager->GetBufferPool(poolId);
308     if (pool == nullptr) {
309         CAMERA_LOGE("can't get buffer pool, id = %{public}" PRId64 "", poolId);
310         return;
311     }
312     pool->EnableTracking(trackingId);
313 
314     return;
315 }
316 
AddTrackingStreamEnd(const int32_t trackingId)317 void BufferLoopTracking::AddTrackingStreamEnd(const int32_t trackingId)
318 {
319     auto stream = FindTrackingStream(trackingId);
320     if (stream == nullptr) {
321         return;
322     }
323     stream->NodeAddComplete();
324     CAMERA_LOGD("add tracking stream %{public}d end", trackingId);
325 
326     return;
327 }
328 
DeleteTrackingStream(const int32_t trackingId)329 void BufferLoopTracking::DeleteTrackingStream(const int32_t trackingId)
330 {
331     std::lock_guard<std::mutex> l(lock_);
332     auto it = std::find_if(trackingStreamList_.begin(), trackingStreamList_.end(),
333         [&trackingId](const std::shared_ptr<TrackingStream>& stream) {
334             return stream->GetTrackingStreamId() == trackingId;
335         });
336     if (it == trackingStreamList_.end()) {
337         CAMERA_LOGE("stream %{public}d is not being tracked.", trackingId);
338         return;
339     }
340     trackingStreamList_.erase(it);
341 
342     return;
343 }
344 
AddTrackingNode(const int32_t trackingId,const std::string node)345 void BufferLoopTracking::AddTrackingNode(const int32_t trackingId, const std::string node)
346 {
347     auto stream = FindTrackingStream(trackingId);
348     if (stream == nullptr) {
349         CAMERA_LOGI("can't add node %{public}s to stream %{public}d", node.c_str(), trackingId);
350         return;
351     }
352     auto n = std::make_shared<TrackingNode>(node);
353     if (n == nullptr) {
354         CAMERA_LOGE("n is nullptr");
355         return;
356     }
357     return stream->AttachTrackingNode(n);
358 }
359 
ReceiveMessage()360 std::shared_ptr<BufferTrackingMessage> BufferLoopTracking::ReceiveMessage()
361 {
362     if (messageQueue_.empty()) {
363         std::unique_lock<std::mutex> l(messageLock_);
364         if (messageQueue_.empty()) {
365             cv_.wait(l, [this] { return !(running_.load() && messageQueue_.empty()); });
366         }
367     }
368 
369     if (!running_.load()) {
370         return nullptr;
371     }
372 
373     std::shared_ptr<BufferTrackingMessage> message = nullptr;
374     if (!messageQueue_.empty()) {
375         std::unique_lock<std::mutex> l(messageLock_);
376         if (!messageQueue_.empty()) {
377             message = messageQueue_.front();
378             messageQueue_.pop_front();
379             return message;
380         }
381     }
382 
383     return message;
384 }
385 
SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage> & message)386 void BufferLoopTracking::SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage>& message)
387 {
388     std::unique_lock<std::mutex> l(messageLock_);
389     messageQueue_.emplace_back(message);
390     cv_.notify_one();
391 
392     return;
393 }
394 
HandleMessage()395 void BufferLoopTracking::HandleMessage()
396 {
397     auto message = ReceiveMessage();
398     if (message == nullptr) {
399         return;
400     }
401 
402     auto stream = FindTrackingStream(message->trackingId);
403     if (stream == nullptr) {
404         CAMERA_LOGE("cannot handle stream %{public}d", message->trackingId);
405         return;
406     }
407 
408     if (!stream->IsNodeComplete()) {
409         CAMERA_LOGW("tracking node in stream %{public}d is incomplete", message->trackingId);
410         return;
411     }
412 
413     auto buffer = std::make_shared<TrackingBuffer>(message->frameNumber);
414     if (message->isReturnBack) {
415         stream->RemoveBuffer(buffer);
416         CAMERA_LOGI("buffer %{public}" PRIu64 " return back to pool.", message->frameNumber);
417         return;
418     }
419 
420     auto node = std::make_shared<TrackingNode>(message->nodeName);
421     stream->MoveBuffer(buffer, node);
422 
423     return;
424 }
425 
StartTracking()426 void BufferLoopTracking::StartTracking()
427 {
428     handler_ = std::make_unique<std::thread>([this] {
429         prctl(PR_SET_NAME, "buffertracking");
430         do {
431             HandleMessage();
432         } while (running_.load() == true);
433     });
434     if (handler_ == nullptr) {
435         return;
436     }
437     running_ = true;
438     return;
439 }
440 
StopTracking()441 void BufferLoopTracking::StopTracking()
442 {
443     running_ = false;
444     cv_.notify_one();
445     handler_->join();
446     return;
447 }
448 
IsEmpty(const int32_t id,const std::string node)449 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string node)
450 {
451     auto stream = FindTrackingStream(id);
452     if (stream == nullptr) {
453         CAMERA_LOGI("stream %{public}d doesn't exist", id);
454         return INVALID_TRACKING_ID;
455     }
456     auto n = stream->FindTrackingNode(node);
457     return n->IsEmpty() ? NODE_IS_EMPTY : NODE_IS_NOT_EMPTY;
458 }
459 
IsEmpty(const int32_t id,const std::string beginNode,const std::string endNode)460 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string beginNode, const std::string endNode)
461 {
462     auto stream = FindTrackingStream(id);
463     if (stream == nullptr) {
464         CAMERA_LOGI("stream %{public}d doesn't exist", id);
465         return INVALID_TRACKING_ID;
466     }
467     auto nodePath = stream->FindTrackingNodePath(beginNode, endNode);
468     for (auto& n : nodePath) {
469         if (n == nullptr) {
470             continue;
471         }
472         if (n->IsEmpty() != true) {
473             return NODE_IS_NOT_EMPTY;
474         } else {
475             return NODE_IS_EMPTY;
476         }
477     }
478 
479     return true;
480 }
481 
DumpTrace(const int32_t id,BufferTraceGraph & graph)482 void BufferLoopTracking::DumpTrace(const int32_t id, BufferTraceGraph& graph)
483 {
484     auto stream = FindTrackingStream(id);
485     if (stream == nullptr) {
486         CAMERA_LOGI("stream %{public}d doesn't exist, can't dump trace", id);
487         return;
488     }
489 
490     stream->DumpTrace(graph);
491     return;
492 }
493 } // namespace OHOS::Camera
494