• 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         CAMERA_LOGD("dtor TrackingStream %{public}p", this);
98     }
99 }
100 
GetTrackingStreamId() const101 int32_t TrackingStream::GetTrackingStreamId() const
102 {
103     return trackingId_;
104 }
105 
FindTrackingNode(const std::string node)106 std::shared_ptr<TrackingNode> TrackingStream::FindTrackingNode(const std::string node)
107 {
108     std::lock_guard<std::mutex> l(lock_);
109     auto it = std::find_if(trackingNodeList_.begin(), trackingNodeList_.end(),
110                            [&node](const std::shared_ptr<TrackingNode>& n) { return n->GetNodeName() == node; });
111     if (it != trackingNodeList_.end()) {
112         return *it;
113     }
114 
115     return nullptr;
116 }
117 
AttachTrackingNode(const std::shared_ptr<TrackingNode> & node)118 void TrackingStream::AttachTrackingNode(const std::shared_ptr<TrackingNode>& node)
119 {
120     if (FindTrackingNode(node->GetNodeName()) != nullptr) {
121         return;
122     }
123 
124     {
125         std::lock_guard<std::mutex> l(lock_);
126         trackingNodeList_.emplace_back(node);
127     }
128 
129     return;
130 }
131 
DetachTrackingNode(const std::shared_ptr<TrackingNode> & node)132 void TrackingStream::DetachTrackingNode(const std::shared_ptr<TrackingNode>& node)
133 {
134     auto n = FindTrackingNode(node->GetNodeName());
135     if (n == nullptr) {
136         return;
137     }
138 
139     {
140         std::lock_guard<std::mutex> l(lock_);
141         auto it = std::find(trackingNodeList_.begin(), trackingNodeList_.end(), node);
142         if (it != trackingNodeList_.end()) {
143             trackingNodeList_.erase(it);
144         }
145     }
146 
147     return;
148 }
149 
LocateBuffer(const std::shared_ptr<TrackingBuffer> & buffer)150 std::shared_ptr<TrackingNode> TrackingStream::LocateBuffer(const std::shared_ptr<TrackingBuffer>& buffer)
151 {
152     {
153         std::lock_guard<std::mutex> l(lock_);
154         for (auto& n : trackingNodeList_) {
155             if (n == nullptr) {
156                 CAMERA_LOGE("fatal error, tracking node list is corrupt.");
157                 return nullptr;
158             }
159             if (n->IsEmpty()) {
160                 continue;
161             }
162             if (n->FindTrackingBuffer(buffer) != nullptr) {
163                 return n;
164             }
165         }
166         return nullptr;
167     }
168 }
169 
MoveBuffer(std::shared_ptr<TrackingBuffer> & buffer,std::shared_ptr<TrackingNode> & node)170 void TrackingStream::MoveBuffer(std::shared_ptr<TrackingBuffer>& buffer, std::shared_ptr<TrackingNode>& node)
171 {
172     if (node == nullptr) {
173         CAMERA_LOGE("node is null, cannot track");
174         return;
175     }
176     auto dest = FindTrackingNode(node->GetNodeName());
177     if (dest == nullptr) {
178         CAMERA_LOGE("node %{public}s doesn't being tracked", node->GetNodeName().c_str());
179         return;
180     }
181 
182     {
183         std::lock_guard<std::mutex> tl(traceLock_);
184         auto src = LocateBuffer(buffer);
185         if (src != nullptr) {
186             src->DetachTrackingBuffer(buffer);
187         }
188 
189         dest->AttachTrackingBuffer(buffer);
190     }
191     return;
192 }
193 
RemoveBuffer(std::shared_ptr<TrackingBuffer> & buffer)194 void TrackingStream::RemoveBuffer(std::shared_ptr<TrackingBuffer>& buffer)
195 {
196     std::lock_guard<std::mutex> tl(traceLock_);
197     auto src = LocateBuffer(buffer);
198     if (src != nullptr) {
199         src->DetachTrackingBuffer(buffer);
200     }
201 
202     return;
203 }
204 
DumpTrace(BufferTraceGraph & graph)205 void TrackingStream::DumpTrace(BufferTraceGraph& graph)
206 {
207     graph.clear();
208     std::lock_guard<std::mutex> tl(traceLock_);
209     std::lock_guard<std::mutex> l(lock_);
210     for (auto& n : trackingNodeList_) {
211         if (n == nullptr) {
212             graph.clear();
213             return;
214         }
215         std::list<TrackingBuffer> buffers = {};
216         auto bufferList = n->GetTrackingBuffer();
217         for (const auto& b : bufferList) {
218             if (b == nullptr) {
219                 graph.clear();
220                 return;
221             }
222             buffers.emplace_back(*b);
223         }
224         graph.emplace_back(std::make_pair(n->GetNodeName(), buffers));
225     }
226 
227     return;
228 }
229 
FindTrackingNodePath(const std::string beginNode,const std::string endNode)230 std::list<std::shared_ptr<TrackingNode>> TrackingStream::FindTrackingNodePath(const std::string beginNode,
231                                                                               const std::string endNode)
232 {
233     std::lock_guard<std::mutex> l(lock_);
234     std::list<std::shared_ptr<TrackingNode>> nodePath = {};
235     bool isInPath = false;
236     for (auto& n : trackingNodeList_) {
237         if (n == nullptr) {
238             return {};
239         }
240         if (n->GetNodeName() == beginNode || n->GetNodeName() == endNode) {
241             if (nodePath.empty()) {
242                 isInPath = true;
243             } else {
244                 isInPath = false;
245             }
246             nodePath.emplace_back(n);
247             continue;
248         }
249         if (isInPath) {
250             nodePath.emplace_back(n);
251         }
252     }
253     return nodePath;
254 }
255 
GetInstance()256 BufferLoopTracking& BufferLoopTracking::GetInstance()
257 {
258     static BufferLoopTracking stalker;
259     return stalker;
260 }
261 
~BufferLoopTracking()262 BufferLoopTracking::~BufferLoopTracking()
263 {
264     {
265         std::lock_guard<std::mutex> l(lock_);
266         trackingStreamList_.clear();
267         handler_ = nullptr;
268     }
269 }
270 
FindTrackingStream(const int32_t id)271 std::shared_ptr<TrackingStream> BufferLoopTracking::FindTrackingStream(const int32_t id)
272 {
273     std::lock_guard<std::mutex> l(lock_);
274     auto it = std::find_if(
275         trackingStreamList_.begin(), trackingStreamList_.end(),
276         [&id](const std::shared_ptr<TrackingStream>& stream) { return stream->GetTrackingStreamId() == id; });
277     if (it != trackingStreamList_.end()) {
278         return *it;
279     }
280 
281     return nullptr;
282 }
283 
AddTrackingStreamBegin(const int32_t trackingId,const int64_t poolId)284 void BufferLoopTracking::AddTrackingStreamBegin(const int32_t trackingId, const int64_t poolId)
285 {
286     auto stream = FindTrackingStream(trackingId);
287     if (stream != nullptr) {
288         return;
289     }
290 
291     {
292         std::lock_guard<std::mutex> l(lock_);
293         stream = std::make_shared<TrackingStream>(trackingId);
294         trackingStreamList_.emplace_back(stream);
295         CAMERA_LOGD("add tracking stream %{public}d begin", trackingId);
296     }
297 
298     auto manager = BufferManager::GetInstance();
299     if (manager == nullptr) {
300         CAMERA_LOGE("can't get buffer manager");
301         return;
302     }
303 
304     auto pool = manager->GetBufferPool(poolId);
305     if (pool == nullptr) {
306         CAMERA_LOGE("can't get buffer pool, id = %{public}" PRId64 "", poolId);
307         return;
308     }
309     pool->EnableTracking(trackingId);
310 
311     return;
312 }
313 
AddTrackingStreamEnd(const int32_t trackingId)314 void BufferLoopTracking::AddTrackingStreamEnd(const int32_t trackingId)
315 {
316     auto stream = FindTrackingStream(trackingId);
317     if (stream == nullptr) {
318         return;
319     }
320     stream->NodeAddComplete();
321     CAMERA_LOGD("add tracking stream %{public}d end", trackingId);
322 
323     return;
324 }
325 
DeleteTrackingStream(const int32_t trackingId)326 void BufferLoopTracking::DeleteTrackingStream(const int32_t trackingId)
327 {
328     std::lock_guard<std::mutex> l(lock_);
329     auto it = std::find_if(trackingStreamList_.begin(), trackingStreamList_.end(),
330         [&trackingId](const std::shared_ptr<TrackingStream>& stream) {
331             return stream->GetTrackingStreamId() == trackingId;
332         });
333     if (it == trackingStreamList_.end()) {
334         CAMERA_LOGE("stream %{public}d is not being tracked.", trackingId);
335         return;
336     }
337     trackingStreamList_.erase(it);
338 
339     return;
340 }
341 
AddTrackingNode(const int32_t trackingId,const std::string node)342 void BufferLoopTracking::AddTrackingNode(const int32_t trackingId, const std::string node)
343 {
344     auto stream = FindTrackingStream(trackingId);
345     if (stream == nullptr) {
346         CAMERA_LOGI("can't add node %{public}s to stream %{public}d", node.c_str(), trackingId);
347         return;
348     }
349     auto n = std::make_shared<TrackingNode>(node);
350     return stream->AttachTrackingNode(n);
351 }
352 
ReceiveMessage()353 std::shared_ptr<BufferTrackingMessage> BufferLoopTracking::ReceiveMessage()
354 {
355     if (messageQueue_.empty()) {
356         std::unique_lock<std::mutex> l(messageLock_);
357         if (messageQueue_.empty()) {
358             cv_.wait(l, [this] { return !(running_.load() && messageQueue_.empty()); });
359         }
360     }
361 
362     if (!running_.load()) {
363         return nullptr;
364     }
365 
366     std::shared_ptr<BufferTrackingMessage> message = nullptr;
367     if (!messageQueue_.empty()) {
368         std::unique_lock<std::mutex> l(messageLock_);
369         if (!messageQueue_.empty()) {
370             message = messageQueue_.front();
371             messageQueue_.pop_front();
372             return message;
373         }
374     }
375 
376     return message;
377 }
378 
SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage> & message)379 void BufferLoopTracking::SendBufferMovementMessage(const std::shared_ptr<BufferTrackingMessage>& message)
380 {
381     std::unique_lock<std::mutex> l(messageLock_);
382     messageQueue_.emplace_back(message);
383     cv_.notify_one();
384 
385     return;
386 }
387 
HandleMessage()388 void BufferLoopTracking::HandleMessage()
389 {
390     auto message = ReceiveMessage();
391     if (message == nullptr) {
392         return;
393     }
394 
395     auto stream = FindTrackingStream(message->trackingId);
396     if (stream == nullptr) {
397         CAMERA_LOGE("cannot handle stream %{public}d", message->trackingId);
398         return;
399     }
400 
401     if (!stream->IsNodeComplete()) {
402         CAMERA_LOGW("tracking node in stream %{public}d is incomplete", message->trackingId);
403         return;
404     }
405 
406     auto buffer = std::make_shared<TrackingBuffer>(message->frameNumber);
407     if (message->isReturnBack) {
408         stream->RemoveBuffer(buffer);
409         CAMERA_LOGI("buffer %{public}" PRIu64 " return back to pool.", message->frameNumber);
410         return;
411     }
412 
413     auto node = std::make_shared<TrackingNode>(message->nodeName);
414     stream->MoveBuffer(buffer, node);
415 
416     return;
417 }
418 
StartTracking()419 void BufferLoopTracking::StartTracking()
420 {
421     handler_ = std::make_unique<std::thread>([this] {
422         prctl(PR_SET_NAME, "buffertracking");
423         do {
424             HandleMessage();
425         } while (running_.load() == true);
426     });
427     if (handler_ == nullptr) {
428         return;
429     }
430     running_ = true;
431     return;
432 }
433 
StopTracking()434 void BufferLoopTracking::StopTracking()
435 {
436     running_ = false;
437     cv_.notify_one();
438     handler_->join();
439     return;
440 }
441 
IsEmpty(const int32_t id,const std::string node)442 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string node)
443 {
444     auto stream = FindTrackingStream(id);
445     if (stream == nullptr) {
446         CAMERA_LOGI("stream %{public}d doesn't exist", id);
447         return INVALID_TRACKING_ID;
448     }
449     auto n = stream->FindTrackingNode(node);
450     return n->IsEmpty() ? NODE_IS_EMPTY : NODE_IS_NOT_EMPTY;
451 }
452 
IsEmpty(const int32_t id,const std::string beginNode,const std::string endNode)453 int32_t BufferLoopTracking::IsEmpty(const int32_t id, const std::string beginNode, const std::string endNode)
454 {
455     auto stream = FindTrackingStream(id);
456     if (stream == nullptr) {
457         CAMERA_LOGI("stream %{public}d doesn't exist", id);
458         return INVALID_TRACKING_ID;
459     }
460     auto nodePath = stream->FindTrackingNodePath(beginNode, endNode);
461     for (auto& n : nodePath) {
462         if (n == nullptr) {
463             continue;
464         }
465         if (n->IsEmpty() != true) {
466             return NODE_IS_NOT_EMPTY;
467         } else {
468             return NODE_IS_EMPTY;
469         }
470     }
471 
472     return true;
473 }
474 
DumpTrace(const int32_t id,BufferTraceGraph & graph)475 void BufferLoopTracking::DumpTrace(const int32_t id, BufferTraceGraph& graph)
476 {
477     auto stream = FindTrackingStream(id);
478     if (stream == nullptr) {
479         CAMERA_LOGI("stream %{public}d doesn't exist, can't dump trace", id);
480         return;
481     }
482 
483     stream->DumpTrace(graph);
484     return;
485 }
486 } // namespace OHOS::Camera
487