void Event::notify(){ for (std::set<EventListener*>::iterator it=listeners.begin(); it!=listeners.end();){ EventListener* e = *it; it++; // Increment before calling handler in case the handler removes this listener, // which would invalidate the iterator. e->handler(); } }
extern void sys_waitevents(struct ListHead *listeners_list) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); EventListener *listeners = GET_LIST_ENTRY(listeners_list, EventListener, listeners_list_head); EventListener *last_listener = GET_LIST_ENTRY(listeners_list->prev, EventListener, listeners_list_head); int min_timeout = INT_MAX; int count = 0; //first: find maximum allowed sleep time, and count file descriptor listeners EventListener *listener = listeners; do { if (listener->expires) { int wait_ms = timespec_diff_to_ms(&listener->expiral_timestamp, &now); if (wait_ms <= 0) { min_timeout = 0; } else if (min_timeout > wait_ms) { min_timeout = wait_ms; } } if (listener->fd >= 0) { count++; } listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head); } while (listener != listeners); //second: use either poll or nanosleep if (count > 0) { struct pollfd *fds = calloc(count, sizeof(struct pollfd)); if (IS_NULL_PTR(fds)) { fprintf(stderr, "Cannot allocate memory for pollfd, aborting.\n"); abort(); } int poll_fd_index = 0; //build pollfd array EventListener *listener = listeners; do { if (listener->fd >= 0) { fds[poll_fd_index].fd = listener->fd; fds[poll_fd_index].events = POLLIN; fds[poll_fd_index].revents = 0; } poll_fd_index++; listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head); } while (listener != listeners); poll(fds, poll_fd_index, min_timeout); //check which event happened listener = listeners; do { EventListener *next_listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head); for (int i = 0; i < poll_fd_index; i++) { if ((fds[i].fd == listener->fd) && (fds[i].revents & fds[i].events)) { //it is completely safe to free a listener in the callback, we are going to not use it after this call listener->handler(listener); } } listener = next_listener; } while (listener != listeners); free(fds); //just need to wait for a certain timespan } else { struct timespec t; t.tv_sec = min_timeout / 1000; t.tv_nsec = (min_timeout % 1000) * 1000000; struct timespec rem; int nanosleep_result = nanosleep(&t, &rem); while (nanosleep_result == -1) { nanosleep_result = nanosleep(&rem, &rem); } } //third: execute handlers for expiered timers if (min_timeout != INT_MAX) { listener = listeners; clock_gettime(CLOCK_MONOTONIC, &now); do { EventListener *next_listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head); if (listener->expires) { int wait_ms = timespec_diff_to_ms(&listener->expiral_timestamp, &now); if (wait_ms <= 0) { //it is completely safe to free a listener in the callback, we are going to not use it after this call listener->handler(listener); //TODO check if one shot } } listener = next_listener; } while (listener != last_listener); } }