forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlatformManagerImpl.h
175 lines (143 loc) · 5.67 KB
/
PlatformManagerImpl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Provides an implementation of the PlatformManager object.
*/
#pragma once
#include "lib/core/CHIPError.h"
#include <condition_variable>
#include <mutex>
#include <platform/PlatformManager.h>
#include <platform/internal/GenericPlatformManagerImpl_POSIX.h>
#if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
#include <gio/gio.h>
#endif
namespace chip {
namespace DeviceLayer {
/**
* Concrete implementation of the PlatformManager singleton object for Linux platforms.
*/
class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>
{
// Allow the PlatformManager interface class to delegate method calls to
// the implementation methods provided by this class.
friend PlatformManager;
// Allow the generic implementation base class to call helper methods on
// this class.
#ifndef DOXYGEN_SHOULD_SKIP_THIS
friend Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>;
#endif
public:
// ===== Platform-specific members that may be accessed directly by the application.
#if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
/**
* @brief Invoke a function on the Matter GLib context.
*
* If execution of the function will have to be scheduled on other thread,
* this call will block the current thread until the function is executed.
*
* @param[in] function The function to call.
* @param[in] userData User data to pass to the function.
* @returns The result of the function.
*/
template <typename T>
CHIP_ERROR GLibMatterContextInvokeSync(CHIP_ERROR (*func)(T *), T * userData)
{
struct
{
CHIP_ERROR returnValue = CHIP_NO_ERROR;
CHIP_ERROR (*functionToCall)(T *);
T * userData;
} context;
context.functionToCall = func;
context.userData = userData;
LambdaBridge bridge;
bridge.Initialize([&context]() { context.returnValue = context.functionToCall(context.userData); });
_GLibMatterContextInvokeSync(std::move(bridge));
return context.returnValue;
}
unsigned int GLibMatterContextAttachSource(GSource * source)
{
VerifyOrDie(mGLibMainLoop != nullptr);
return g_source_attach(source, g_main_loop_get_context(mGLibMainLoop));
}
#endif
System::Clock::Timestamp GetStartTime() { return mStartTime; }
private:
// ===== Methods that implement the PlatformManager abstract interface.
CHIP_ERROR _InitChipStack();
void _Shutdown();
// ===== Members for internal use by the following friends.
friend PlatformManager & PlatformMgr();
friend PlatformManagerImpl & PlatformMgrImpl();
friend class Internal::BLEManagerImpl;
System::Clock::Timestamp mStartTime = System::Clock::kZero;
static PlatformManagerImpl sInstance;
#if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
struct GLibMatterContextInvokeData
{
LambdaBridge bridge;
// Sync primitives to wait for the function to be executed
std::condition_variable mDoneCond;
bool mDone = false;
};
/**
* @brief Invoke a function on the Matter GLib context.
*
* @param[in] bridge a LambdaBridge object that holds the lambda to be invoked within the GLib context.
*
* @note This function moves the LambdaBridge into the GLib context for invocation.
* The LambdaBridge is created and initialised in GLibMatterContextInvokeSync().
* use the GLibMatterContextInvokeSync() template function instead of this one.
*/
void _GLibMatterContextInvokeSync(LambdaBridge && bridge);
// XXX: Mutex for guarding access to glib main event loop callback indirection
// synchronization primitives. This is a workaround to suppress TSAN warnings.
// TSAN does not know that from the thread synchronization perspective the
// g_source_attach() function should be treated as pthread_create(). Memory
// access to shared data before the call to g_source_attach() without mutex
// is not a race condition - the callback will not be executed on glib main
// event loop thread before the call to g_source_attach().
std::mutex mGLibMainLoopCallbackIndirectionMutex;
GMainLoop * mGLibMainLoop = nullptr;
GThread * mGLibMainLoopThread = nullptr;
#endif // CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
};
/**
* Returns the public interface of the PlatformManager singleton object.
*
* chip applications should use this to access features of the PlatformManager object
* that are common to all platforms.
*/
inline PlatformManager & PlatformMgr()
{
return PlatformManagerImpl::sInstance;
}
/**
* Returns the platform-specific implementation of the PlatformManager singleton object.
*
* chip applications can use this to gain access to features of the PlatformManager
* that are specific to the platform.
*/
inline PlatformManagerImpl & PlatformMgrImpl()
{
return PlatformManagerImpl::sInstance;
}
} // namespace DeviceLayer
} // namespace chip