{
struct event_base *base = ev->ev_base;
int res = 0;
+ int notify = 0;
event_debug((
"event_add: event: %p, %s%s%scall %p",
res = evmap_signal_add(base, ev->ev_fd, ev);
if (res != -1)
event_queue_insert(base, ev, EVLIST_INSERTED);
+ if (res == 1) {
+ /* evmap says we need to notify the main thread. */
+ notify = 1;
+ res = 0;
+ }
}
/*
* we already reserved memory above for the case where we
* are not replacing an exisiting timeout.
*/
- if (ev->ev_flags & EVLIST_TIMEOUT)
+ if (ev->ev_flags & EVLIST_TIMEOUT) {
+ if (min_heap_elt_is_top(ev))
+ notify = 1;
event_queue_remove(base, ev, EVLIST_TIMEOUT);
+ }
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
(int)tv->tv_sec, ev->ev_callback));
event_queue_insert(base, ev, EVLIST_TIMEOUT);
+ if (min_heap_elt_is_top(ev)) {
+ /* The earliest timeout is now earlier than it was
+ * before: we will need to tell the main thread to
+ * wake up earlier than it would otherwise. */
+ notify = 1;
+ }
}
/* if we are not in the right thread, we need to wake up the loop */
- if (res != -1 && !EVBASE_IN_THREAD(base))
+ if (res != -1 && notify && !EVBASE_IN_THREAD(base))
evthread_notify_base(base);
return (res);
event_del_internal(struct event *ev)
{
struct event_base *base;
- int res = 0;
+ int res = 0, notify = 0;
int need_cur_lock;
event_debug(("event_del: %p, callback %p",
}
}
- if (ev->ev_flags & EVLIST_TIMEOUT)
+ if (ev->ev_flags & EVLIST_TIMEOUT) {
+ /* NOTE: We never need to notify the main thread because of a
+ * deleted timeout event: all that could happen if we don't is
+ * that the dispatch loop might wake up too early. But the
+ * point of notifying the main thread _is_ to wake up the
+ * dispatch loop early anyway, so we wouldn't gain anything by
+ * doing it.
+ */
event_queue_remove(base, ev, EVLIST_TIMEOUT);
+ }
if (ev->ev_flags & EVLIST_ACTIVE)
event_queue_remove(base, ev, EVLIST_ACTIVE);
res = evmap_io_del(base, ev->ev_fd, ev);
else
res = evmap_signal_del(base, ev->ev_fd, ev);
+ if (res == 1) {
+ /* evmap says we need to notify the main thread. */
+ notify = 1;
+ res = 0;
+ }
}
/* if we are not in the right thread, we need to wake up the loop */
- if (res != -1 && !EVBASE_IN_THREAD(base))
+ if (res != -1 && notify && !EVBASE_IN_THREAD(base))
evthread_notify_base(base);
if (need_cur_lock)
}
+/* return -1 on error, 0 on success if nothing changed in the event backend,
+ * and 1 on success if something did. */
int
evmap_io_add(struct event_base *base, int fd, struct event *ev)
{
const struct eventop *evsel = base->evsel;
struct event_io_map *io = &base->io;
struct evmap_io *ctx = NULL;
- int nread, nwrite;
+ int nread, nwrite, retval = 0;
short res = 0, old = 0;
assert(fd == ev->ev_fd); /*XXX(nickm) always true? */
if (evsel->add(base, ev->ev_fd,
old, (ev->ev_events & EV_ET) | res, extra) == -1)
return (-1);
+ retval = 1;
}
ctx->nread = nread;
ctx->nwrite = nwrite;
TAILQ_INSERT_TAIL(&ctx->events, ev, ev_io_next);
- return (0);
+ return (retval);
}
+/* return -1 on error, 0 on success if nothing changed in the event backend,
+ * and 1 on success if something did. */
int
evmap_io_del(struct event_base *base, int fd, struct event *ev)
{
const struct eventop *evsel = base->evsel;
struct event_io_map *io = &base->io;
struct evmap_io *ctx;
- int nread, nwrite;
+ int nread, nwrite, retval = 0;
short res = 0, old = 0;
if (fd < 0)
void *extra = ((char*)ctx) + sizeof(struct evmap_io);
if (evsel->del(base, ev->ev_fd, old, res, extra) == -1)
return (-1);
+ retval = 1;
}
ctx->nread = nread;
ctx->nwrite = nwrite;
TAILQ_REMOVE(&ctx->events, ev, ev_io_next);
- return (0);
+ return (retval);
}
void
TAILQ_INSERT_TAIL(&ctx->events, ev, ev_signal_next);
- return (0);
+ return (1);
}
int
TAILQ_REMOVE(&ctx->events, ev, ev_signal_next);
- return (0);
+ return (1);
}
void
static inline void min_heap_ctor(min_heap_t* s);
static inline void min_heap_dtor(min_heap_t* s);
static inline void min_heap_elem_init(struct event* e);
+static inline int min_heap_elt_is_top(const struct event *e);
static inline int min_heap_elem_greater(struct event *a, struct event *b);
static inline int min_heap_empty(min_heap_t* s);
static inline unsigned min_heap_size(min_heap_t* s);
return 0;
}
+int min_heap_elt_is_top(const struct event *e)
+{
+ return e->min_heap_idx == 0;
+}
+
int min_heap_erase(min_heap_t* s, struct event* e)
{
if(((unsigned int)-1) != e->min_heap_idx)
event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1);
event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2);
event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2);
- if (event_add(&r1.ev, NULL) == -1)
- exit(1);
- if (event_add(&w1.ev, NULL))
- exit(1);
- if (event_add(&r2.ev, NULL))
- exit(1);
- if (event_add(&w2.ev, NULL))
- exit(1);
-
+ tt_assert(event_add(&r1.ev, NULL) != -1);
+ tt_assert(!event_add(&w1.ev, NULL));
+ tt_assert(!event_add(&r2.ev, NULL));
+ tt_assert(!event_add(&w2.ev, NULL));
event_dispatch();
if (r1.nread == 8192 && r2.nread == 4096)
test_ok = 1;
+end:
cleanup_test();
}