int zloop_start (zloop_t *self) { assert (self); int rc = 0; // Recalculate all timers now s_timer_t *timer = (s_timer_t *) zlist_first (self->timers); while (timer) { timer->when = timer->delay + zclock_time (); timer = (s_timer_t *) zlist_next (self->timers); } // Main reactor loop while (!zctx_interrupted) { if (self->need_rebuild) { // If s_rebuild_pollset() fails, break out of the loop and // return its error rc = s_rebuild_pollset (self); if (rc) break; } rc = zmq_poll (self->pollset, (int) self->poll_size, s_tickless_timer (self) * ZMQ_POLL_MSEC); if (rc == -1 || zctx_interrupted) { if (self->verbose) zclock_log ("I: zloop: interrupted (%d) - %s", rc, zmq_strerror (zmq_errno ())); rc = 0; break; // Context has been shut down } // Handle any timers that have now expired timer = (s_timer_t *) zlist_first (self->timers); while (timer) { if (zclock_time () >= timer->when && timer->when != -1) { if (self->verbose) zclock_log ("I: zloop: call timer id=%d handler", timer->timer_id); rc = timer->handler (self, timer->timer_id, timer->arg); if (rc == -1) break; // Timer handler signaled break if (timer->times && --timer->times == 0) { zlist_remove (self->timers, timer); free (timer); } else timer->when = timer->delay + zclock_time (); } timer = (s_timer_t *) zlist_next (self->timers); } // Handle any pollers that are ready size_t item_nbr; for (item_nbr = 0; item_nbr < self->poll_size && rc >= 0; item_nbr++) { s_poller_t *poller = &self->pollact [item_nbr]; assert (self->pollset [item_nbr].socket == poller->item.socket); if ((self->pollset [item_nbr].revents & ZMQ_POLLERR) && !poller->tolerant) { if (self->verbose) zclock_log ("W: zloop: can't poll %s socket (%p, %d): %s", poller->item.socket? zsocket_type_str (poller->item.socket): "FD", poller->item.socket, poller->item.fd, zmq_strerror (zmq_errno ())); // Give handler one chance to handle error, then kill // poller because it'll disrupt the reactor otherwise. if (poller->errors++) { zloop_poller_end (self, &poller->item); self->pollset [item_nbr].revents = 0; } } else poller->errors = 0; // A non-error happened if (self->pollset [item_nbr].revents) { if (self->verbose) zclock_log ("I: zloop: call %s socket handler (%p, %d)", poller->item.socket? zsocket_type_str (poller->item.socket): "FD", poller->item.socket, poller->item.fd); rc = poller->handler (self, &self->pollset [item_nbr], poller->arg); if (rc == -1 || self->need_rebuild) break; } } // Now handle any timer zombies // This is going to be slow if we have many timers; we might use // a faster lookup on the timer list. while (zlist_size (self->zombies)) { // This hack lets us convert our pointer back into an integer timer_id int timer_id = (byte *) zlist_pop (self->zombies) - (byte *) NULL; timer = (s_timer_t *) zlist_first (self->timers); while (timer) { if (timer->timer_id == timer_id) { zlist_remove (self->timers, timer); free (timer); } timer = (s_timer_t *) zlist_next (self->timers); } } if (rc == -1) break; } return rc; }
int zloop_start (zloop_t *self) { assert (self); int rc = 0; // Main reactor loop while (!zsys_interrupted) { if (self->need_rebuild) { // If s_rebuild_pollset() fails, break out of the loop and // return its error rc = s_rebuild_pollset (self); if (rc) break; } rc = zmq_poll (self->pollset, (int) self->poll_size, s_tickless (self)); if (rc == -1 || zsys_interrupted) { if (self->verbose) zsys_debug ("zloop: interrupted"); rc = 0; break; // Context has been shut down } // Handle any timers that have now expired int64_t time_now = zclock_mono (); s_timer_t *timer = (s_timer_t *) zlistx_first (self->timers); while (timer) { if (time_now >= timer->when) { if (self->verbose) zsys_debug ("zloop: call timer handler id=%d", timer->timer_id); rc = timer->handler (self, timer->timer_id, timer->arg); if (rc == -1) break; // Timer handler signaled break if (timer->times && --timer->times == 0) zlistx_delete (self->timers, timer->list_handle); else timer->when += timer->delay; } timer = (s_timer_t *) zlistx_next (self->timers); } // Handle any tickets that have now expired s_ticket_t *ticket = (s_ticket_t *) zlistx_first (self->tickets); while (ticket && time_now >= ticket->when) { if (self->verbose) zsys_debug ("zloop: call ticket handler"); rc = ticket->handler (self, 0, ticket->arg); if (rc == -1) break; // Timer handler signaled break zlistx_delete (self->tickets, ticket->list_handle); ticket = (s_ticket_t *) zlistx_next (self->tickets); } // Handle any readers and pollers that are ready size_t item_nbr; for (item_nbr = 0; item_nbr < self->poll_size && rc >= 0; item_nbr++) { s_reader_t *reader = &self->readact [item_nbr]; if (reader->handler) { if ((self->pollset [item_nbr].revents & ZMQ_POLLERR) && !reader->tolerant) { if (self->verbose) zsys_warning ("zloop: can't read %s socket: %s", zsock_type_str (reader->sock), zmq_strerror (zmq_errno ())); // Give handler one chance to handle error, then kill // reader because it'll disrupt the reactor otherwise. if (reader->errors++) { zloop_reader_end (self, reader->sock); self->pollset [item_nbr].revents = 0; } } else reader->errors = 0; // A non-error happened if (self->pollset [item_nbr].revents) { if (self->verbose) zsys_debug ("zloop: call %s socket handler", zsock_type_str (reader->sock)); rc = reader->handler (self, reader->sock, reader->arg); if (rc == -1 || self->need_rebuild) break; } } else { s_poller_t *poller = &self->pollact [item_nbr]; assert (self->pollset [item_nbr].socket == poller->item.socket); if ((self->pollset [item_nbr].revents & ZMQ_POLLERR) && !poller->tolerant) { if (self->verbose) zsys_warning ("zloop: can't poll %s socket (%p, %d): %s", poller->item.socket ? zsys_sockname (zsock_type (poller->item.socket)) : "FD", poller->item.socket, poller->item.fd, zmq_strerror (zmq_errno ())); // Give handler one chance to handle error, then kill // poller because it'll disrupt the reactor otherwise. if (poller->errors++) { zloop_poller_end (self, &poller->item); self->pollset [item_nbr].revents = 0; } } else poller->errors = 0; // A non-error happened if (self->pollset [item_nbr].revents) { if (self->verbose) zsys_debug ("zloop: call %s socket handler (%p, %d)", poller->item.socket ? zsys_sockname (zsock_type (poller->item.socket)) : "FD", poller->item.socket, poller->item.fd); rc = poller->handler (self, &self->pollset [item_nbr], poller->arg); if (rc == -1 || self->need_rebuild) break; } } } // Now handle any timer zombies // This is going to be slow if we have many timers; we might use // a faster lookup on the timer list. while (zlistx_first (self->zombies)) { // Get timer_id back from pointer int timer_id = (byte *) zlistx_detach (self->zombies, NULL) - (byte *) NULL; s_timer_remove (self, timer_id); } if (rc == -1) break; } self->terminated = true; return rc; }
int zloop_start (zloop_t *self) { assert (self); int rc = 0; // Recalculate all timers now s_timer_t *timer = (s_timer_t *) zlist_first (self->timers); while (timer) { timer->when = timer->delay + zclock_time (); timer = (s_timer_t *) zlist_next (self->timers); } // Main reactor loop while (!zctx_interrupted) { if (self->dirty) { // If s_rebuild_pollset() fails, break out of the loop and // return its error rc = s_rebuild_pollset (self); if (rc) break; } rc = zmq_poll (self->pollset, (int) self->poll_size, s_tickless_timer (self) * ZMQ_POLL_MSEC); if (rc == -1 || zctx_interrupted) { if (self->verbose) zclock_log ("I: zloop: interrupted (%d) - %s", rc, zmq_strerror (zmq_errno ())); rc = 0; break; // Context has been shut down } // Handle any timers that have now expired timer = (s_timer_t *) zlist_first (self->timers); while (timer) { if (zclock_time () >= timer->when && timer->when != -1) { if (self->verbose) zclock_log ("I: zloop: call timer handler"); rc = timer->handler (self, NULL, timer->arg); if (rc == -1) break; // Timer handler signaled break if (timer->times && --timer->times == 0) { zlist_remove (self->timers, timer); free (timer); } else timer->when = timer->delay + zclock_time (); } timer = (s_timer_t *) zlist_next (self->timers); } // Handle any pollers that are ready size_t item_nbr; for (item_nbr = 0; item_nbr < self->poll_size && rc >= 0; item_nbr++) { s_poller_t *poller = &self->pollact [item_nbr]; assert (self->pollset [item_nbr].socket == poller->item.socket); if ((self->pollset [item_nbr].revents & ZMQ_POLLERR) && !poller->ignore_errors) { if (self->verbose) zclock_log ("I: zloop: can't poll %s socket (%p, %d): %s", poller->item.socket? zsocket_type_str (poller->item.socket): "FD", poller->item.socket, poller->item.fd, zmq_strerror (zmq_errno ())); // Give handler one chance to handle error, then kill // poller because it'll disrupt the reactor otherwise. if (poller->errors++) { zloop_poller_end (self, &poller->item); self->pollset [item_nbr].revents = 0; } } else poller->errors = 0; // A non-error happened if (self->pollset [item_nbr].revents) { if (self->verbose) zclock_log ("I: zloop: call %s socket handler (%p, %d)", poller->item.socket? zsocket_type_str (poller->item.socket): "FD", poller->item.socket, poller->item.fd); rc = poller->handler (self, &self->pollset [item_nbr], poller->arg); if (rc == -1) break; // Poller handler signaled break // If the poller handler calls zloop_poller_end on poller other than itself // we need to force rebuild in order to avoid reading from freed memory in the handler if (self->dirty) { if (self->verbose) zclock_log ("I: zloop: pollers canceled, forcing rebuild"); break; } } } // Now handle any timer zombies // This is going to be slow if we have many zombies while (zlist_size (self->zombies)) { void *arg = zlist_pop (self->zombies); timer = (s_timer_t *) zlist_first (self->timers); while (timer) { if (timer->arg == arg) { zlist_remove (self->timers, timer); free (timer); } timer = (s_timer_t *) zlist_next (self->timers); } } if (rc == -1) break; } return rc; }