int zloop_start (zloop_t *self) { assert (self); int rc = 0; // Main reactor loop while (!zsys_interrupted || self->nonstop) { if (rc == -1) // somebody wanted us to quit break; 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 && !self->nonstop)) { if (self->verbose) { if (rc == -1) zsys_debug ("zloop: interrupted: %s", strerror (errno)); else zsys_debug ("zloop: zsys_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 (timer->times && --timer->times == 0) zlistx_delete (self->timers, timer->list_handle); else timer->when += timer->delay; if (rc == -1) break; // Timer handler signaled break } 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"); if (!ticket->deleted && ticket->handler (self, 0, ticket->arg) == -1) { rc = -1; // Trigger exit from zloop_start break; // Ticket handler signaled break } zlistx_delete (self->tickets, ticket->list_handle); ticket = (s_ticket_t *) zlistx_next (self->tickets); } // Handle any tickets that were flagged for deletion ticket = (s_ticket_t *) zlistx_last (self->tickets); while (ticket && ticket->deleted) { zlistx_delete (self->tickets, ticket->list_handle); ticket = (s_ticket_t *) zlistx_last (self->tickets); } // Check if timers changed pollset if (self->need_rebuild) continue; // 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 ptrdiff_t timer_id = (byte *) zlistx_detach (self->zombies, NULL) - (byte *) NULL; s_timer_remove (self, (int) timer_id); } } self->terminated = true; return rc; }
void zlistx_test (bool verbose) { printf (" * zlistx: "); // @selftest zlistx_t *list = zlistx_new (); assert (list); assert (zlistx_size (list) == 0); // Test operations on an empty list assert (zlistx_first (list) == NULL); assert (zlistx_last (list) == NULL); assert (zlistx_next (list) == NULL); assert (zlistx_prev (list) == NULL); assert (zlistx_find (list, "hello") == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); zlistx_purge (list); zlistx_sort (list); // Use item handlers zlistx_set_destructor (list, (zlistx_destructor_fn *) zstr_free); zlistx_set_duplicator (list, (zlistx_duplicator_fn *) strdup); zlistx_set_comparator (list, (zlistx_comparator_fn *) strcmp); // Try simple insert/sort/delete/next assert (zlistx_next (list) == NULL); zlistx_add_end (list, "world"); assert (streq ((char *) zlistx_next (list), "world")); zlistx_add_end (list, "hello"); assert (streq ((char *) zlistx_prev (list), "hello")); zlistx_sort (list); assert (zlistx_size (list) == 2); void *handle = zlistx_find (list, "hello"); char *item1 = (char *) zlistx_item (list); char *item2 = (char *) zlistx_handle_item (handle); assert (item1 == item2); assert (streq (item1, "hello")); zlistx_delete (list, handle); assert (zlistx_size (list) == 1); char *string = (char *) zlistx_detach (list, NULL); assert (streq (string, "world")); free (string); assert (zlistx_size (list) == 0); // Check next/back work // Now populate the list with items zlistx_add_start (list, "five"); zlistx_add_end (list, "six"); zlistx_add_start (list, "four"); zlistx_add_end (list, "seven"); zlistx_add_start (list, "three"); zlistx_add_end (list, "eight"); zlistx_add_start (list, "two"); zlistx_add_end (list, "nine"); zlistx_add_start (list, "one"); zlistx_add_end (list, "ten"); // Test our navigation skills assert (zlistx_size (list) == 10); assert (streq ((char *) zlistx_last (list), "ten")); assert (streq ((char *) zlistx_prev (list), "nine")); assert (streq ((char *) zlistx_prev (list), "eight")); assert (streq ((char *) zlistx_prev (list), "seven")); assert (streq ((char *) zlistx_prev (list), "six")); assert (streq ((char *) zlistx_prev (list), "five")); assert (streq ((char *) zlistx_first (list), "one")); assert (streq ((char *) zlistx_next (list), "two")); assert (streq ((char *) zlistx_next (list), "three")); assert (streq ((char *) zlistx_next (list), "four")); // Sort by alphabetical order zlistx_sort (list); assert (streq ((char *) zlistx_first (list), "eight")); assert (streq ((char *) zlistx_last (list), "two")); // Moving items around handle = zlistx_find (list, "six"); zlistx_move_start (list, handle); assert (streq ((char *) zlistx_first (list), "six")); zlistx_move_end (list, handle); assert (streq ((char *) zlistx_last (list), "six")); zlistx_sort (list); assert (streq ((char *) zlistx_last (list), "two")); // Copying a list zlistx_t *copy = zlistx_dup (list); assert (copy); assert (zlistx_size (copy) == 10); assert (streq ((char *) zlistx_first (copy), "eight")); assert (streq ((char *) zlistx_last (copy), "two")); zlistx_destroy (©); // Delete items while iterating string = (char *) zlistx_first (list); assert (streq (string, "eight")); string = (char *) zlistx_next (list); assert (streq (string, "five")); zlistx_delete (list, zlistx_cursor (list)); string = (char *) zlistx_next (list); assert (streq (string, "four")); zlistx_purge (list); zlistx_destroy (&list); // @end printf ("OK\n"); }
/// // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor pointing at the tail item, or NULL if the list is empty. void * QZlistx::last () { void * rv = zlistx_last (self); return rv; }