Implement eloop for Fuchsia. Use the mtl message loop to implement hostap's eloop interface. This implementation only includes registering and cancelling timeouts. The other features are not necessary for wpa_supplicant. Accidentally submitted and reverted. Previous-Change-Id: I7260f15547d28133d33aaa9467b0eb6e920ee79d Change-Id: I34f01e70da8e0fc184b84b2dccff367b88c15ae2
diff --git a/src/utils/eloop_fuchsia.cc b/src/utils/eloop_fuchsia.cc index a938f26..59baefe 100644 --- a/src/utils/eloop_fuchsia.cc +++ b/src/utils/eloop_fuchsia.cc
@@ -3,13 +3,70 @@ // See README for more details. extern "C" { -// Hostap code requires this be the first file included +// Hostap does not include "includes.h" in their header files, though it is +// required. +// So this must be included before "eloop.h" in order to compile. #include "includes.h" #include "eloop.h" -} // extern "C" +} // extern "C" -extern "C" int eloop_init() { return 0; } +#include <stdint.h> + +#include <algorithm> +#include <list> +#include <memory> + +#include "lib/ftl/logging.h" +#include "lib/ftl/time/time_delta.h" +#include "lib/ftl/time/time_point.h" +#include "lib/mtl/tasks/message_loop.h" + +extern "C" { +#include "os.h" +} // extern "C" + +constexpr int64_t kUsecPerSec = 1000000L; + +struct EloopTimeout { + int id; + eloop_timeout_handler handler; + void *eloop_data; + void *user_data; + ftl::TimeDelta delay; + ftl::TimePoint approx_end_time; +}; + +static mtl::MessageLoop *loop = nullptr; +static std::list<EloopTimeout> *timeouts = nullptr; +static int current_registration_id = 0; + +static std::list<EloopTimeout>::iterator FindTimeout( + eloop_timeout_handler handler, void *eloop_data, void *user_data) { + return std::find_if(timeouts->begin(), timeouts->end(), + [handler, eloop_data, user_data](EloopTimeout timeout) { + return timeout.handler == handler && + timeout.eloop_data == eloop_data && + timeout.user_data == user_data; + }); +} + +static ftl::TimeDelta TimeDelta(unsigned int secs, unsigned int usecs) { + return ftl::TimeDelta::FromSeconds(secs) + + ftl::TimeDelta::FromMicroseconds(usecs); +} + +static ftl::TimeDelta RemainingTimeDelta(ftl::TimePoint end_time) { + ftl::TimePoint now = ftl::TimePoint::Now(); + return end_time > now ? ftl::TimeDelta::Zero() : end_time - now; +} + +extern "C" int eloop_init() { + FTL_CHECK(loop == nullptr); + loop = new mtl::MessageLoop(); + timeouts = new std::list<EloopTimeout>(); + return 0; +} extern "C" int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) { @@ -46,43 +103,103 @@ extern "C" int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data) { - // TODO(alangardner): Implement - return -1; + ftl::TimeDelta delay = TimeDelta(secs, usecs); + int registration_id = ++current_registration_id; + EloopTimeout timeout = {registration_id, handler, + eloop_data, user_data, + delay, ftl::TimePoint::Now() + delay}; + timeouts->push_back(timeout); + loop->task_runner()->PostDelayedTask( + [registration_id] { + for (auto timeout_iter = timeouts->begin(); + timeout_iter != timeouts->end(); ++timeout_iter) { + if (registration_id == timeout_iter->id) { + timeout_iter->handler(timeout_iter->eloop_data, + timeout_iter->user_data); + timeouts->erase(timeout_iter); + break; + } + } + }, + delay); + return 0; } extern "C" int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data) { - // TODO(alangardner): Implement - return -1; + size_t old_size = std::distance(timeouts->begin(), timeouts->end()); + timeouts->erase( + std::remove_if(timeouts->begin(), timeouts->end(), + [handler, eloop_data, user_data](EloopTimeout timeout) { + return timeout.handler == handler && + (timeout.eloop_data == eloop_data || + eloop_data == ELOOP_ALL_CTX) && + (timeout.user_data == user_data || + user_data == ELOOP_ALL_CTX); + }), + timeouts->end()); + size_t new_size = std::distance(timeouts->begin(), timeouts->end()); + return old_size - new_size; } extern "C" int eloop_cancel_timeout_one(eloop_timeout_handler handler, void *eloop_data, void *user_data, struct os_reltime *remaining) { - // TODO(alangardner): Implement - return -1; + std::list<EloopTimeout>::iterator timeout = + FindTimeout(handler, eloop_data, user_data); + if (timeout == timeouts->end()) { + return 0; + } else { + ftl::TimeDelta remaining_delta = + RemainingTimeDelta(timeout->approx_end_time); + remaining->sec = remaining_delta.ToSeconds(); + remaining->usec = remaining_delta.ToMicroseconds() % kUsecPerSec; + timeouts->erase(timeout); + return 1; + } } extern "C" int eloop_is_timeout_registered(eloop_timeout_handler handler, void *eloop_data, void *user_data) { - // TODO(alangardner): Implement - return -1; + return FindTimeout(handler, eloop_data, user_data) == timeouts->end() ? 0 : 1; } extern "C" int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data) { - // TODO(alangardner): Implement - return -1; + std::list<EloopTimeout>::iterator timeout = + FindTimeout(handler, eloop_data, user_data); + if (timeout == timeouts->end()) { + return -1; + } else if (RemainingTimeDelta(timeout->approx_end_time) > + TimeDelta(req_secs, req_usecs)) { + timeouts->erase(timeout); + // Note: Current implementation of register cannot fail. + eloop_register_timeout(req_secs, req_usecs, handler, eloop_data, user_data); + return 1; + } else { + return 0; + } } extern "C" int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data) { - // TODO(alangardner): Implement - return -1; + std::list<EloopTimeout>::iterator timeout = + FindTimeout(handler, eloop_data, user_data); + if (timeout == timeouts->end()) { + return -1; + } else if (RemainingTimeDelta(timeout->approx_end_time) < + TimeDelta(req_secs, req_usecs)) { + timeouts->erase(timeout); + // Note: Current implementation of register cannot fail. + eloop_register_timeout(req_secs, req_usecs, handler, eloop_data, user_data); + return 1; + } else { + return 0; + } } extern "C" int eloop_register_signal(int sig, eloop_signal_handler handler, @@ -104,21 +221,24 @@ } extern "C" void eloop_run() { - // TODO(alangardner): Implement + FTL_CHECK(loop); + loop->Run(); } extern "C" void eloop_terminate() { - // TODO(alangardner): Implement + FTL_CHECK(loop); + loop->QuitNow(); } extern "C" void eloop_destroy() { - // TODO(alangardner): Implement + FTL_CHECK(loop); + loop->QuitNow(); + delete loop; + loop = nullptr; + delete timeouts; } -extern "C" int eloop_terminated() { - // TODO(alangardner): Implement - return 1; -} +extern "C" int eloop_terminated() { return loop ? 0 : 1; } extern "C" void eloop_wait_for_read_sock(int sock) { // Not implemented.
diff --git a/wpa_supplicant/BUILD.gn b/wpa_supplicant/BUILD.gn index b28e87f..1eb68e3 100644 --- a/wpa_supplicant/BUILD.gn +++ b/wpa_supplicant/BUILD.gn
@@ -94,4 +94,10 @@ ] configs += [ ":wpa_supplicant_private" ] + + deps = [ + "//lib/ftl", + "//lib/mtl", + "//mojo/system", + ] }