1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
4*89c4ff92SAndroid Build Coastguard Worker //
5*89c4ff92SAndroid Build Coastguard Worker
6*89c4ff92SAndroid Build Coastguard Worker #include "SendThread.hpp"
7*89c4ff92SAndroid Build Coastguard Worker #include "ProfilingUtils.hpp"
8*89c4ff92SAndroid Build Coastguard Worker
9*89c4ff92SAndroid Build Coastguard Worker #include <common/include/NumericCast.hpp>
10*89c4ff92SAndroid Build Coastguard Worker #include <common/include/ProfilingException.hpp>
11*89c4ff92SAndroid Build Coastguard Worker
12*89c4ff92SAndroid Build Coastguard Worker #if defined(ARMNN_DISABLE_THREADS)
13*89c4ff92SAndroid Build Coastguard Worker #include <common/include/IgnoreUnused.hpp>
14*89c4ff92SAndroid Build Coastguard Worker #endif
15*89c4ff92SAndroid Build Coastguard Worker
16*89c4ff92SAndroid Build Coastguard Worker #include <cstring>
17*89c4ff92SAndroid Build Coastguard Worker
18*89c4ff92SAndroid Build Coastguard Worker namespace arm
19*89c4ff92SAndroid Build Coastguard Worker {
20*89c4ff92SAndroid Build Coastguard Worker
21*89c4ff92SAndroid Build Coastguard Worker namespace pipe
22*89c4ff92SAndroid Build Coastguard Worker {
23*89c4ff92SAndroid Build Coastguard Worker
SendThread(ProfilingStateMachine & profilingStateMachine,IBufferManager & buffer,ISendCounterPacket & sendCounterPacket,int timeout)24*89c4ff92SAndroid Build Coastguard Worker SendThread::SendThread(ProfilingStateMachine& profilingStateMachine,
25*89c4ff92SAndroid Build Coastguard Worker IBufferManager& buffer,
26*89c4ff92SAndroid Build Coastguard Worker ISendCounterPacket& sendCounterPacket,
27*89c4ff92SAndroid Build Coastguard Worker int timeout)
28*89c4ff92SAndroid Build Coastguard Worker : m_StateMachine(profilingStateMachine)
29*89c4ff92SAndroid Build Coastguard Worker , m_BufferManager(buffer)
30*89c4ff92SAndroid Build Coastguard Worker , m_SendCounterPacket(sendCounterPacket)
31*89c4ff92SAndroid Build Coastguard Worker , m_Timeout(timeout)
32*89c4ff92SAndroid Build Coastguard Worker , m_IsRunning(false)
33*89c4ff92SAndroid Build Coastguard Worker , m_KeepRunning(false)
34*89c4ff92SAndroid Build Coastguard Worker , m_SendThreadException(nullptr)
35*89c4ff92SAndroid Build Coastguard Worker {
36*89c4ff92SAndroid Build Coastguard Worker m_BufferManager.SetConsumer(this);
37*89c4ff92SAndroid Build Coastguard Worker }
38*89c4ff92SAndroid Build Coastguard Worker
SetReadyToRead()39*89c4ff92SAndroid Build Coastguard Worker void SendThread::SetReadyToRead()
40*89c4ff92SAndroid Build Coastguard Worker {
41*89c4ff92SAndroid Build Coastguard Worker // We need to wait for the send thread to release its mutex
42*89c4ff92SAndroid Build Coastguard Worker {
43*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
44*89c4ff92SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lck(m_WaitMutex);
45*89c4ff92SAndroid Build Coastguard Worker #endif
46*89c4ff92SAndroid Build Coastguard Worker m_ReadyToRead = true;
47*89c4ff92SAndroid Build Coastguard Worker }
48*89c4ff92SAndroid Build Coastguard Worker // Signal the send thread that there's something to read in the buffer
49*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
50*89c4ff92SAndroid Build Coastguard Worker m_WaitCondition.notify_one();
51*89c4ff92SAndroid Build Coastguard Worker #endif
52*89c4ff92SAndroid Build Coastguard Worker }
53*89c4ff92SAndroid Build Coastguard Worker
Start(IProfilingConnection & profilingConnection)54*89c4ff92SAndroid Build Coastguard Worker void SendThread::Start(IProfilingConnection& profilingConnection)
55*89c4ff92SAndroid Build Coastguard Worker {
56*89c4ff92SAndroid Build Coastguard Worker // Check if the send thread is already running
57*89c4ff92SAndroid Build Coastguard Worker if (m_IsRunning.load())
58*89c4ff92SAndroid Build Coastguard Worker {
59*89c4ff92SAndroid Build Coastguard Worker // The send thread is already running
60*89c4ff92SAndroid Build Coastguard Worker return;
61*89c4ff92SAndroid Build Coastguard Worker }
62*89c4ff92SAndroid Build Coastguard Worker
63*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
64*89c4ff92SAndroid Build Coastguard Worker if (m_SendThread.joinable())
65*89c4ff92SAndroid Build Coastguard Worker {
66*89c4ff92SAndroid Build Coastguard Worker m_SendThread.join();
67*89c4ff92SAndroid Build Coastguard Worker }
68*89c4ff92SAndroid Build Coastguard Worker #endif
69*89c4ff92SAndroid Build Coastguard Worker
70*89c4ff92SAndroid Build Coastguard Worker // Mark the send thread as running
71*89c4ff92SAndroid Build Coastguard Worker m_IsRunning.store(true);
72*89c4ff92SAndroid Build Coastguard Worker
73*89c4ff92SAndroid Build Coastguard Worker // Keep the send procedure going until the send thread is signalled to stop
74*89c4ff92SAndroid Build Coastguard Worker m_KeepRunning.store(true);
75*89c4ff92SAndroid Build Coastguard Worker
76*89c4ff92SAndroid Build Coastguard Worker // Make sure the send thread will not flush the buffer until signaled to do so
77*89c4ff92SAndroid Build Coastguard Worker // no need for a mutex as the send thread can not be running at this point
78*89c4ff92SAndroid Build Coastguard Worker m_ReadyToRead = false;
79*89c4ff92SAndroid Build Coastguard Worker
80*89c4ff92SAndroid Build Coastguard Worker m_PacketSent = false;
81*89c4ff92SAndroid Build Coastguard Worker
82*89c4ff92SAndroid Build Coastguard Worker // Start the send thread
83*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
84*89c4ff92SAndroid Build Coastguard Worker m_SendThread = std::thread(&SendThread::Send, this, std::ref(profilingConnection));
85*89c4ff92SAndroid Build Coastguard Worker #else
86*89c4ff92SAndroid Build Coastguard Worker IgnoreUnused(profilingConnection);
87*89c4ff92SAndroid Build Coastguard Worker #endif
88*89c4ff92SAndroid Build Coastguard Worker }
89*89c4ff92SAndroid Build Coastguard Worker
Stop(bool rethrowSendThreadExceptions)90*89c4ff92SAndroid Build Coastguard Worker void SendThread::Stop(bool rethrowSendThreadExceptions)
91*89c4ff92SAndroid Build Coastguard Worker {
92*89c4ff92SAndroid Build Coastguard Worker // Signal the send thread to stop
93*89c4ff92SAndroid Build Coastguard Worker m_KeepRunning.store(false);
94*89c4ff92SAndroid Build Coastguard Worker
95*89c4ff92SAndroid Build Coastguard Worker // Check that the send thread is running
96*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
97*89c4ff92SAndroid Build Coastguard Worker if (m_SendThread.joinable())
98*89c4ff92SAndroid Build Coastguard Worker {
99*89c4ff92SAndroid Build Coastguard Worker // Kick the send thread out of the wait condition
100*89c4ff92SAndroid Build Coastguard Worker SetReadyToRead();
101*89c4ff92SAndroid Build Coastguard Worker // Wait for the send thread to complete operations
102*89c4ff92SAndroid Build Coastguard Worker m_SendThread.join();
103*89c4ff92SAndroid Build Coastguard Worker }
104*89c4ff92SAndroid Build Coastguard Worker #endif
105*89c4ff92SAndroid Build Coastguard Worker
106*89c4ff92SAndroid Build Coastguard Worker // Check if the send thread exception has to be rethrown
107*89c4ff92SAndroid Build Coastguard Worker if (!rethrowSendThreadExceptions)
108*89c4ff92SAndroid Build Coastguard Worker {
109*89c4ff92SAndroid Build Coastguard Worker // No need to rethrow the send thread exception, return immediately
110*89c4ff92SAndroid Build Coastguard Worker return;
111*89c4ff92SAndroid Build Coastguard Worker }
112*89c4ff92SAndroid Build Coastguard Worker
113*89c4ff92SAndroid Build Coastguard Worker // Check if there's an exception to rethrow
114*89c4ff92SAndroid Build Coastguard Worker if (m_SendThreadException)
115*89c4ff92SAndroid Build Coastguard Worker {
116*89c4ff92SAndroid Build Coastguard Worker // Rethrow the send thread exception
117*89c4ff92SAndroid Build Coastguard Worker std::rethrow_exception(m_SendThreadException);
118*89c4ff92SAndroid Build Coastguard Worker
119*89c4ff92SAndroid Build Coastguard Worker // Nullify the exception as it has been rethrown
120*89c4ff92SAndroid Build Coastguard Worker m_SendThreadException = nullptr;
121*89c4ff92SAndroid Build Coastguard Worker }
122*89c4ff92SAndroid Build Coastguard Worker }
123*89c4ff92SAndroid Build Coastguard Worker
Send(IProfilingConnection & profilingConnection)124*89c4ff92SAndroid Build Coastguard Worker void SendThread::Send(IProfilingConnection& profilingConnection)
125*89c4ff92SAndroid Build Coastguard Worker {
126*89c4ff92SAndroid Build Coastguard Worker // Run once and keep the sending procedure looping until the thread is signalled to stop
127*89c4ff92SAndroid Build Coastguard Worker do
128*89c4ff92SAndroid Build Coastguard Worker {
129*89c4ff92SAndroid Build Coastguard Worker // Check the current state of the profiling service
130*89c4ff92SAndroid Build Coastguard Worker ProfilingState currentState = m_StateMachine.GetCurrentState();
131*89c4ff92SAndroid Build Coastguard Worker switch (currentState)
132*89c4ff92SAndroid Build Coastguard Worker {
133*89c4ff92SAndroid Build Coastguard Worker case ProfilingState::Uninitialised:
134*89c4ff92SAndroid Build Coastguard Worker case ProfilingState::NotConnected:
135*89c4ff92SAndroid Build Coastguard Worker
136*89c4ff92SAndroid Build Coastguard Worker // The send thread cannot be running when the profiling service is uninitialized or not connected,
137*89c4ff92SAndroid Build Coastguard Worker // stop the thread immediately
138*89c4ff92SAndroid Build Coastguard Worker m_KeepRunning.store(false);
139*89c4ff92SAndroid Build Coastguard Worker m_IsRunning.store(false);
140*89c4ff92SAndroid Build Coastguard Worker
141*89c4ff92SAndroid Build Coastguard Worker // An exception should be thrown here, save it to be rethrown later from the main thread so that
142*89c4ff92SAndroid Build Coastguard Worker // it can be caught by the consumer
143*89c4ff92SAndroid Build Coastguard Worker m_SendThreadException =
144*89c4ff92SAndroid Build Coastguard Worker std::make_exception_ptr(arm::pipe::ProfilingException(
145*89c4ff92SAndroid Build Coastguard Worker "The send thread should not be running with the profiling service not yet initialized or connected"));
146*89c4ff92SAndroid Build Coastguard Worker
147*89c4ff92SAndroid Build Coastguard Worker return;
148*89c4ff92SAndroid Build Coastguard Worker case ProfilingState::WaitingForAck:
149*89c4ff92SAndroid Build Coastguard Worker
150*89c4ff92SAndroid Build Coastguard Worker // Send out a StreamMetadata packet and wait for the profiling connection to be acknowledged.
151*89c4ff92SAndroid Build Coastguard Worker // When a ConnectionAcknowledged packet is received, the profiling service state will be automatically
152*89c4ff92SAndroid Build Coastguard Worker // updated by the command handler
153*89c4ff92SAndroid Build Coastguard Worker
154*89c4ff92SAndroid Build Coastguard Worker // Prepare a StreamMetadata packet and write it to the Counter Stream buffer
155*89c4ff92SAndroid Build Coastguard Worker m_SendCounterPacket.SendStreamMetaDataPacket();
156*89c4ff92SAndroid Build Coastguard Worker
157*89c4ff92SAndroid Build Coastguard Worker // Flush the buffer manually to send the packet
158*89c4ff92SAndroid Build Coastguard Worker FlushBuffer(profilingConnection);
159*89c4ff92SAndroid Build Coastguard Worker
160*89c4ff92SAndroid Build Coastguard Worker // Wait for a connection ack from the remote server. We should expect a response within timeout value.
161*89c4ff92SAndroid Build Coastguard Worker // If not, drop back to the start of the loop and detect somebody closing the thread. Then send the
162*89c4ff92SAndroid Build Coastguard Worker // StreamMetadata again.
163*89c4ff92SAndroid Build Coastguard Worker
164*89c4ff92SAndroid Build Coastguard Worker // Wait condition lock scope - Begin
165*89c4ff92SAndroid Build Coastguard Worker {
166*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
167*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(m_WaitMutex);
168*89c4ff92SAndroid Build Coastguard Worker
169*89c4ff92SAndroid Build Coastguard Worker bool timeout = m_WaitCondition.wait_for(lock,
170*89c4ff92SAndroid Build Coastguard Worker std::chrono::milliseconds(std::max(m_Timeout, 1000)),
171*89c4ff92SAndroid Build Coastguard Worker [&]{ return m_ReadyToRead; });
172*89c4ff92SAndroid Build Coastguard Worker // If we get notified we need to flush the buffer again
173*89c4ff92SAndroid Build Coastguard Worker if (timeout)
174*89c4ff92SAndroid Build Coastguard Worker {
175*89c4ff92SAndroid Build Coastguard Worker // Otherwise if we just timed out don't flush the buffer
176*89c4ff92SAndroid Build Coastguard Worker continue;
177*89c4ff92SAndroid Build Coastguard Worker }
178*89c4ff92SAndroid Build Coastguard Worker #endif
179*89c4ff92SAndroid Build Coastguard Worker //reset condition variable predicate for next use
180*89c4ff92SAndroid Build Coastguard Worker m_ReadyToRead = false;
181*89c4ff92SAndroid Build Coastguard Worker }
182*89c4ff92SAndroid Build Coastguard Worker // Wait condition lock scope - End
183*89c4ff92SAndroid Build Coastguard Worker break;
184*89c4ff92SAndroid Build Coastguard Worker case ProfilingState::Active:
185*89c4ff92SAndroid Build Coastguard Worker default:
186*89c4ff92SAndroid Build Coastguard Worker // Wait condition lock scope - Begin
187*89c4ff92SAndroid Build Coastguard Worker {
188*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
189*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(m_WaitMutex);
190*89c4ff92SAndroid Build Coastguard Worker #endif
191*89c4ff92SAndroid Build Coastguard Worker // Normal working state for the send thread
192*89c4ff92SAndroid Build Coastguard Worker // Check if the send thread is required to enforce a timeout wait policy
193*89c4ff92SAndroid Build Coastguard Worker if (m_Timeout < 0)
194*89c4ff92SAndroid Build Coastguard Worker {
195*89c4ff92SAndroid Build Coastguard Worker // Wait indefinitely until notified that something to read has become available in the buffer
196*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
197*89c4ff92SAndroid Build Coastguard Worker m_WaitCondition.wait(lock, [&] { return m_ReadyToRead; });
198*89c4ff92SAndroid Build Coastguard Worker #endif
199*89c4ff92SAndroid Build Coastguard Worker }
200*89c4ff92SAndroid Build Coastguard Worker else
201*89c4ff92SAndroid Build Coastguard Worker {
202*89c4ff92SAndroid Build Coastguard Worker // Wait until the thread is notified of something to read from the buffer,
203*89c4ff92SAndroid Build Coastguard Worker // or check anyway after the specified number of milliseconds
204*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
205*89c4ff92SAndroid Build Coastguard Worker m_WaitCondition.wait_for(lock, std::chrono::milliseconds(m_Timeout), [&] { return m_ReadyToRead; });
206*89c4ff92SAndroid Build Coastguard Worker #endif
207*89c4ff92SAndroid Build Coastguard Worker }
208*89c4ff92SAndroid Build Coastguard Worker
209*89c4ff92SAndroid Build Coastguard Worker //reset condition variable predicate for next use
210*89c4ff92SAndroid Build Coastguard Worker m_ReadyToRead = false;
211*89c4ff92SAndroid Build Coastguard Worker }
212*89c4ff92SAndroid Build Coastguard Worker // Wait condition lock scope - End
213*89c4ff92SAndroid Build Coastguard Worker break;
214*89c4ff92SAndroid Build Coastguard Worker }
215*89c4ff92SAndroid Build Coastguard Worker
216*89c4ff92SAndroid Build Coastguard Worker // Send all the available packets in the buffer
217*89c4ff92SAndroid Build Coastguard Worker FlushBuffer(profilingConnection);
218*89c4ff92SAndroid Build Coastguard Worker } while (m_KeepRunning.load());
219*89c4ff92SAndroid Build Coastguard Worker
220*89c4ff92SAndroid Build Coastguard Worker // Ensure that all readable data got written to the profiling connection before the thread is stopped
221*89c4ff92SAndroid Build Coastguard Worker // (do not notify any watcher in this case, as this is just to wrap up things before shutting down the send thread)
222*89c4ff92SAndroid Build Coastguard Worker FlushBuffer(profilingConnection, false);
223*89c4ff92SAndroid Build Coastguard Worker
224*89c4ff92SAndroid Build Coastguard Worker // Mark the send thread as not running
225*89c4ff92SAndroid Build Coastguard Worker m_IsRunning.store(false);
226*89c4ff92SAndroid Build Coastguard Worker }
227*89c4ff92SAndroid Build Coastguard Worker
FlushBuffer(IProfilingConnection & profilingConnection,bool notifyWatchers)228*89c4ff92SAndroid Build Coastguard Worker void SendThread::FlushBuffer(IProfilingConnection& profilingConnection, bool notifyWatchers)
229*89c4ff92SAndroid Build Coastguard Worker {
230*89c4ff92SAndroid Build Coastguard Worker // Get the first available readable buffer
231*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr packetBuffer = m_BufferManager.GetReadableBuffer();
232*89c4ff92SAndroid Build Coastguard Worker
233*89c4ff92SAndroid Build Coastguard Worker // Initialize the flag that indicates whether at least a packet has been sent
234*89c4ff92SAndroid Build Coastguard Worker bool packetsSent = false;
235*89c4ff92SAndroid Build Coastguard Worker
236*89c4ff92SAndroid Build Coastguard Worker while (packetBuffer != nullptr)
237*89c4ff92SAndroid Build Coastguard Worker {
238*89c4ff92SAndroid Build Coastguard Worker // Get the data to send from the buffer
239*89c4ff92SAndroid Build Coastguard Worker const unsigned char* readBuffer = packetBuffer->GetReadableData();
240*89c4ff92SAndroid Build Coastguard Worker unsigned int readBufferSize = packetBuffer->GetSize();
241*89c4ff92SAndroid Build Coastguard Worker
242*89c4ff92SAndroid Build Coastguard Worker if (readBuffer == nullptr || readBufferSize == 0)
243*89c4ff92SAndroid Build Coastguard Worker {
244*89c4ff92SAndroid Build Coastguard Worker // Nothing to send, get the next available readable buffer and continue
245*89c4ff92SAndroid Build Coastguard Worker m_BufferManager.MarkRead(packetBuffer);
246*89c4ff92SAndroid Build Coastguard Worker packetBuffer = m_BufferManager.GetReadableBuffer();
247*89c4ff92SAndroid Build Coastguard Worker
248*89c4ff92SAndroid Build Coastguard Worker continue;
249*89c4ff92SAndroid Build Coastguard Worker }
250*89c4ff92SAndroid Build Coastguard Worker
251*89c4ff92SAndroid Build Coastguard Worker // Check that the profiling connection is open, silently drop the data and continue if it's closed
252*89c4ff92SAndroid Build Coastguard Worker if (profilingConnection.IsOpen())
253*89c4ff92SAndroid Build Coastguard Worker {
254*89c4ff92SAndroid Build Coastguard Worker // Write a packet to the profiling connection. Silently ignore any write error and continue
255*89c4ff92SAndroid Build Coastguard Worker profilingConnection.WritePacket(readBuffer, arm::pipe::numeric_cast<uint32_t>(readBufferSize));
256*89c4ff92SAndroid Build Coastguard Worker
257*89c4ff92SAndroid Build Coastguard Worker // Set the flag that indicates whether at least a packet has been sent
258*89c4ff92SAndroid Build Coastguard Worker packetsSent = true;
259*89c4ff92SAndroid Build Coastguard Worker }
260*89c4ff92SAndroid Build Coastguard Worker
261*89c4ff92SAndroid Build Coastguard Worker // Mark the packet buffer as read
262*89c4ff92SAndroid Build Coastguard Worker m_BufferManager.MarkRead(packetBuffer);
263*89c4ff92SAndroid Build Coastguard Worker
264*89c4ff92SAndroid Build Coastguard Worker // Get the next available readable buffer
265*89c4ff92SAndroid Build Coastguard Worker packetBuffer = m_BufferManager.GetReadableBuffer();
266*89c4ff92SAndroid Build Coastguard Worker }
267*89c4ff92SAndroid Build Coastguard Worker // Check whether at least a packet has been sent
268*89c4ff92SAndroid Build Coastguard Worker if (packetsSent && notifyWatchers)
269*89c4ff92SAndroid Build Coastguard Worker {
270*89c4ff92SAndroid Build Coastguard Worker // Wait for the parent thread to release its mutex if necessary
271*89c4ff92SAndroid Build Coastguard Worker {
272*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
273*89c4ff92SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lck(m_PacketSentWaitMutex);
274*89c4ff92SAndroid Build Coastguard Worker #endif
275*89c4ff92SAndroid Build Coastguard Worker m_PacketSent = true;
276*89c4ff92SAndroid Build Coastguard Worker }
277*89c4ff92SAndroid Build Coastguard Worker // Notify to any watcher that something has been sent
278*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
279*89c4ff92SAndroid Build Coastguard Worker m_PacketSentWaitCondition.notify_one();
280*89c4ff92SAndroid Build Coastguard Worker #endif
281*89c4ff92SAndroid Build Coastguard Worker }
282*89c4ff92SAndroid Build Coastguard Worker }
283*89c4ff92SAndroid Build Coastguard Worker
WaitForPacketSent(uint32_t timeout=1000)284*89c4ff92SAndroid Build Coastguard Worker bool SendThread::WaitForPacketSent(uint32_t timeout = 1000)
285*89c4ff92SAndroid Build Coastguard Worker {
286*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
287*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(m_PacketSentWaitMutex);
288*89c4ff92SAndroid Build Coastguard Worker // Blocks until notified that at least a packet has been sent or until timeout expires.
289*89c4ff92SAndroid Build Coastguard Worker bool timedOut = m_PacketSentWaitCondition.wait_for(lock,
290*89c4ff92SAndroid Build Coastguard Worker std::chrono::milliseconds(timeout),
291*89c4ff92SAndroid Build Coastguard Worker [&] { return m_PacketSent; });
292*89c4ff92SAndroid Build Coastguard Worker m_PacketSent = false;
293*89c4ff92SAndroid Build Coastguard Worker
294*89c4ff92SAndroid Build Coastguard Worker return timedOut;
295*89c4ff92SAndroid Build Coastguard Worker #else
296*89c4ff92SAndroid Build Coastguard Worker IgnoreUnused(timeout);
297*89c4ff92SAndroid Build Coastguard Worker return false;
298*89c4ff92SAndroid Build Coastguard Worker #endif
299*89c4ff92SAndroid Build Coastguard Worker }
300*89c4ff92SAndroid Build Coastguard Worker
301*89c4ff92SAndroid Build Coastguard Worker } // namespace pipe
302*89c4ff92SAndroid Build Coastguard Worker
303*89c4ff92SAndroid Build Coastguard Worker } // namespace arm
304