blob: 56b5f28af8793472345828d46bb04a993f2790b9 [file] [log] [blame]
/*
* Copyright (c) 2021 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 <iterator>
#include <memory>
#include <utility>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
namespace chip {
namespace DeviceLayer {
namespace Internal {
LoopData::LoopData()
{
mMainContext = g_main_context_new();
mMainLoop = g_main_loop_new(mMainContext, FALSE);
}
LoopData::~LoopData()
{
if (mThread.joinable())
{
mThread.join();
}
if (mMainContext != nullptr)
{
g_main_context_unref(mMainContext);
}
if (mMainLoop != nullptr)
{
g_main_loop_unref(mMainLoop);
}
}
gboolean MainLoop::ThreadTimeout(gpointer userData)
{
LoopData * loopData = reinterpret_cast<LoopData *>(userData);
VerifyOrReturnError(loopData != nullptr, G_SOURCE_REMOVE);
ChipLogDetail(DeviceLayer, "[TIMEOUT] glib main loop [%p]", loopData->mMainLoop);
if (loopData->mTimeoutFn)
{
ChipLogDetail(DeviceLayer, "Running thread timeout function");
loopData->mTimeoutFn(loopData->mTimeoutUserData);
}
g_main_loop_quit(loopData->mMainLoop);
return G_SOURCE_REMOVE;
}
void MainLoop::ThreadHandler(std::shared_ptr<LoopData> loopData)
{
g_main_context_push_thread_default(loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[PUSH] thread default context [%p]", loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[RUN] glib main loop [%p]", loopData->mMainLoop);
g_main_loop_run(loopData->mMainLoop);
ChipLogDetail(DeviceLayer, "[QUIT] glib main loop [%p]", loopData->mMainLoop);
g_main_context_pop_thread_default(loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[POP] thread default context [%p]", loopData->mMainContext);
}
bool MainLoop::Init(initFn_t initFn, gpointer userData)
{
auto loopData = std::make_shared<LoopData>();
bool result = false;
VerifyOrReturnError(loopData, false);
g_main_context_push_thread_default(loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[PUSH] thread default context [%p]", loopData->mMainContext);
result = initFn(userData);
g_main_context_pop_thread_default(loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[POP] thread default context [%p]", loopData->mMainContext);
VerifyOrReturnError(result, false);
loopData->mThread = std::thread(ThreadHandler, loopData);
mLoopData.push_back(loopData);
return true;
}
void MainLoop::Deinit()
{
for (auto & loopData : mLoopData)
{
g_main_loop_quit(loopData->mMainLoop);
}
mLoopData.clear();
}
bool MainLoop::AsyncRequest(asyncFn_t asyncFn, gpointer asyncUserData, guint timeoutInterval, timeoutFn_t timeoutFn,
gpointer timeoutUserData)
{
auto loopData = std::make_shared<LoopData>();
bool result = false;
VerifyOrReturnError(loopData, false);
loopData->mTimeoutFn = timeoutFn;
loopData->mTimeoutUserData = timeoutUserData;
g_main_context_push_thread_default(loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[PUSH] thread default context [%p]", loopData->mMainContext);
result = asyncFn(loopData->mMainLoop, asyncUserData);
g_main_context_pop_thread_default(loopData->mMainContext);
ChipLogDetail(DeviceLayer, "[POP] thread default context [%p]", loopData->mMainContext);
VerifyOrReturnError(result, false);
loopData->mThread = std::thread(ThreadHandler, loopData);
loopData->mThread.detach();
if (timeoutInterval)
{
GSource * source = g_timeout_source_new_seconds(timeoutInterval);
g_source_set_callback(source, ThreadTimeout, loopData.get(), nullptr);
g_source_attach(source, loopData->mMainContext);
g_source_unref(source);
}
return true;
}
MainLoop & MainLoop::Instance()
{
static MainLoop sMainLoop;
return sMainLoop;
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip