Skip to content

Commit

Permalink
Add python main loop work method
Browse files Browse the repository at this point in the history
  • Loading branch information
andreilitvin committed Aug 1, 2023
1 parent 4a2d6e9 commit 91d4722
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 50 deletions.
8 changes: 8 additions & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ config("controller_wno_deprecate") {
declare_args() {
chip_python_version = "0.0"
chip_python_package_prefix = "chip"
chip_python_supports_stack_locking = (current_os != "mac") || (current_os != "ios")
}

shared_library("ChipDeviceCtrl") {
Expand Down Expand Up @@ -78,11 +79,18 @@ shared_library("ChipDeviceCtrl") {
"chip/internal/CommissionerImpl.cpp",
"chip/logging/LoggingRedirect.cpp",
"chip/native/PyChipError.cpp",
"chip/native/ChipMainLoopWork.h",
"chip/tracing/TracingSetup.cpp",
"chip/utils/DeviceProxyUtils.cpp",
]
defines += [ "CHIP_CONFIG_MAX_GROUPS_PER_FABRIC=50" ]
defines += [ "CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC=50" ]

if (chip_python_supports_stack_locking) {
sources += [ "chip/native/ChipMainLoopWork_StackLock.cpp" ]
} else {
sources += [ "chip/native/ChipMainLoopWork_WorkSchedule.cpp" ]
}
} else {
sources += [
"chip/server/Options.cpp",
Expand Down
39 changes: 39 additions & 0 deletions src/controller/python/chip/native/ChipMainLoopWork.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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.
*/
#pragma once

#include <functional>

namespace chip {
namespace MainLoopWork {

/**
* Executes the given function in the CHIP main loop if one exists.
*
* If chip stack locking is available, this will lock the chip stack
* and execute `f`.
*
* If chip stack locking is not available:
* - if already in the chip main loop, this will execute `f` right away
* - if main loop running, this will schedule and WAIT for `f` to execute
* - if main loop is stopped, this will execute `f` right away
*/
void ExecuteInMainLoop(std::function<void()> f);

} // namespace MainLoopWork
} // namespace chip
43 changes: 43 additions & 0 deletions src/controller/python/chip/native/ChipMainLoopWork_StackLock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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 "ChipMainLoopWork.h"

#include <platform/PlatformManager.h>

namespace chip {
namespace MainLoopWork {
namespace {

using chip::DeviceLayer::PlatformMgr;

class ScopedStackLock
{
public:
ScopedStackLock() { PlatformMgr().LockChipStack(); }
~ScopedStackLock() { PlatformMgr().UnlockChipStack(); }
};

} // namespace

void ExecuteInMainLoop(std::function<void()> f) {
ScopedStackLock lock;
f();
}

} // namespace MainLoopWork
} // namespace chip
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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 "ChipMainLoopWork.h"

#include <platform/CHIPDeviceLayer.h>
#include <semaphore.h>

namespace chip {
namespace MainLoopWork {
namespace {

struct WorkData
{
std::function<void()> callback;
sem_t done;

WorkData() { sem_init(&done, 0 /* shared */, 0); }
~WorkData() { sem_destroy(&done); }
void Post() { sem_post(&done); }
void Wait() { sem_wait(&done); }
};

void PerformWork(intptr_t arg)
{
WorkData * work = reinterpret_cast<WorkData *>(arg);

work->callback();
work->Post();
}


} // namespace

void ExecuteInMainLoop(std::function<void()> f) {

#if CHIP_STACK_LOCK_TRACKING_ENABLED
if (chip::DeviceLayer::PlatformMgr().IsChipStackLockedByCurrentThread()) {
f();
return;
}
#endif

#if defined(__APPLE__)
if (chip::DeviceLayer::PlatformManagerImpl()::IsWorkQueueCurrentQueue()) {
f();
return;
}
#endif


// NOTE: the code below assumes that chip main loop is running.
// if it does not, this will deadlock.
//
// When CHIP_STACK_LOCK_TRACKING_ENABLED, stack locking will detect
// main event loop not running, so this will not run when chip event
// loop is stopped
//
// The cases when this will deadlock is:
// - chip stack lock tracking is disabled
// - main chip loop is not started (or stopped already)
WorkData workdata;
workdata.callback = f;
chip::DeviceLayer::PlatformMgr().ScheduleWork(PerformWork, reinterpret_cast<intptr_t>(&workdata));
workdata.Wait();
}

} // namespace MainLoopWork
} // namespace chip
92 changes: 42 additions & 50 deletions src/controller/python/chip/tracing/TracingSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* limitations under the License.
*/

#include <controller/python/chip/native/ChipMainLoopWork.h>
#include <controller/python/chip/native/PyChipError.h>
#include <platform/PlatformManager.h>

#include <tracing/json/json_tracing.h>
#include <tracing/perfetto/event_storage.h>
Expand All @@ -27,17 +27,6 @@
#include <tracing/registry.h>

namespace {

using chip::DeviceLayer::PlatformMgr;

class ScopedStackLock
{
public:
ScopedStackLock() { PlatformMgr().LockChipStack(); }

~ScopedStackLock() { PlatformMgr().UnlockChipStack(); }
};

chip::Tracing::Json::JsonBackend gJsonBackend;

chip::Tracing::Perfetto::FileTraceOutput gPerfettoFileOutput;
Expand All @@ -47,58 +36,61 @@ chip::Tracing::Perfetto::PerfettoBackend gPerfettoBackend;

extern "C" void pychip_tracing_start_json_log(const char * file_name)
{

ScopedStackLock lock;

gJsonBackend.CloseFile(); // just in case, ensure no file output
chip::Tracing::Register(gJsonBackend);
chip::MainLoopWork::ExecuteInMainLoop([] {
gJsonBackend.CloseFile(); // just in case, ensure no file output
chip::Tracing::Register(gJsonBackend);
});
}

extern "C" PyChipError pychip_tracing_start_json_file(const char * file_name)
{
ScopedStackLock lock;

CHIP_ERROR err = gJsonBackend.OpenFile(file_name);
if (err != CHIP_NO_ERROR)
{
return ToPyChipError(err);
}
chip::Tracing::Register(gJsonBackend);
return ToPyChipError(CHIP_NO_ERROR);
CHIP_ERROR err = CHIP_NO_ERROR;

chip::MainLoopWork::ExecuteInMainLoop([&err, file_name] {
err = gJsonBackend.OpenFile(file_name);
if (err != CHIP_NO_ERROR)
{
return;
}
chip::Tracing::Register(gJsonBackend);
});

return ToPyChipError(err);
}

extern "C" void pychip_tracing_start_perfetto_system()
{
ScopedStackLock lock;

chip::Tracing::Perfetto::Initialize(perfetto::kSystemBackend);
chip::Tracing::Perfetto::RegisterEventTrackingStorage();
chip::Tracing::Register(gPerfettoBackend);
chip::MainLoopWork::ExecuteInMainLoop([] {
chip::Tracing::Perfetto::Initialize(perfetto::kSystemBackend);
chip::Tracing::Perfetto::RegisterEventTrackingStorage();
chip::Tracing::Register(gPerfettoBackend);
});
}

extern "C" PyChipError pychip_tracing_start_perfetto_file(const char * file_name)
{
ScopedStackLock lock;

chip::Tracing::Perfetto::Initialize(perfetto::kInProcessBackend);
chip::Tracing::Perfetto::RegisterEventTrackingStorage();

CHIP_ERROR err = gPerfettoFileOutput.Open(file_name);
if (err != CHIP_NO_ERROR)
{
return ToPyChipError(err);
}
chip::Tracing::Register(gPerfettoBackend);

return ToPyChipError(CHIP_NO_ERROR);
CHIP_ERROR err = CHIP_NO_ERROR;
chip::MainLoopWork::ExecuteInMainLoop([&err, file_name] {
chip::Tracing::Perfetto::Initialize(perfetto::kInProcessBackend);
chip::Tracing::Perfetto::RegisterEventTrackingStorage();

err = gPerfettoFileOutput.Open(file_name);
if (err != CHIP_NO_ERROR)
{
return;
}
chip::Tracing::Register(gPerfettoBackend);
});

return ToPyChipError(err);
}

extern "C" void pychip_tracing_stop()
{
ScopedStackLock lock;

chip::Tracing::Perfetto::FlushEventTrackingStorage();
gPerfettoFileOutput.Close();
chip::Tracing::Unregister(gPerfettoBackend);
chip::Tracing::Unregister(gJsonBackend);
chip::MainLoopWork::ExecuteInMainLoop([] {
chip::Tracing::Perfetto::FlushEventTrackingStorage();
gPerfettoFileOutput.Close();
chip::Tracing::Unregister(gPerfettoBackend);
chip::Tracing::Unregister(gJsonBackend);
});
}

0 comments on commit 91d4722

Please sign in to comment.