Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions tests/monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ TEST_CASE("monitor init event count", "[monitor]")
CHECK(monitor.total == expected_event_count);
}

#if __cplusplus >= 202002L
static_assert(requires {
[](){
mock_monitor_t monitor;
monitor.check_event();
monitor.check_event(0);
monitor.check_event(100);
monitor.check_event(std::chrono::milliseconds{0});
monitor.check_event(std::chrono::milliseconds{100});
monitor.check_event(std::chrono::microseconds{100});
monitor.check_event(std::chrono::nanoseconds{100});
monitor.check_event(std::chrono::seconds{100});
monitor.check_event(std::chrono::minutes{100});
monitor.check_event(std::chrono::hours{100});
}();
});
#endif

TEST_CASE("monitor init abort", "[monitor]")
{
class mock_monitor : public mock_monitor_t
Expand Down
2 changes: 2 additions & 0 deletions tests/poller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ TEST_CASE("poller wait with no handlers throws", "[poller]")
/// \todo the actual error code should be checked
CHECK_THROWS_AS(poller.wait_all(events, std::chrono::milliseconds{10}),
zmq::error_t);
CHECK_THROWS_AS(poller.wait_all(events, std::chrono::microseconds{10000}),
zmq::error_t);
}

#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3)
Expand Down
12 changes: 11 additions & 1 deletion tests/timers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ TEST_CASE("timers add/execute", "[timers]")
bool handler_ran = false;
timers.add(4ms, [](auto, void *arg) { *(bool *) arg = true; }, &handler_ran);
CHECK(timers.timeout().has_value());
// Check any std::chrono duration support
std::chrono::microseconds _ = timers.timeout().value();
CHECK(!handler_ran);
std::this_thread::sleep_for(10ms);
timers.execute();
CHECK(handler_ran);
// Check any std::chrono duration support
auto id2 =
timers.add(std::chrono::seconds{4}, [](auto, void *arg) { *(bool *) arg = true; }, &handler_ran);
}

TEST_CASE("timers add/cancel", "[timers]")
Expand Down Expand Up @@ -59,6 +64,12 @@ TEST_CASE("timers set_interval", "[timers]")
std::this_thread::sleep_for(10ms);
timers.execute();
CHECK(handler_ran);
handler_ran = false;
// Check any std::chrono duration support
timers.set_interval(id, std::chrono::microseconds{1000});
std::this_thread::sleep_for(3ms);
timers.execute();
CHECK(handler_ran);
}

TEST_CASE("timers reset", "[timers]")
Expand All @@ -74,7 +85,6 @@ TEST_CASE("timers reset", "[timers]")
timers.reset(id);
CHECK(timers.timeout().has_value());
CHECK(!handler_ran);

}

#endif // defined(ZMQ_CPP11) && defined(ZMQ_HAVE_TIMERS)
52 changes: 34 additions & 18 deletions zmq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,16 +351,19 @@ inline int poll(std::vector<zmq_pollitem_t> const &items, long timeout_ = -1)
return detail::poll(const_cast<zmq_pollitem_t *>(items.data()), items.size(), timeout_);
}

inline int
poll(zmq_pollitem_t *items, size_t nitems, std::chrono::milliseconds timeout = std::chrono::milliseconds{-1})
template<typename Duration = std::chrono::milliseconds>
int
poll(zmq_pollitem_t *items, size_t nitems, Duration timeout = std::chrono::milliseconds{-1})
{
return detail::poll(items, nitems, static_cast<long>(timeout.count()));
auto timeout_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
return detail::poll(items, nitems, static_cast<long>(timeout_ms.count()));
Copy link
Member

Choose a reason for hiding this comment

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

One concern is that for poll and poller, -1 millisecond is a special value that may need special handling. E.g. does -1s or -1ns do the right thing?

If the value of timeout is -1, zmq_poll() shall block indefinitely until a requested event has occurred on at least one zmq_pollitem_t.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Negative duration work:

#include <print>
#include <optional>
#include <chrono>

int main()
{
    std::chrono::milliseconds ms{-1};
    std::println("{}", ms);
    std::println("{}", ms.count());

    std::chrono::nanoseconds ns{-1};
    std::println("{}", ns);
    std::println("{}", ns.count());
    return 0;
}

Output:

$ g++ -std=c++23 temp.cpp && ./a.out
-1ms
-1
-1ns
-1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With c++17:

int main()
{
    std::chrono::milliseconds ms{-1};
    // std::cout << ms << '\n';
    std::cout << ms.count() << '\n';

    std::chrono::nanoseconds ns{-1};
    // std::cout << ns << '\n';
    std::cout << ns.count() << '\n';
    return 0;
}

Output:

$ g++ -std=c++17 temp.cpp && ./a.out
-1
-1

Copy link
Member

Choose a reason for hiding this comment

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

Yes, but you cast the input Duration to milliseconds then pass that to libzmq.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, casting from -1ns to ms give 0ms, I'll change that

}

inline int poll(std::vector<zmq_pollitem_t> &items,
std::chrono::milliseconds timeout = std::chrono::milliseconds{-1})
template<typename Duration = std::chrono::milliseconds>
int poll(std::vector<zmq_pollitem_t> &items, Duration timeout = std::chrono::milliseconds{-1})
{
return detail::poll(items.data(), items.size(), static_cast<long>(timeout.count()));
auto timeout_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
return detail::poll(items.data(), items.size(), static_cast<long>(timeout_ms.count()));
}

ZMQ_DEPRECATED("from 4.3.1, use poll taking std::chrono::duration instead of long")
Expand All @@ -369,11 +372,11 @@ inline int poll(std::vector<zmq_pollitem_t> &items, long timeout_)
return detail::poll(items.data(), items.size(), timeout_);
}

template<std::size_t SIZE>
inline int poll(std::array<zmq_pollitem_t, SIZE> &items,
std::chrono::milliseconds timeout = std::chrono::milliseconds{-1})
template<std::size_t SIZE, typename Duration>
int poll(std::array<zmq_pollitem_t, SIZE> &items, Duration timeout = std::chrono::milliseconds{-1})
{
return detail::poll(items.data(), items.size(), static_cast<long>(timeout.count()));
auto timeout_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
return detail::poll(items.data(), items.size(), static_cast<long>(timeout_ms.count()));
}
#endif

Expand Down Expand Up @@ -2366,6 +2369,14 @@ class monitor_t
on_monitor_started();
}

#ifdef ZMQ_CPP11
template<typename Duration = std::chrono::milliseconds>
bool check_event(Duration timeout = std::chrono::milliseconds{0})
Copy link
Member

Choose a reason for hiding this comment

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

check_event() is ambiguous

{
return check_event(static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()));
}
#endif

bool check_event(int timeout = 0)
{
assert(_monitor_socket);
Expand Down Expand Up @@ -2725,17 +2736,17 @@ template<typename T = no_user_data> class poller_t
}
}

template <typename Sequence>
template <typename Sequence, typename Duration = std::chrono::milliseconds>
size_t wait_all(Sequence &poller_events,
const std::chrono::milliseconds timeout)
const Duration timeout)
{
static_assert(std::is_same<typename Sequence::value_type, event_type>::value,
"Sequence::value_type must be of poller_t::event_type");
int rc = zmq_poller_wait_all(
poller_ptr.get(),
reinterpret_cast<zmq_poller_event_t *>(poller_events.data()),
static_cast<int>(poller_events.size()),
static_cast<long>(timeout.count()));
static_cast<long>(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()));
if (rc > 0)
return static_cast<size_t>(rc);

Expand Down Expand Up @@ -2824,9 +2835,11 @@ class timers
ZMQ_ASSERT(rc == 0);
}

id_t add(std::chrono::milliseconds interval, zmq_timer_fn handler, void *arg)
template<typename Duration = std::chrono::milliseconds>
id_t add(Duration interval, zmq_timer_fn handler, void *arg)
{
id_t timer_id = zmq_timers_add(_timers, interval.count(), handler, arg);
auto interval_ms = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
id_t timer_id = zmq_timers_add(_timers, interval_ms.count(), handler, arg);
if (timer_id == -1)
throw zmq::error_t();
return timer_id;
Expand All @@ -2839,9 +2852,11 @@ class timers
throw zmq::error_t();
}

void set_interval(id_t timer_id, std::chrono::milliseconds interval)
template<typename Duration = std::chrono::milliseconds>
void set_interval(id_t timer_id, Duration interval)
{
int rc = zmq_timers_set_interval(_timers, timer_id, interval.count());
auto interval_ms = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
int rc = zmq_timers_set_interval(_timers, timer_id, interval_ms.count());
if (rc == -1)
throw zmq::error_t();
}
Expand All @@ -2853,12 +2868,13 @@ class timers
throw zmq::error_t();
}

template<typename Duration = std::chrono::milliseconds>
timeout_result_t timeout() const
{
int timeout = zmq_timers_timeout(_timers);
if (timeout == -1)
return timeout_result_t{};
return std::chrono::milliseconds{timeout};
return std::chrono::duration_cast<Duration>(std::chrono::milliseconds{timeout});
}

void execute()
Expand Down
6 changes: 4 additions & 2 deletions zmq_addon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,8 @@ class active_poller_t
base_poller.modify(fd, events);
}

size_t wait(std::chrono::milliseconds timeout)
template<typename Duration = std::chrono::milliseconds>
size_t wait(Duration timeout)
{
if (need_rebuild) {
poller_events.resize(handlers.size());
Expand All @@ -816,7 +817,8 @@ class active_poller_t
}
need_rebuild = false;
}
const auto count = base_poller.wait_all(poller_events, timeout);
auto timeout_ms = std::chrono::duration_cast<Duration>(timeout);
const auto count = base_poller.wait_all(poller_events, timeout_ms);
std::for_each(poller_events.begin(),
poller_events.begin() + static_cast<ptrdiff_t>(count),
[](decltype(base_poller)::event_type &event) {
Expand Down