Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * Contains non-inline method definitions for the
21 : * GenericPlatformManagerImpl_POSIX<> template.
22 : */
23 :
24 : #ifndef GENERIC_PLATFORM_MANAGER_IMPL_POSIX_CPP
25 : #define GENERIC_PLATFORM_MANAGER_IMPL_POSIX_CPP
26 :
27 : #include <platform/PlatformManager.h>
28 : #include <platform/internal/CHIPDeviceLayerInternal.h>
29 : #include <platform/internal/GenericPlatformManagerImpl_POSIX.h>
30 :
31 : // Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
32 : // from which the GenericPlatformManagerImpl_POSIX<> template inherits.
33 : #include <platform/internal/GenericPlatformManagerImpl.ipp>
34 :
35 : #include <system/SystemError.h>
36 : #include <system/SystemLayer.h>
37 :
38 : #include <assert.h>
39 : #include <errno.h>
40 : #include <fcntl.h>
41 : #include <poll.h>
42 : #include <sched.h>
43 : #include <unistd.h>
44 :
45 : namespace chip {
46 : namespace DeviceLayer {
47 : namespace Internal {
48 :
49 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
50 : namespace {
51 585 : System::LayerSocketsLoop & SystemLayerSocketsLoop()
52 : {
53 585 : return static_cast<System::LayerSocketsLoop &>(DeviceLayer::SystemLayer());
54 : }
55 : } // anonymous namespace
56 : #endif
57 :
58 : template <class ImplClass>
59 48 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack()
60 : {
61 : // Call up to the base class _InitChipStack() to perform the bulk of the initialization.
62 48 : ReturnErrorOnFailure(GenericPlatformManagerImpl<ImplClass>::_InitChipStack());
63 :
64 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
65 :
66 48 : mShouldRunEventLoop.store(true, std::memory_order_relaxed);
67 :
68 48 : int ret = pthread_cond_init(&mEventQueueStoppedCond, nullptr);
69 48 : VerifyOrReturnError(ret == 0, CHIP_ERROR_POSIX(ret));
70 :
71 48 : ret = pthread_mutex_init(&mStateLock, nullptr);
72 48 : VerifyOrReturnError(ret == 0, CHIP_ERROR_POSIX(ret));
73 : #endif
74 :
75 48 : return CHIP_NO_ERROR;
76 : }
77 :
78 : template <class ImplClass>
79 162 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_LockChipStack()
80 : {
81 162 : int err = pthread_mutex_lock(&mChipStackLock);
82 162 : assert(err == 0);
83 :
84 : #if CHIP_STACK_LOCK_TRACKING_ENABLED
85 162 : mChipStackIsLocked = true;
86 162 : mChipStackLockOwnerThread = pthread_self();
87 : #endif
88 162 : }
89 :
90 : template <class ImplClass>
91 1 : bool GenericPlatformManagerImpl_POSIX<ImplClass>::_TryLockChipStack()
92 : {
93 1 : bool locked = (pthread_mutex_trylock(&mChipStackLock) == 0);
94 : #if CHIP_STACK_LOCK_TRACKING_ENABLED
95 1 : if (locked)
96 : {
97 1 : mChipStackIsLocked = true;
98 1 : mChipStackLockOwnerThread = pthread_self();
99 : }
100 : #endif
101 1 : return locked;
102 : }
103 :
104 : template <class ImplClass>
105 163 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_UnlockChipStack()
106 : {
107 : #if CHIP_STACK_LOCK_TRACKING_ENABLED
108 163 : if (!mChipStackIsLocked)
109 : {
110 0 : ChipLogError(DeviceLayer, "_UnlockChipStack while unlocked");
111 : #if CHIP_STACK_LOCK_TRACKING_ERROR_FATAL
112 0 : chipDie();
113 : #endif
114 : }
115 163 : mChipStackIsLocked = false;
116 163 : mChipStackLockOwnerThread = pthread_t();
117 : #endif
118 :
119 163 : int err = pthread_mutex_unlock(&mChipStackLock);
120 163 : assert(err == 0);
121 163 : }
122 :
123 : #if CHIP_STACK_LOCK_TRACKING_ENABLED
124 : template <class ImplClass>
125 65968438 : bool GenericPlatformManagerImpl_POSIX<ImplClass>::_IsChipStackLockedByCurrentThread() const
126 : {
127 : // If no Matter thread is currently running we do not have to worry about
128 : // locking. Hence, this function always returns true in that case.
129 65968438 : if (mState.load(std::memory_order_relaxed) == State::kStopped)
130 65968096 : return true;
131 342 : return mChipStackIsLocked && (pthread_equal(pthread_self(), mChipStackLockOwnerThread));
132 : }
133 : #endif
134 :
135 : template <class ImplClass>
136 0 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StartChipTimer(System::Clock::Timeout delay)
137 : {
138 : // Let System::LayerSocketsLoop.PrepareEvents() handle timers.
139 0 : return CHIP_NO_ERROR;
140 : }
141 :
142 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
143 : template <class ImplClass>
144 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_DispatchEventViaScheduleWork(System::Layer * aLayer, void * appState)
145 : {
146 : auto * event = static_cast<const ChipDeviceEvent *>(appState);
147 : PlatformMgrImpl().DispatchEvent(event);
148 : delete event;
149 : }
150 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
151 :
152 : template <class ImplClass>
153 179 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_PostEvent(const ChipDeviceEvent * event)
154 : {
155 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
156 : // Note: PostEvent() is documented to allow being called "from any thread".
157 : // In the libev mainloop case however, calling from another thread is NOT supported.
158 : // Introducing this restriction is OK because the very goal of using libev is to avoid
159 : // multiple threads by running matter and all application code in the same thread on the
160 : // libev mainloop. So getting called from another thread here is very likely a
161 : // application design error.
162 : VerifyOrDieWithMsg(_IsChipStackLockedByCurrentThread(), DeviceLayer, "PostEvent() not allowed from outside chip stack lock");
163 :
164 : // Schedule dispatching this event via System Layer's ScheduleWork
165 : ChipDeviceEvent * eventCopyP = new ChipDeviceEvent;
166 : VerifyOrDie(eventCopyP != nullptr);
167 : *eventCopyP = *event;
168 : SystemLayer().ScheduleWork(&_DispatchEventViaScheduleWork, eventCopyP);
169 : return CHIP_NO_ERROR;
170 : #else
171 179 : mChipEventQueue.Push(*event);
172 :
173 179 : SystemLayerSocketsLoop().Signal(); // Trigger wake select on CHIP thread
174 179 : return CHIP_NO_ERROR;
175 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
176 : }
177 :
178 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
179 :
180 : template <class ImplClass>
181 85 : void GenericPlatformManagerImpl_POSIX<ImplClass>::ProcessDeviceEvents()
182 : {
183 216 : while (!mChipEventQueue.Empty())
184 : {
185 131 : const ChipDeviceEvent event = mChipEventQueue.PopFront();
186 131 : Impl()->DispatchEvent(&event);
187 : }
188 85 : }
189 :
190 : template <class ImplClass>
191 74 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_RunEventLoop()
192 : {
193 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
194 :
195 : VerifyOrDieWithMsg(false, DeviceLayer, "libev based app should never try to run a separate event loop");
196 :
197 : #else
198 :
199 74 : pthread_mutex_lock(&mStateLock);
200 :
201 : //
202 : // If we haven't set mInternallyManagedChipTask by now, it means that the application did not call
203 : // StartEventLoopTask and consequently, are running the event loop from their own, externally managed
204 : // task.
205 : //
206 74 : if (!mInternallyManagedChipTask)
207 : {
208 68 : mChipTask = pthread_self();
209 68 : mState.store(State::kRunning, std::memory_order_relaxed);
210 68 : mShouldRunEventLoop.store(true, std::memory_order_relaxed);
211 : }
212 :
213 74 : pthread_mutex_unlock(&mStateLock);
214 :
215 74 : Impl()->LockChipStack();
216 :
217 74 : SystemLayerSocketsLoop().EventLoopBegins();
218 : do
219 : {
220 85 : SystemLayerSocketsLoop().PrepareEvents();
221 :
222 85 : Impl()->UnlockChipStack();
223 85 : SystemLayerSocketsLoop().WaitForEvents();
224 85 : Impl()->LockChipStack();
225 :
226 85 : SystemLayerSocketsLoop().HandleEvents();
227 :
228 85 : ProcessDeviceEvents();
229 85 : } while (mShouldRunEventLoop.load(std::memory_order_relaxed));
230 74 : SystemLayerSocketsLoop().EventLoopEnds();
231 :
232 74 : Impl()->UnlockChipStack();
233 :
234 74 : pthread_mutex_lock(&mStateLock);
235 74 : mState.store(State::kStopping, std::memory_order_relaxed);
236 74 : pthread_mutex_unlock(&mStateLock);
237 :
238 : //
239 : // Wake up anyone blocked waiting for the event queue to stop in
240 : // StopEventLoopTask().
241 : //
242 74 : pthread_cond_signal(&mEventQueueStoppedCond);
243 :
244 : //
245 : // Mark event loop as truly stopped. After that line, we can not use any
246 : // non-simple type member variables, because they can be destroyed by the
247 : // Shutdown() method.
248 : //
249 74 : mState.store(State::kStopped, std::memory_order_relaxed);
250 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
251 74 : }
252 :
253 : template <class ImplClass>
254 3 : void * GenericPlatformManagerImpl_POSIX<ImplClass>::EventLoopTaskMain(void * arg)
255 : {
256 3 : ChipLogDetail(DeviceLayer, "CHIP task running");
257 3 : static_cast<GenericPlatformManagerImpl_POSIX<ImplClass> *>(arg)->Impl()->RunEventLoop();
258 3 : return nullptr;
259 : }
260 :
261 : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
262 :
263 : template <class ImplClass>
264 3 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StartEventLoopTask()
265 : {
266 :
267 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
268 : // Note: With libev, we dont need our own mainloop.
269 : // Still, we set State::kRunning to activate lock checking, because
270 : // calls to ScheduleWork and some System Layer methods may not
271 : // occur from other threads (which usually don't exist in a
272 : // libev app)
273 : mState.store(State::kRunning, std::memory_order_relaxed);
274 : return CHIP_NO_ERROR;
275 : #else
276 :
277 : int err;
278 3 : err = pthread_attr_init(&mChipTaskAttr);
279 3 : VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
280 3 : err = pthread_attr_getschedparam(&mChipTaskAttr, &mChipTaskSchedParam);
281 3 : VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
282 :
283 : #if CHIP_DEVICE_CONFIG_RUN_AS_ROOT
284 : // set SCHED_RR need root/admin on Android
285 3 : err = pthread_attr_setschedpolicy(&mChipTaskAttr, SCHED_RR);
286 3 : VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
287 : #endif
288 :
289 3 : mShouldRunEventLoop.store(true, std::memory_order_relaxed);
290 :
291 : //
292 : // We need to grab the lock here since we have to protect setting
293 : // mHasValidChipTask, which will be read right away upon creating the
294 : // thread below.
295 : //
296 3 : pthread_mutex_lock(&mStateLock);
297 :
298 3 : err = pthread_create(&mChipTask, &mChipTaskAttr, EventLoopTaskMain, this);
299 3 : if (err == 0)
300 : {
301 3 : mInternallyManagedChipTask = true;
302 3 : mState.store(State::kRunning, std::memory_order_relaxed);
303 : }
304 :
305 3 : pthread_mutex_unlock(&mStateLock);
306 :
307 3 : return CHIP_ERROR_POSIX(err);
308 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
309 : }
310 :
311 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
312 : // fallback implementation
313 : void __attribute__((weak)) ExitExternalMainLoop()
314 : {
315 : // FIXME: implement better exit
316 : VerifyOrDieWithMsg(false, DeviceLayer, "Missing custom ExitExternalMainLoop() implementation for clean shutdown -> just die");
317 : }
318 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
319 :
320 : template <class ImplClass>
321 74 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StopEventLoopTask()
322 : {
323 :
324 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
325 : // with libev, the mainloop is set up and managed externally
326 : mState.store(State::kStopping, std::memory_order_relaxed);
327 : ExitExternalMainLoop(); // this callback needs to be implemented.
328 : mState.store(State::kStopped, std::memory_order_relaxed);
329 : return CHIP_NO_ERROR;
330 : #else
331 :
332 74 : int err = 0;
333 :
334 : //
335 : // Signal to the runloop to stop.
336 : //
337 74 : mShouldRunEventLoop.store(false, std::memory_order_relaxed);
338 :
339 74 : pthread_mutex_lock(&mStateLock);
340 :
341 : //
342 : // If we're calling this from a different thread than the one running chip, then
343 : // we need to wait till the event queue has completely stopped before proceeding.
344 : //
345 74 : auto isRunning = mState.load(std::memory_order_relaxed) == State::kRunning;
346 74 : if (isRunning && (pthread_equal(pthread_self(), mChipTask) == 0))
347 : {
348 3 : pthread_mutex_unlock(&mStateLock);
349 :
350 : //
351 : // We need to grab the lock to protect critical sections accessed by the WakeSelect() call within
352 : // System::Layer.
353 : //
354 3 : Impl()->LockChipStack();
355 3 : SystemLayerSocketsLoop().Signal();
356 3 : Impl()->UnlockChipStack();
357 :
358 3 : pthread_mutex_lock(&mStateLock);
359 :
360 6 : while (mState.load(std::memory_order_relaxed) == State::kRunning)
361 : {
362 3 : err = pthread_cond_wait(&mEventQueueStoppedCond, &mStateLock);
363 3 : VerifyOrExit(err == 0, );
364 : }
365 :
366 3 : pthread_mutex_unlock(&mStateLock);
367 :
368 : //
369 : // Wait further for the thread to terminate if we had previously created it.
370 : //
371 3 : if (mInternallyManagedChipTask)
372 : {
373 3 : err = pthread_join(mChipTask, nullptr);
374 3 : VerifyOrExit(err == 0, );
375 : }
376 : }
377 : else
378 : {
379 71 : pthread_mutex_unlock(&mStateLock);
380 : }
381 :
382 74 : exit:
383 74 : return CHIP_ERROR_POSIX(err);
384 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
385 : }
386 :
387 : template <class ImplClass>
388 48 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_Shutdown()
389 : {
390 : //
391 : // We cannot shutdown the stack while the event loop is still running. This can lead
392 : // to use after free errors - here we are destroying mutex and condition variable that
393 : // are still in use by the event loop!
394 : //
395 48 : VerifyOrDie(mState.load(std::memory_order_relaxed) == State::kStopped);
396 :
397 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
398 48 : pthread_mutex_destroy(&mStateLock);
399 48 : pthread_cond_destroy(&mEventQueueStoppedCond);
400 : #endif
401 :
402 : //
403 : // Call up to the base class _Shutdown() to perform the actual stack de-initialization
404 : // and clean-up
405 : //
406 48 : GenericPlatformManagerImpl<ImplClass>::_Shutdown();
407 48 : }
408 :
409 : // Fully instantiate the generic implementation class in whatever compilation unit includes this file.
410 : // NB: This must come after all templated class members are defined.
411 : template class GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>;
412 :
413 : } // namespace Internal
414 : } // namespace DeviceLayer
415 : } // namespace chip
416 :
417 : #endif // GENERIC_PLATFORM_MANAGER_IMPL_POSIX_CPP
|