Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize socket-based event loop #6561

Merged
merged 6 commits into from
Jun 18, 2021
Merged

Conversation

kpschoedel
Copy link
Contributor

@kpschoedel kpschoedel commented May 6, 2021

Problem

Socket event management is currently tied closely to select(2),
and does not integrate well with other event loops.

See issue #5556 rework system layer event loop

Change overview

The primary purpose of this change is to provide a clear interface for
monitoring socket events, that can be used both within the CHIP SDK
and by an application using the SDK, and can be implemented either
inside or outside the SDK. Functionality does not change.

  • Defines an interface, in system/SystemSockets.h.
  • Converts most existing uses of socket event monitoring (except mDNS,
    to be done as a followup).
  • Converts the existing select(2)-based event management into an
    implementation of the new interface.
  • Adds a second implementation of the interface, using libevent,
    to verify that the interface is general enough.

Testing

  • Converted the applicable unit tests from select(2) to this interface,
    and ran them with both the select and libevent implementations.
    (CI remains select-only for now.)
  • Integration tests involving socket-based platforms exercise this code
    and confirm no change to functionality.
  • Manual verification of controller/device communication

src/inet/InetLayer.cpp Outdated Show resolved Hide resolved

#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unclear from the current arrangement of the code whether CHIP_SYSTEM_CONFIG_USE_IO_THREAD == (CHIP_SYSTEM_CONFIG_USE_SOCKETS == 1) && (CHIP_SYSTEM_CONFIG_SOCKETS_USE_SELECT == 0) or if CHIP_SYSTEM_CONFIG_USE_IO_THREAD is completely independent of either of those.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a part that needs to be fleshed out. It's independent of the interface for file descriptor watching, but dependent on the implementation. Some may require a thread (as select does), some may require there not be one (e.g. using a CHIP-consuming application's mechanism instead), and some may go either way. Actual #if tests should end up much reduced, since I can probably abstract WakeIOThread() (previously WakeSelect()) a bit more.

@@ -2368,15 +2372,15 @@ void TCPEndPoint::HandlePendingIO()
// ready to be received on the socket, process the incoming connection.
if (State == kState_Listening)
{
if (OnConnectionReceived != nullptr && mPendingIO.IsReadable())
if (OnConnectionReceived != nullptr && mPendingIO.Has(System::SocketEventFlag::kRead))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not make IsReadable() as a convenience inline for Has(System::SocketEventFlag::kRead)?

Copy link
Contributor Author

@kpschoedel kpschoedel May 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern for most other flag sets in the code is not to have them, so I didn't re-add them when moving SocketEvents to use the type-safe BitFlags when I had to move it from inet to system. Easy enough to replace. (A bit sad that enum class can't have methods, not to mention a bitwise mixin.)

HandleIncomingConnection();
}

// If in the processes of initiating a connection...
else if (State == kState_Connecting)
{
// The socket being writable indicates the connection has completed (successfully or otherwise).
if (mPendingIO.IsWriteable())
if (mPendingIO.Has(System::SocketEventFlag::kWrite))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not make IsWriteable() as a convenience inline for Has(System::SocketEventFlag::kWrite)?

@@ -35,7 +35,7 @@ namespace chip {
* in the range of valid values for T.
*/
template <typename T, typename U>
bool CanCastTo(U arg)
constexpr bool CanCastTo(U arg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth factoring this out as a simple one-liner PR.

Copy link
Contributor Author

@kpschoedel kpschoedel May 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. (The reason I touched this actually no longer exists in this PR. Most uses of CanCastTo are testing dynamically computer values, but I think there are a small number of tests that could be replaced with a static_assert. CanCastTo couldn't be constexpr in C++11, but can be now in C++14.)

@@ -111,6 +111,14 @@

// clang-format off

#ifndef CHIP_SYSTEM_CONFIG_USE_IO_THREAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See prior comments about CHIP_SYSTEM_CONFIG_USE_IO_THREAD. There might be an opportunity to detect and flag incorrect configurations.

FD_SET(socket, writefds);
if (IsError())
if (mRequestIO.Has(System::SocketEventFlag::kError))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See prior comments on convenience inlines.

@gerickson
Copy link
Contributor

Will check this out. With CHIP, one of my integration goals would be / is to make the CHIP stack an easy add-on as a CoreFoundation run loop source. I'll be looking at this through that integration lens.

@gerickson
Copy link
Contributor

Will check this out. With CHIP, one of my integration goals would be / is to make the CHIP stack an easy add-on as a CoreFoundation run loop source. I'll be looking at this through that integration lens.

The PR seems reasonable; however, not having ever worked with Darwin libnetwork, I'm probably not the best person to assess that integration goal (but the code doesn't seem harmful toward that end at all and certainly seems to help). As for the CoreFoundation run loop, at minimum, such an integration would seem to require an import/export of sockets, which is likely no different / worse than integrating CoreFoundation run loops with a pure BSD sockets implementation, as opposed to CFNetwork sources.

@msandstedt
Copy link
Contributor

I had previously found that for the posix platform, the following was sufficient to allow driving the task function from an existing event loop:

diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
index 5d34c339bb..abe2087683 100644
--- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
+++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
@@ -155,8 +155,11 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::SysProcess()
     nextTimeoutMs = mNextTimeout.tv_sec * 1000 + mNextTimeout.tv_usec / 1000;
     _StartChipTimer(nextTimeoutMs);
 
+    // override; select must not block.
+    struct timeval immediate = { .tv_sec = 0, .tv_usec = 0 };
+
     Impl()->UnlockChipStack();
-    selectRes = select(mMaxFd + 1, &mReadSet, &mWriteSet, &mErrorSet, &mNextTimeout);
+    selectRes = select(mMaxFd + 1, &mReadSet, &mWriteSet, &mErrorSet, &immediate);
     Impl()->LockChipStack();
 
     if (selectRes < 0)
@@ -192,7 +195,7 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::_RunEventLoop()
     {
         SysUpdate();
         SysProcess();
-    } while (mShouldRunEventLoop.load(std::memory_order_relaxed));
+    } while (0); // mShouldRunEventLoop.load(std::memory_order_relaxed));
 
     Impl()->UnlockChipStack();
 }

One of the main sales pitches here is that this set of changes also can allow such a thing. But if the above is so concise, why are the proposed changes in this PR better? I'm not asking this as a rhetorical question. It is implied what's in this PR is better and I want to understand why.

I can see some other problems with select, but I don't think we have a C10K problem to solve. I'm therefore assuming performance isn't a primary motivator.

Copy link
Contributor

@mspang mspang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had previously found that for the posix platform, the following was sufficient to allow driving the task function from an existing event loop:

diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
index 5d34c339bb..abe2087683 100644
--- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
+++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
@@ -155,8 +155,11 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::SysProcess()
     nextTimeoutMs = mNextTimeout.tv_sec * 1000 + mNextTimeout.tv_usec / 1000;
     _StartChipTimer(nextTimeoutMs);
 
+    // override; select must not block.
+    struct timeval immediate = { .tv_sec = 0, .tv_usec = 0 };
+
     Impl()->UnlockChipStack();
-    selectRes = select(mMaxFd + 1, &mReadSet, &mWriteSet, &mErrorSet, &mNextTimeout);
+    selectRes = select(mMaxFd + 1, &mReadSet, &mWriteSet, &mErrorSet, &immediate);
     Impl()->LockChipStack();
 
     if (selectRes < 0)
@@ -192,7 +195,7 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::_RunEventLoop()
     {
         SysUpdate();
         SysProcess();
-    } while (mShouldRunEventLoop.load(std::memory_order_relaxed));
+    } while (0); // mShouldRunEventLoop.load(std::memory_order_relaxed));
 
     Impl()->UnlockChipStack();
 }

That code does not seem sufficient; I don't even see how you would correctly combine this approach with polling other (non-CHIP) file descriptors on the same thread.

To fix the problem, CHIP must register its file descriptors to be included in application's poll set, so that the thread can block itself pending IO on either CHIP owned or application owned file descriptors. Properly there can only be one blocking I/O poll on any given thread. If instead CHIP does a non-blocking poll, and the application does a blocking one, then we won't wake immediately when e.g. UDP packets arrive for CHIP. It may appear to work if there's ongoing activity, but it risks unbounded additional response latency.

This is not about scalability, it's about having the flexibility to use an applications' preferred event loop for the file descriptors managed by CHIP.

One of the main sales pitches here is that this set of changes also can allow such a thing. But if the above is so concise, why are the proposed changes in this PR better? I'm not asking this as a rhetorical question. It is implied what's in this PR is better and I want to understand why.

I can see some other problems with select, but I don't think we have a C10K problem to solve. I'm therefore assuming performance isn't a primary motivator.

* For BSD/POSIX Sockets, event readiness notification is handled
* via file descriptors and a traditional poll / select
* implementation on the platform adaptation.
* For BSD/POSIX Sockets (CHIP_SYSTEM_CONFIG_USE_LWIP), event readiness
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHIP_SYSTEM_CONFIG_USE_LWIP -> CHIP_SYSTEM_CONFIG_USE_SOCKETS ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I will definitely fix and add substantially more documentation.

void SystemSocketWatchState::HandleEvents()
{
VerifyOrDie(mEventBase != nullptr);
event_base_dispatch(mEventBase);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be event_base_loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably. I've gone back and forth on what exactly HandleEvents() should mean, so the second opinion is welcome.

void ClearReadable() { mRequestIO.Clear(System::SocketEventFlag::kRead); }
void ClearWritable() { mRequestIO.Clear(System::SocketEventFlag::kWrite); }

// Platform is currently hard-coded to use InetLayer::HandleSelectResult().
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we able to remove this discrepancy and make both work with SetCallback & remove HandleSelectResult?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that should be easy; I just put it off. The remaining #if-select() code would be the PrepareSelect/HandleSelectResult stuff in //system, which looks a bit harder to refactor, but probably possible — if anybody's still going to want to use select() in the long run.

class SystemSocketWatcherBasis
{
public:
typedef void (*Callback)(int socket, SocketEvents events, void * data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could replace this class with

using SystemSocketWatcherCallback = void(int socket, SocketEvents events, void * data);

?

Copy link
Contributor Author

@kpschoedel kpschoedel May 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The tentative reason for the otherwise-vacuous base class is to have an easily-found place to document the SystemSocketWatcher interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, after further investigation, I do want to have a base class containing the file descriptor and active-event flags — essentially, changing the consumers' members from int mSocket; SocketEvents mPendingIO; SystemSocketWatcher mWatcher; as here, to WatchableSocket mSocket.

@gerickson
Copy link
Contributor

@mspang and @msandstedt both raise good points here.

Ideally, I can have a single-threaded, simple application with multiple "sources" on the main select loop. CHIP should be one potential integration source in such an application. Perhaps Avahi has some inspiring APIs in this regard in terms of how Avahi can be added as such an integration source. It's been a decade-plus since I've looked at that code; however, I think it amounted to being able to import/export the descriptors Avahi uses for its passive/active sockets and being able to patch those in/out of the main select loop with appropriate callbacks when those particular descriptors have "work" to do.

IIRC, Apple's mDNS/DNS-SD CFNetworkService code works similarly but in a CFRunLoop-centric way (which is just, at its core, a select loop as hand-waved above). There's a main application CFRunLoop and CFNetworkService is patched in as a source of work on that run loop. IIRC, there was/is no need to maintain a separate mDNS/DNS-SD work thread and manage complexities around multiple threads.

If the CHIP stack had the ability, on POSIX-like systems, to export/import descriptors similarly, then it would be possible to have a CFRunLoop adapter, a GLib adapter, etc. for the stack to integrate with each of those run loop types.

@kpschoedel kpschoedel closed this May 7, 2021
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Jun 22, 2021
Followups from project-chip#6561 Generalize socket-based event loop

#### Change overview

* mDNS: Convert `platform/Linux/MdnsImpl`; remove Darwin stubs.
* Change `mCallbackData` type to `intptr_t` (review feedback).
* Comment for `System::WakeEvent` (this is minimal since it's
  likely to change soon for issue project-chip#7725).

Fixes project-chip#7758 _Convert MDNS to WatchableSocket._

#### Testing

Manual sanity check of mDNS using chip-device-ctrl on Linux.
Otherwise, no change to functionality is intended.
andy31415 pushed a commit that referenced this pull request Jun 23, 2021
* #### Problem

Followups from #6561 Generalize socket-based event loop

#### Change overview

* mDNS: Convert `platform/Linux/MdnsImpl`; remove Darwin stubs.
* Change `mCallbackData` type to `intptr_t` (review feedback).
* Comment for `System::WakeEvent` (this is minimal since it's
  likely to change soon for issue #7725).

Fixes #7758 _Convert MDNS to WatchableSocket._

#### Testing

Manual sanity check of mDNS using chip-device-ctrl on Linux.
Otherwise, no change to functionality is intended.

* review

* review
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 3, 2021
#### Problem

XXX

#### Change overview

XXX

socket events in project-chip#6561

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

`System::Timer` remains as an optional `Object`-pool implementation tool for the XXX

The intent is that the public `WatchableEventManager` interface will
become pure virtual methods of `System::Layer`, and the various versions
of `WatchableEventManager` will be its implementations.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing
How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 3, 2021
#### Problem

XXX

#### Change overview

XXX

socket events in project-chip#6561

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

`System::Timer` remains as an optional `Object`-pool implementation tool for the XXX

The intent is that the public `WatchableEventManager` interface will
become pure virtual methods of `System::Layer`, and the various versions
of `WatchableEventManager` will be its implementations.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing
How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 3, 2021
#### Problem

XXX

#### Change overview

XXX

socket events in project-chip#6561

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

`System::Timer` remains as an optional `Object`-pool implementation tool for the XXX

The intent is that the public `WatchableEventManager` interface will
become pure virtual methods of `System::Layer`, and the various versions
of `WatchableEventManager` will be its implementations.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing
How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 3, 2021
#### Problem

XXX

#### Change overview

XXX

socket events in project-chip#6561

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

`System::Timer` remains as an optional `Object`-pool implementation tool for the XXX

The intent is that the public `WatchableEventManager` interface will
become pure virtual methods of `System::Layer`, and the various versions
of `WatchableEventManager` will be its implementations.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing
How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 3, 2021
#### Problem

XXX

#### Change overview

XXX

socket events in project-chip#6561

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

`System::Timer` remains as an optional `Object`-pool implementation tool for the XXX

The intent is that the public `WatchableEventManager` interface will
become pure virtual methods of `System::Layer`, and the various versions
of `WatchableEventManager` will be its implementations.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing
How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 4, 2021
#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 4, 2021
#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 4, 2021
#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 4, 2021
#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 4, 2021
#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 4, 2021
#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 5, 2021
The event loop in JNI `IOThreadMain()` used to wait no more than ten
seconds on each iteration. This timeout was temporarily removed in
PR project-chip#6561.

#### Change overview

Add an explicit ten second timer.

Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

How was this tested? (at least one bullet point required)
* If unit tests were added, how do they cover this issue?
* If unit tests existed, how were they fixed/modified to prevent this in future?
* If new unit tests are not added, why not?
* If integration tests were added, how do they verify this change?
* If new integration tests are not added, why not?
* If manually tested, what platforms controller and device platforms were manually tested, and how?
* If no testing is required, why not?
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 5, 2021
The event loop in JNI `IOThreadMain()` used to wait no more than ten
seconds on each iteration. This timeout was temporarily removed in
PR project-chip#6561.

#### Change overview

Add an explicit ten second timer.

Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Passes Android workflow.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 5, 2021
#### Problem

The event loop in JNI `IOThreadMain()` used to wait no more than ten
seconds on each iteration. This timeout was temporarily removed in
PR project-chip#6561.

#### Change overview

Add an explicit timer.

Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Passes Android workflow.
woody-apple pushed a commit that referenced this pull request Aug 11, 2021
* Separate System::Layer and Timer into per-implementation files.

#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR #6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.

* rebase and regen zap

* Remove obsolete TODO.

* restyle

* remove leftover debug logging

* restyle

* convert outdated ChipError::FormatError()

* review

- add config flag CHIP_SYSTEM_CONFIG_USE_TIMER_POOL
- use std::lock_guard rather than inventing ScopedMutexLock
- rename mWatchableEvents and WatchableEvents()
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 11, 2021
#### Problem

Some TODOs left over from PR project-chip#6561.

#### Change overview

- Remove the temporary `PrepareEventsWithTimeout()`, and have the tests
  that used it use a timer instead.
- Remove obsolete TODOs.

Fixes project-chip#7760 _Some unit tests supply a timeout at low level_
Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Ran the affected tests.
@kpschoedel kpschoedel mentioned this pull request Aug 11, 2021
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 11, 2021
#### Problem

Some TODOs left over from PR project-chip#6561.

#### Change overview

- Remove the temporary `PrepareEventsWithTimeout()`, and have the tests
  that used it use a timer instead.
- Remove obsolete TODOs.

Fixes project-chip#7760 _Some unit tests supply a timeout at low level_
Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Ran the affected tests.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 13, 2021
#### Problem

Some TODOs left over from PR project-chip#6561.

#### Change overview

- Remove the temporary `PrepareEventsWithTimeout()`, and have the tests
  that used it use a timer instead.
- Remove obsolete TODOs.

Fixes project-chip#7760 _Some unit tests supply a timeout at low level_
Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Ran the affected tests.
kpschoedel added a commit to kpschoedel/connectedhomeip that referenced this pull request Aug 16, 2021
#### Problem

Some TODOs left over from PR project-chip#6561.

#### Change overview

- Remove the temporary `PrepareEventsWithTimeout()`, and have the tests
  that used it use a timer instead.
- Remove obsolete TODOs.

Fixes project-chip#7760 _Some unit tests supply a timeout at low level_
Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Ran the affected tests.
andy31415 pushed a commit that referenced this pull request Aug 17, 2021
* TODOs from PR #6561

#### Problem

Some TODOs left over from PR #6561.

#### Change overview

- Remove the temporary `PrepareEventsWithTimeout()`, and have the tests
  that used it use a timer instead.
- Remove obsolete TODOs.

Fixes #7760 _Some unit tests supply a timeout at low level_
Fixes #7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Ran the affected tests.

* fix kSleepTimeMilliseconds

* review
nikita-s-wrk pushed a commit to nikita-s-wrk/connectedhomeip that referenced this pull request Sep 23, 2021
* Generalize socket-based event loop

#### Problem

Socket event management is currently tied closely to select(2),
and does not integrate well with other event loops.

See issue project-chip#5556 _rework system layer event loop_

#### Change overview

The primary purpose of this change is to provide a clear interface for
monitoring socket events, that can be used both within the CHIP SDK
and by an application using the SDK, and can be implemented either
inside or outside the SDK. Functionality does not change.

* Defines an interface, in `system/SystemSockets.h`.
* Converts most existing uses of socket event monitoring (except mDNS,
  to be done as a followup).
* Converts the existing select(2)-based event management into an
  implementation of the new interface.
* Adds a second implementation of the interface, using libevent,
  to verify that the interface is general enough.

#### Testing

* Converted the applicable unit tests from select(2) to this interface,
  and ran them with both the select and libevent implementations.
  (CI remains select-only for now.)
* Integration tests involving socket-based platforms exercise this code
  and confirm no change to functionality.
* Manual verification of controller/device communication

* Clarify SocketEventFlags error vs exceptional condition

* restyle

* fixes for CHIP_SYSTEM_CONFIG_USE_DISPATCH merge

* restyle

* rename System::SystemWakeEvent to System::WakeEvent
nikita-s-wrk pushed a commit to nikita-s-wrk/connectedhomeip that referenced this pull request Sep 23, 2021
…roject-chip#7799)

* #### Problem

Followups from project-chip#6561 Generalize socket-based event loop

#### Change overview

* mDNS: Convert `platform/Linux/MdnsImpl`; remove Darwin stubs.
* Change `mCallbackData` type to `intptr_t` (review feedback).
* Comment for `System::WakeEvent` (this is minimal since it's
  likely to change soon for issue project-chip#7725).

Fixes project-chip#7758 _Convert MDNS to WatchableSocket._

#### Testing

Manual sanity check of mDNS using chip-device-ctrl on Linux.
Otherwise, no change to functionality is intended.

* review

* review
nikita-s-wrk pushed a commit to nikita-s-wrk/connectedhomeip that referenced this pull request Sep 23, 2021
…ect-chip#8800)

* Separate System::Layer and Timer into per-implementation files.

#### Problem

Various implementations of System::Layer are provided by `#if` sections,
which prevents mock versions for testing and out-of-tree platform
implementations.

#### Change overview

Split platform `#if` sections of `System::Layer` and `System::Timer`
into separate `WatchableEventManager` implementations.

This change does for timers what PR project-chip#6561 did for socket I/O events.
The intent is that the public `WatchableEventManager` interface here
will become pure virtual methods of `System::Layer`, and the various
versions of `WatchableEventManager` will become its implementations.

`System::Timer` remains as an `Object`-pool based utility class for
implementing the Timer API.

- Make `Timer` list not LwIP-specific, mutex it, and use it in preference
  to iterating through the entire pool.
- Move `IsEarlier` from `Timer` to `Clock`.
- Fix dual definitions of `Clock::Platform` functions on Linux.

#### Testing

Relying on CI in general, since no externally visible functionality
should have changed. Sanity-checked the libevent implementation (not in
CI) using chip-tool.

* rebase and regen zap

* Remove obsolete TODO.

* restyle

* remove leftover debug logging

* restyle

* convert outdated ChipError::FormatError()

* review

- add config flag CHIP_SYSTEM_CONFIG_USE_TIMER_POOL
- use std::lock_guard rather than inventing ScopedMutexLock
- rename mWatchableEvents and WatchableEvents()
nikita-s-wrk pushed a commit to nikita-s-wrk/connectedhomeip that referenced this pull request Sep 23, 2021
* TODOs from PR project-chip#6561

#### Problem

Some TODOs left over from PR project-chip#6561.

#### Change overview

- Remove the temporary `PrepareEventsWithTimeout()`, and have the tests
  that used it use a timer instead.
- Remove obsolete TODOs.

Fixes project-chip#7760 _Some unit tests supply a timeout at low level_
Fixes project-chip#7756 _add a timer for sleepTime.tv_sec = 10; sleepTime.tv_usec = 0;_

#### Testing

Ran the affected tests.

* fix kSleepTimeMilliseconds

* review
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants