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