Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / Tizen / bluez / MainLoop.cpp
1 /*
2  *    Copyright (c) 2021 Project CHIP Authors
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "MainLoop.h"
18
19 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
20
21 #include <errno.h>
22 #include <pthread.h>
23 #include <support/CodeUtils.h>
24 #include <support/logging/CHIPLogging.h>
25
26 namespace chip {
27 namespace DeviceLayer {
28 namespace Internal {
29
30 namespace {
31
32 class Semaphore
33 {
34 public:
35     Semaphore()
36     {
37         if (sem_init(&mSemaphore, 0 /* shared */, 0 /*value*/) != 0)
38         {
39             ChipLogError(DeviceLayer, "Failed to initialize semaphore.");
40         }
41     }
42
43     ~Semaphore()
44     {
45         if (sem_destroy(&mSemaphore) != 0)
46         {
47             ChipLogError(DeviceLayer, "Failed to destroy semaphore.");
48         }
49     }
50
51     void Post() { sem_post(&mSemaphore); }
52
53     void Wait() { sem_wait(&mSemaphore); }
54
55 private:
56     sem_t mSemaphore;
57 };
58
59 int PostSemaphore(Semaphore * semaphore)
60 {
61     semaphore->Post();
62     return 0;
63 }
64
65 class CallbackIndirection
66 {
67 public:
68     CallbackIndirection(GSourceFunc f, void * a) : mCallback(f), mArgument(a) {}
69
70     void Wait() { mDoneSemaphore.Wait(); }
71
72     static int Callback(CallbackIndirection * self)
73     {
74         int result = self->mCallback(self->mArgument);
75         self->mDoneSemaphore.Post();
76         return result;
77     }
78
79 private:
80     Semaphore mDoneSemaphore;
81     GSourceFunc mCallback;
82     void * mArgument;
83 };
84
85 } // namespace
86
87 MainLoop & MainLoop::Instance()
88 {
89     static MainLoop sMainLoop;
90     return sMainLoop;
91 }
92
93 void * MainLoop::Thread(void * self)
94 {
95     MainLoop * loop = reinterpret_cast<MainLoop *>(self);
96
97     ChipLogDetail(DeviceLayer, "TRACE: Bluez mainloop starting %s", __func__);
98     g_main_loop_run(loop->mBluezMainLoop);
99     ChipLogDetail(DeviceLayer, "TRACE: Bluez mainloop stopping %s", __func__);
100
101     if (loop->mCleanup != nullptr)
102     {
103         ChipLogDetail(DeviceLayer, "TRACE: Executing cleanup %s", __func__);
104         loop->mCleanup(loop->mCleanupArgument);
105     }
106
107     return nullptr;
108 }
109
110 CHIP_ERROR MainLoop::EnsureStarted()
111 {
112     if (mBluezMainLoop != nullptr)
113     {
114         return CHIP_NO_ERROR;
115     }
116
117     mBluezMainLoop = g_main_loop_new(nullptr, TRUE);
118     if (mBluezMainLoop == nullptr)
119     {
120         ChipLogError(DeviceLayer, "FAIL: memory alloc in %s", __func__);
121         return CHIP_ERROR_NO_MEMORY;
122     }
123
124     int pthreadErr = pthread_create(&mThread, nullptr, &MainLoop::Thread, reinterpret_cast<void *>(this));
125     int tmpErrno   = errno;
126     if (pthreadErr != 0)
127     {
128         ChipLogError(DeviceLayer, "FAIL: pthread_create (%s) in %s", strerror(tmpErrno), __func__);
129         g_free(mBluezMainLoop);
130         mBluezMainLoop = nullptr;
131         return CHIP_ERROR_INTERNAL;
132     }
133
134     Semaphore semaphore;
135
136     GMainContext * context = g_main_loop_get_context(mBluezMainLoop);
137     VerifyOrDie(context != nullptr);
138
139     g_main_context_invoke(context, GSourceFunc(PostSemaphore), &semaphore);
140
141     semaphore.Wait();
142
143     return CHIP_NO_ERROR;
144 }
145
146 bool MainLoop::RunOnBluezThread(GSourceFunc callback, void * argument)
147 {
148     GMainContext * context = nullptr;
149     const char * msg       = nullptr;
150
151     VerifyOrExit(mBluezMainLoop != nullptr, msg = "FAIL: NULL sBluezMainLoop");
152     VerifyOrExit(g_main_loop_is_running(mBluezMainLoop), msg = "FAIL: sBluezMainLoop not running");
153
154     context = g_main_loop_get_context(mBluezMainLoop);
155     VerifyOrExit(context != nullptr, msg = "FAIL: NULL main context");
156     g_main_context_invoke(context, callback, argument);
157
158 exit:
159     if (msg != nullptr)
160     {
161         ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
162     }
163
164     return msg == nullptr;
165 }
166
167 bool MainLoop::RunOnBluezThreadAndWait(GSourceFunc closure, void * argument)
168 {
169     CallbackIndirection indirection(closure, argument);
170
171     if (!Schedule(&CallbackIndirection::Callback, &indirection))
172     {
173         return false;
174     }
175
176     indirection.Wait();
177
178     return true;
179 }
180
181 } // namespace Internal
182 } // namespace DeviceLayer
183 } // namespace chip
184
185 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE