| /* |
| * Copyright (c) 2022 Project CHIP Authors |
| * |
| * 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. |
| */ |
| |
| #include "MainLoop.h" |
| |
| #include <errno.h> |
| #include <lib/support/CHIPMem.h> |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| #include <pthread.h> |
| #include <system/SystemTimer.h> |
| |
| namespace chip { |
| namespace DeviceLayer { |
| namespace Internal { |
| |
| gboolean MainLoop::ThreadTimeout(gpointer userData) |
| { |
| LoopData * loopData = reinterpret_cast<LoopData *>(userData); |
| |
| VerifyOrReturnError(loopData != NULL, G_SOURCE_REMOVE); |
| |
| if (loopData->mTimeoutFn) |
| { |
| ChipLogProgress(DeviceLayer, "[Timeout] thread timeout function"); |
| loopData->mTimeoutFn(loopData->mTimeoutUserData); |
| } |
| |
| if (loopData->mMainLoop) |
| { |
| ChipLogProgress(DeviceLayer, "[Timeout] main loop %p", loopData->mMainLoop); |
| g_main_loop_quit(loopData->mMainLoop); |
| } |
| |
| return G_SOURCE_REMOVE; |
| } |
| |
| void MainLoop::SetThreadTimeout(LoopData * loopData, guint interval) |
| { |
| VerifyOrReturn(loopData != NULL); |
| |
| GSource * source = g_timeout_source_new_seconds(interval); |
| g_source_set_callback(source, ThreadTimeout, reinterpret_cast<gpointer>(loopData), NULL); |
| g_source_attach(source, loopData->mMainContext); |
| g_source_unref(source); |
| } |
| |
| gpointer MainLoop::ThreadMainHandler(gpointer data) |
| { |
| LoopData * loopData = reinterpret_cast<LoopData *>(data); |
| |
| g_main_context_push_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[PUSH] main context %p", loopData->mMainContext); |
| |
| ChipLogProgress(DeviceLayer, "[RUN] main loop %p", loopData->mMainLoop); |
| g_main_loop_run(loopData->mMainLoop); |
| ChipLogProgress(DeviceLayer, "[QUIT] main loop %p", loopData->mMainLoop); |
| g_main_loop_unref(loopData->mMainLoop); |
| loopData->mMainLoop = NULL; |
| |
| g_main_context_pop_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[POP] main context %p", loopData->mMainContext); |
| g_main_context_unref(loopData->mMainContext); |
| loopData->mMainContext = NULL; |
| |
| return NULL; |
| } |
| |
| gpointer MainLoop::ThreadAsyncHandler(gpointer data) |
| { |
| LoopData * loopData = reinterpret_cast<LoopData *>(data); |
| |
| g_main_context_push_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[PUSH] async context %p", loopData->mMainContext); |
| |
| ChipLogProgress(DeviceLayer, "[RUN] async loop %p", loopData->mMainLoop); |
| g_main_loop_run(loopData->mMainLoop); |
| ChipLogProgress(DeviceLayer, "[QUIT] async loop %p", loopData->mMainLoop); |
| g_main_loop_unref(loopData->mMainLoop); |
| loopData->mMainLoop = NULL; |
| |
| g_main_context_pop_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[POP] async context %p", loopData->mMainContext); |
| g_main_context_unref(loopData->mMainContext); |
| loopData->mMainContext = NULL; |
| |
| chip::Platform::Delete(loopData); |
| |
| return NULL; |
| } |
| |
| bool MainLoop::Init(initFn_t initFn, gpointer userData) |
| { |
| bool result; |
| LoopData * loopData = chip::Platform::New<LoopData>(); |
| |
| VerifyOrReturnError(loopData != NULL, false); |
| |
| loopData->mMainContext = g_main_context_new(); |
| loopData->mMainLoop = g_main_loop_new(loopData->mMainContext, FALSE); |
| |
| g_main_context_push_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[PUSH] main context %p", loopData->mMainContext); |
| |
| result = initFn(userData); |
| |
| g_main_context_pop_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[POP] main context %p", loopData->mMainContext); |
| |
| if (result != false) |
| { |
| loopData->mThread = g_thread_new("ThreadMainHandler", ThreadMainHandler, reinterpret_cast<gpointer>(loopData)); |
| mLoopData.push_back(loopData); |
| } |
| |
| return result; |
| } |
| |
| void MainLoop::DeleteData(LoopData * loopData) |
| { |
| if (loopData->mMainLoop) |
| { |
| g_main_loop_quit(loopData->mMainLoop); |
| g_thread_join(loopData->mThread); |
| } |
| |
| chip::Platform::Delete(loopData); |
| } |
| |
| void MainLoop::Deinit() |
| { |
| std::vector<LoopData *>::const_iterator iter = mLoopData.cbegin(); |
| while (iter != mLoopData.cend()) |
| { |
| DeleteData(*iter); |
| mLoopData.erase(iter); |
| iter++; |
| } |
| } |
| |
| bool MainLoop::AsyncRequest(asyncFn_t asyncFn, gpointer asyncUserData, guint interval, timeoutFn_t timeoutFn, |
| gpointer timeoutUserData) |
| { |
| bool result = false; |
| LoopData * loopData = chip::Platform::New<LoopData>(); |
| |
| VerifyOrReturnError(loopData != NULL, false); |
| |
| loopData->mMainContext = g_main_context_new(); |
| loopData->mMainLoop = g_main_loop_new(loopData->mMainContext, FALSE); |
| |
| g_main_context_push_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[PUSH] async context %p", loopData->mMainContext); |
| |
| result = asyncFn(loopData->mMainLoop, asyncUserData); |
| |
| g_main_context_pop_thread_default(loopData->mMainContext); |
| ChipLogProgress(DeviceLayer, "[POP] async context %p", loopData->mMainContext); |
| |
| if (result != false) |
| { |
| loopData->mThread = g_thread_new("ThreadAsyncHandler", ThreadAsyncHandler, reinterpret_cast<gpointer>(loopData)); |
| |
| if (interval) |
| { |
| loopData->mTimeoutFn = timeoutFn; |
| loopData->mTimeoutUserData = timeoutUserData; |
| SetThreadTimeout(loopData, interval); |
| } |
| } |
| |
| return result; |
| } |
| |
| gpointer MainLoop::ThreadStartLSMainLoopHandler(gpointer data) |
| { |
| LoopData * loopData = reinterpret_cast<LoopData *>(data); |
| |
| ChipLogProgress(DeviceLayer, "[RUN] LS2 loop %p", loopData->mMainLoop); |
| g_main_loop_run(loopData->mMainLoop); |
| ChipLogProgress(DeviceLayer, "[QUIT] LS2 loop %p", loopData->mMainLoop); |
| g_main_loop_unref(loopData->mMainLoop); |
| loopData->mMainLoop = NULL; |
| |
| g_main_context_unref(loopData->mMainContext); |
| loopData->mMainContext = NULL; |
| |
| chip::Platform::Delete(loopData); |
| |
| return NULL; |
| } |
| |
| bool MainLoop::StartLSMainLoop() |
| { |
| bool result = true; |
| LSError lserror; |
| LSErrorInit(&lserror); |
| |
| LoopData * loopData = chip::Platform::New<LoopData>(); |
| |
| VerifyOrReturnError(loopData != NULL, false); |
| |
| loopData->mMainContext = g_main_context_new(); |
| loopData->mMainLoop = g_main_loop_new(loopData->mMainContext, FALSE); |
| |
| if (!LSRegister("com.webos.service.matter-1234", &mLSHandle, &lserror)) |
| { |
| g_print("Unable to register to luna-bus\n"); |
| LSErrorFree(&lserror); |
| result = false; |
| } |
| |
| if (!LSGmainAttach(mLSHandle, loopData->mMainLoop, &lserror)) |
| { |
| g_print("Unable to attach service\n"); |
| result = false; |
| } |
| |
| if (result != false) |
| { |
| loopData->mThread = |
| g_thread_new("ThreadStartLSMainLoopHandler", ThreadStartLSMainLoopHandler, reinterpret_cast<gpointer>(loopData)); |
| } |
| |
| return result; |
| } |
| |
| MainLoop & MainLoop::Instance() |
| { |
| static MainLoop sMainLoop; |
| return sMainLoop; |
| } |
| |
| } // namespace Internal |
| } // namespace DeviceLayer |
| } // namespace chip |