/* * 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 #include #include #include #include #include namespace chip { namespace DeviceLayer { namespace Internal { gboolean MainLoop::ThreadTimeout(gpointer userData) { LoopData * loopData = reinterpret_cast(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(loopData), NULL); g_source_attach(source, loopData->mMainContext); g_source_unref(source); } gpointer MainLoop::ThreadMainHandler(gpointer data) { LoopData * loopData = reinterpret_cast(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(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(); 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(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::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(); 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(loopData)); if (interval) { loopData->mTimeoutFn = timeoutFn; loopData->mTimeoutUserData = timeoutUserData; SetThreadTimeout(loopData, interval); } } return result; } gpointer MainLoop::ThreadStartLSMainLoopHandler(gpointer data) { LoopData * loopData = reinterpret_cast(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(); 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(loopData)); } return result; } MainLoop & MainLoop::Instance() { static MainLoop sMainLoop; return sMainLoop; } } // namespace Internal } // namespace DeviceLayer } // namespace chip