-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Followups from #6561 Generalize socket-based event loop #7799
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,13 +25,15 @@ | |
|
||
#include <netinet/in.h> | ||
|
||
#include <platform/internal/CHIPDeviceLayerInternal.h> | ||
#include <support/CHIPMem.h> | ||
#include <support/CHIPMemString.h> | ||
#include <support/CodeUtils.h> | ||
|
||
using chip::Mdns::kMdnsTypeMaxSize; | ||
using chip::Mdns::MdnsServiceProtocol; | ||
using chip::Mdns::TextEntry; | ||
using chip::System::SocketEvents; | ||
using std::chrono::duration_cast; | ||
using std::chrono::microseconds; | ||
using std::chrono::seconds; | ||
|
@@ -79,6 +81,19 @@ chip::Inet::IPAddressType ToAddressType(AvahiProtocol protocol) | |
return type; | ||
} | ||
|
||
AvahiWatchEvent ToAvahiWatchEvent(SocketEvents events) | ||
{ | ||
return static_cast<AvahiWatchEvent>((events.Has(chip::System::SocketEventFlags::kRead) ? AVAHI_WATCH_IN : 0) | | ||
(events.Has(chip::System::SocketEventFlags::kWrite) ? AVAHI_WATCH_OUT : 0) | | ||
(events.Has(chip::System::SocketEventFlags::kError) ? AVAHI_WATCH_ERR : 0)); | ||
} | ||
|
||
void AvahiWatchCallbackTrampoline(chip::System::WatchableSocket & socket) | ||
{ | ||
AvahiWatch * const watch = reinterpret_cast<AvahiWatch *>(socket.GetCallbackData()); | ||
watch->mCallback(watch, socket.GetFD(), ToAvahiWatchEvent(socket.GetPendingEvents()), watch->mContext); | ||
} | ||
|
||
CHIP_ERROR MakeAvahiStringListFromTextEntries(TextEntry * entries, size_t size, AvahiStringList ** strListOut) | ||
{ | ||
*strListOut = avahi_string_list_new(nullptr, nullptr); | ||
|
@@ -133,6 +148,8 @@ Poller::Poller() | |
mAvahiPoller.timeout_new = TimeoutNew; | ||
mAvahiPoller.timeout_update = TimeoutUpdate; | ||
mAvahiPoller.timeout_free = TimeoutFree; | ||
|
||
mWatchableEvents = &DeviceLayer::SystemLayer.WatchableEvents(); | ||
} | ||
|
||
AvahiWatch * Poller::WatchNew(const struct AvahiPoll * poller, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, | ||
|
@@ -145,19 +162,43 @@ AvahiWatch * Poller::WatchNew(int fd, AvahiWatchEvent event, AvahiWatchCallback | |
{ | ||
VerifyOrDie(callback != nullptr && fd >= 0); | ||
|
||
mWatches.emplace_back(new AvahiWatch{ fd, event, 0, callback, context, this }); | ||
auto watch = std::make_unique<AvahiWatch>(); | ||
watch->mSocket.Init(*mWatchableEvents) | ||
.Attach(fd) | ||
.SetCallback(AvahiWatchCallbackTrampoline, reinterpret_cast<intptr_t>(watch.get())) | ||
.RequestCallbackOnPendingRead(event & AVAHI_WATCH_IN) | ||
.RequestCallbackOnPendingWrite(event & AVAHI_WATCH_OUT); | ||
watch->mCallback = callback; | ||
watch->mContext = context; | ||
watch->mPoller = this; | ||
mWatches.emplace_back(std::move(watch)); | ||
|
||
return mWatches.back().get(); | ||
} | ||
|
||
void Poller::WatchUpdate(AvahiWatch * watch, AvahiWatchEvent event) | ||
{ | ||
watch->mWatchEvents = event; | ||
if (event & AVAHI_WATCH_IN) | ||
{ | ||
watch->mSocket.RequestCallbackOnPendingRead(); | ||
} | ||
else | ||
{ | ||
watch->mSocket.ClearCallbackOnPendingRead(); | ||
} | ||
if (event & AVAHI_WATCH_OUT) | ||
{ | ||
watch->mSocket.RequestCallbackOnPendingWrite(); | ||
} | ||
else | ||
{ | ||
watch->mSocket.ClearCallbackOnPendingWrite(); | ||
} | ||
} | ||
|
||
AvahiWatchEvent Poller::WatchGetEvents(AvahiWatch * watch) | ||
{ | ||
return static_cast<AvahiWatchEvent>(watch->mHappenedEvents); | ||
return ToAvahiWatchEvent(watch->mSocket.GetPendingEvents()); | ||
} | ||
|
||
void Poller::WatchFree(AvahiWatch * watch) | ||
|
@@ -167,6 +208,7 @@ void Poller::WatchFree(AvahiWatch * watch) | |
|
||
void Poller::WatchFree(AvahiWatch & watch) | ||
{ | ||
(void) watch.mSocket.ReleaseFD(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a confused by this. WatchableSocket is normally expected to own the fd but not in the case of avahi? If WatchableSocket is owning, why doesn't it close in its destructor? If WatchableSocket is non-owning, why does it close the file descriptor in Close()? If WatchableSocket non-owning but Close() is just a helper for release-and-close, should "release" call WatchableSocket::OnClose which does the actual detach-from-WatchableEventManager? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right. In the other cases (Inet and System::WakeEvent) the WatchableSocket effectively owns the fd, and replaces the fd from the point of view of the holder. In the Avahi case, Avahi itself owns the fd and lends it via
For the normal (Inet) case, it's contained inside an IPEndPointBasis which is not constructible or destructible. It's contained in order to avoid requiring separate allocation. It may be worth revisiting that if/when the System/Inet virtualization and pool allocation improvements happen.
Convenience for the common case.
Yes, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Having a non-owning watcher separate from fd-owner makes the most sense to me and would fit well with avahi but understood there are other constraints here.
Ahh, the pool should really run destructors on slots released back to it :(
Ah, I see that it does I was just confused by the name. Rename sounds good. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'll take a look at this when I do the remaining test and timer TODOs, which likely will be together with #7725. I don't know that it will make much difference; since we don't have weak fds, a watcher must be informed before a file is closed.
Ack, added to my TODO list. |
||
mWatches.erase(std::remove_if(mWatches.begin(), mWatches.end(), | ||
[&watch](const std::unique_ptr<AvahiWatch> & aValue) { return aValue.get() == &watch; }), | ||
mWatches.end()); | ||
|
@@ -226,38 +268,10 @@ void Poller::TimeoutFree(AvahiTimeout & timer) | |
mTimers.end()); | ||
} | ||
|
||
void Poller::UpdateFdSet(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & aMaxFd, timeval & timeout) | ||
void Poller::GetTimeout(timeval & timeout) | ||
{ | ||
microseconds timeoutVal = seconds(timeout.tv_sec) + microseconds(timeout.tv_usec); | ||
|
||
for (auto && watch : mWatches) | ||
{ | ||
int fd = watch->mFd; | ||
AvahiWatchEvent events = watch->mWatchEvents; | ||
|
||
if (AVAHI_WATCH_IN & events) | ||
{ | ||
FD_SET(fd, &readFdSet); | ||
} | ||
|
||
if (AVAHI_WATCH_OUT & events) | ||
{ | ||
FD_SET(fd, &writeFdSet); | ||
} | ||
|
||
if (AVAHI_WATCH_ERR & events) | ||
{ | ||
FD_SET(fd, &errorFdSet); | ||
} | ||
|
||
if (aMaxFd < fd) | ||
{ | ||
aMaxFd = fd; | ||
} | ||
|
||
watch->mHappenedEvents = 0; | ||
} | ||
|
||
for (auto && timer : mTimers) | ||
{ | ||
steady_clock::time_point absTimeout = timer->mAbsTimeout; | ||
|
@@ -282,38 +296,10 @@ void Poller::UpdateFdSet(fd_set & readFdSet, fd_set & writeFdSet, fd_set & error | |
timeout.tv_usec = static_cast<uint64_t>(timeoutVal.count()) % kUsPerSec; | ||
} | ||
|
||
void Poller::Process(const fd_set & readFdSet, const fd_set & writeFdSet, const fd_set & errorFdSet) | ||
void Poller::HandleTimeout() | ||
{ | ||
steady_clock::time_point now = steady_clock::now(); | ||
|
||
for (auto && watch : mWatches) | ||
{ | ||
int fd = watch->mFd; | ||
AvahiWatchEvent events = watch->mWatchEvents; | ||
|
||
watch->mHappenedEvents = 0; | ||
|
||
if ((AVAHI_WATCH_IN & events) && FD_ISSET(fd, &readFdSet)) | ||
{ | ||
watch->mHappenedEvents |= AVAHI_WATCH_IN; | ||
} | ||
|
||
if ((AVAHI_WATCH_OUT & events) && FD_ISSET(fd, &writeFdSet)) | ||
{ | ||
watch->mHappenedEvents |= AVAHI_WATCH_OUT; | ||
} | ||
|
||
if ((AVAHI_WATCH_ERR & events) && FD_ISSET(fd, &errorFdSet)) | ||
{ | ||
watch->mHappenedEvents |= AVAHI_WATCH_ERR; | ||
} | ||
|
||
if (watch->mHappenedEvents) | ||
{ | ||
watch->mCallback(watch.get(), watch->mFd, static_cast<AvahiWatchEvent>(watch->mHappenedEvents), watch->mContext); | ||
} | ||
} | ||
|
||
for (auto && timer : mTimers) | ||
{ | ||
if (!timer->mEnabled) | ||
|
@@ -753,14 +739,14 @@ MdnsAvahi::~MdnsAvahi() | |
} | ||
} | ||
|
||
void UpdateMdnsDataset(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout) | ||
void GetMdnsTimeout(timeval & timeout) | ||
{ | ||
MdnsAvahi::GetInstance().GetPoller().UpdateFdSet(readFdSet, writeFdSet, errorFdSet, maxFd, timeout); | ||
MdnsAvahi::GetInstance().GetPoller().GetTimeout(timeout); | ||
} | ||
|
||
void ProcessMdns(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet) | ||
void HandleMdnsTimeout() | ||
{ | ||
MdnsAvahi::GetInstance().GetPoller().Process(readFdSet, writeFdSet, errorFdSet); | ||
MdnsAvahi::GetInstance().GetPoller().HandleTimeout(); | ||
} | ||
|
||
CHIP_ERROR ChipMdnsInit(MdnsAsyncReturnCallback initCallback, MdnsAsyncReturnCallback errorCallback, void * context) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requires a more casts and stronger casts, I wonder if it is worth it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a request in the previous review, so you and Boris can fight it out :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a suggestion; Boris said he was OK either way. Above was just a question. Ultimately I think it is up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, given what this diff looks like and that we have no non-pointer use cases for this closure, we should probably leave it as
void*
for now. If we ever end up with non-pointer use cases, we can think about how to be best address those then...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added to my TODO list.