int zloop_poller (zloop_t *self, zmq_pollitem_t *item, zloop_fn handler, void *arg) { assert (self); if (!item->socket && !item->fd) return -1; if (item->socket) if (streq (zsocket_type_str (item->socket), "UNKNOWN")) return -1; s_poller_t *poller = s_poller_new (item, handler, arg); if (poller) { if (zlist_append (self->pollers, poller)) return -1; self->dirty = true; if (self->verbose) zclock_log ("I: zloop: register %s poller (%p, %d)", item->socket? zsocket_type_str (item->socket): "FD", item->socket, item->fd); return 0; } else return -1; }
int zsocket_test (Bool verbose) { printf (" * zsocket: "); // @selftest zctx_t *ctx = zctx_new (); assert (ctx); // Create a detached thread, let it run char *interf = "*"; char *domain = "localhost"; int service = 5560; void *writer = zsocket_new (ctx, ZMQ_PUSH); assert (writer); void *reader = zsocket_new (ctx, ZMQ_PULL); assert (reader); assert (streq (zsocket_type_str (writer), "PUSH")); assert (streq (zsocket_type_str (reader), "PULL")); int rc = zsocket_bind (writer, "tcp://%s:%d", interf, service); assert (rc == service); rc = zsocket_connect (reader, "tcp://%s:%d", domain, service); assert (rc == 0); zstr_send (writer, "HELLO"); char *message = zstr_recv (reader); assert (message); assert (streq (message, "HELLO")); free (message); int port = zsocket_bind (writer, "tcp://%s:*", interf); assert (port >= ZSOCKET_DYNFROM && port <= ZSOCKET_DYNTO); assert (zsocket_poll (writer, 100) == FALSE); rc = zsocket_connect (reader, "txp://%s:%d", domain, service); assert (rc == -1); zsocket_destroy (ctx, writer); zctx_destroy (&ctx); // @end printf ("OK\n"); return 0; }
void zsocket_set_unsubscribe (void *zocket, char * unsubscribe) { # if defined (ZMQ_UNSUBSCRIBE) if (zsockopt_type (zocket) != ZMQ_SUB) { printf ("ZMQ_UNSUBSCRIBE is not valid on %s sockets\n", zsocket_type_str (zocket)); assert (false); } int rc = zmq_setsockopt (zocket, ZMQ_UNSUBSCRIBE, unsubscribe, strlen (unsubscribe)); assert (rc == 0 || errno == ETERM); # endif }
void zsocket_set_xpub_verbose (void *zocket, int xpub_verbose) { # if defined (ZMQ_XPUB_VERBOSE) if (zsockopt_type (zocket) != ZMQ_XPUB) { printf ("ZMQ_XPUB_VERBOSE is not valid on %s sockets\n", zsocket_type_str (zocket)); assert (false); } int rc = zmq_setsockopt (zocket, ZMQ_XPUB_VERBOSE, &xpub_verbose, sizeof (int)); assert (rc == 0 || errno == ETERM); # endif }
void zsocket_set_router_raw (void *zocket, int router_raw) { # if defined (ZMQ_ROUTER_RAW) if (zsockopt_type (zocket) != ZMQ_ROUTER) { printf ("ZMQ_ROUTER_RAW is not valid on %s sockets\n", zsocket_type_str (zocket)); assert (false); } int rc = zmq_setsockopt (zocket, ZMQ_ROUTER_RAW, &router_raw, sizeof (int)); assert (rc == 0 || errno == ETERM); # endif }
void zsocket_set_router_mandatory (void *zocket, int router_mandatory) { # if defined (ZMQ_ROUTER_MANDATORY) if (zsockopt_type (zocket) != ZMQ_ROUTER) { printf ("ZMQ_ROUTER_MANDATORY is not valid on %s sockets\n", zsocket_type_str (zocket)); assert (false); } int rc = zmq_setsockopt (zocket, ZMQ_ROUTER_MANDATORY, &router_mandatory, sizeof (int)); assert (rc == 0 || errno == ETERM); # endif }
void zsocket_set_identity (void *zocket, char * identity) { # if defined (ZMQ_IDENTITY) if (zsockopt_type (zocket) != ZMQ_REQ && zsockopt_type (zocket) != ZMQ_REP && zsockopt_type (zocket) != ZMQ_DEALER && zsockopt_type (zocket) != ZMQ_ROUTER) { printf ("ZMQ_IDENTITY is not valid on %s sockets\n", zsocket_type_str (zocket)); assert (false); } int rc = zmq_setsockopt (zocket, ZMQ_IDENTITY, identity, strlen (identity)); assert (rc == 0 || errno == ETERM); # endif }
void zloop_poller_end (zloop_t *self, zmq_pollitem_t *item) { assert (self); assert (item->socket || item->fd); s_poller_t *poller = (s_poller_t *) zlist_first (self->pollers); while (poller) { if ((item->socket && item->socket == poller->item.socket) || (item->fd && item->fd == poller->item.fd)) { zlist_remove (self->pollers, poller); free (poller); self->dirty = true; } poller = (s_poller_t *) zlist_next (self->pollers); } if (self->verbose) zclock_log ("I: zloop: cancel %s poller (%p, %d)", item->socket? zsocket_type_str (item->socket): "FD", item->socket, item->fd); }
void zloop_poller_end (zloop_t *self, zmq_pollitem_t *item) { assert (self); assert (item->socket || item->fd); s_poller_t *poller = (s_poller_t *) zlist_first (self->pollers); while (poller) { if ((item->socket && item->socket == poller->item.socket) || (item->fd && item->fd == poller->item.fd)) { zlist_remove (self->pollers, poller); free (poller); // Force rebuild to avoid reading from freed poller self->need_rebuild = true; } poller = (s_poller_t *) zlist_next (self->pollers); } if (self->verbose) zsys_debug ("zloop: cancel %s poller (%p, %d)", item->socket? zsocket_type_str (item->socket): "FD", item->socket, item->fd); }
void zsocket_test (bool verbose) { printf (" * zsocket (deprecated): "); // @selftest zctx_t *ctx = zctx_new (); assert (ctx); // Create a detached thread, let it run char *interf = "127.0.0.1"; char *domain = "localhost"; int service = 5560; void *writer = zsocket_new (ctx, ZMQ_PUSH); assert (writer); void *reader = zsocket_new (ctx, ZMQ_PULL); assert (reader); assert (streq (zsocket_type_str (writer), "PUSH")); assert (streq (zsocket_type_str (reader), "PULL")); int rc = zsocket_bind (writer, "tcp://%s:%d", interf, service); assert (rc == service); #if (ZMQ_VERSION >= ZMQ_MAKE_VERSION (3, 2, 0)) // Check unbind rc = zsocket_unbind (writer, "tcp://%s:%d", interf, service); assert (rc == 0); // In some cases and especially when running under Valgrind, doing // a bind immediately after an unbind causes an EADDRINUSE error. // Even a short sleep allows the OS to release the port for reuse. zclock_sleep (100); // Bind again rc = zsocket_bind (writer, "tcp://%s:%d", interf, service); assert (rc == service); #endif rc = zsocket_connect (reader, "tcp://%s:%d", domain, service); assert (rc == 0); zstr_send (writer, "HELLO"); char *message = zstr_recv (reader); assert (message); assert (streq (message, "HELLO")); free (message); // Test binding to ports int port = zsocket_bind (writer, "tcp://%s:*", interf); assert (port >= ZSOCKET_DYNFROM && port <= ZSOCKET_DYNTO); assert (zsocket_poll (writer, 100) == false); // Test error state when connecting to an invalid socket type // ('txp://' instead of 'tcp://', typo intentional) rc = zsocket_connect (reader, "txp://%s:%d", domain, service); assert (rc == -1); // Test sending frames to socket rc = zsocket_sendmem (writer, "ABC", 3, ZFRAME_MORE); assert (rc == 0); rc = zsocket_sendmem (writer, "DEFG", 4, 0); assert (rc == 0); zframe_t *frame = zframe_recv (reader); assert (frame); assert (zframe_streq (frame, "ABC")); assert (zframe_more (frame)); zframe_destroy (&frame); frame = zframe_recv (reader); assert (frame); assert (zframe_streq (frame, "DEFG")); assert (!zframe_more (frame)); zframe_destroy (&frame); rc = zsocket_signal (writer); assert (rc == 0); rc = zsocket_wait (reader); assert (rc == 0); zsocket_destroy (ctx, reader); zsocket_destroy (ctx, writer); zctx_destroy (&ctx); // @end printf ("OK\n"); }
int zsocket_test (bool verbose) { printf (" * zsocket: "); // @selftest zctx_t *ctx = zctx_new (); assert (ctx); // Create a detached thread, let it run char *interf = "*"; char *domain = "localhost"; int service = 5560; void *writer = zsocket_new (ctx, ZMQ_PUSH); assert (writer); void *reader = zsocket_new (ctx, ZMQ_PULL); assert (reader); assert (streq (zsocket_type_str (writer), "PUSH")); assert (streq (zsocket_type_str (reader), "PULL")); int rc = zsocket_bind (writer, "tcp://%s:%d", interf, service); assert (rc == service); rc = zsocket_connect (reader, "tcp://%s:%d", domain, service); assert (rc == 0); zstr_send (writer, "HELLO"); char *message = zstr_recv (reader); assert (message); assert (streq (message, "HELLO")); free (message); // Test binding to ports int port = zsocket_bind (writer, "tcp://%s:*", interf); assert (port >= ZSOCKET_DYNFROM && port <= ZSOCKET_DYNTO); assert (zsocket_poll (writer, 100) == false); rc = zsocket_connect (reader, "txp://%s:%d", domain, service); assert (rc == -1); // Test sending frames to socket rc = zsocket_sendmem (writer,"ABC", 3, ZFRAME_MORE); assert (rc == 0); rc = zsocket_sendmem (writer, "DEFG", 4, 0); assert (rc == 0); zframe_t *frame = zframe_recv (reader); assert (frame); assert (zframe_streq (frame, "ABC")); assert (zframe_more (frame)); zframe_destroy (&frame); frame = zframe_recv (reader); assert (frame); assert (zframe_streq (frame, "DEFG")); assert (!zframe_more (frame)); zframe_destroy (&frame); // Test zframe_sendmem_zero_copy rc = zsocket_sendmem_zero_copy (writer, strdup ("ABC"), 3, s_test_free_str_cb, NULL, ZFRAME_MORE); assert (rc == 0); rc = zsocket_sendmem_zero_copy (writer, strdup ("DEFG"), 4, s_test_free_str_cb, NULL, 0); assert (rc == 0); frame = zframe_recv (reader); assert (frame); assert (zframe_streq (frame, "ABC")); assert (zframe_more (frame)); zframe_destroy (&frame); frame = zframe_recv (reader); assert (frame); assert (zframe_streq (frame, "DEFG")); assert (!zframe_more (frame)); zframe_destroy (&frame); zsocket_destroy (ctx, writer); zctx_destroy (&ctx); // @end printf ("OK\n"); return 0; }
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 (!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_timer (self) * ZMQ_POLL_MSEC); if (rc == -1 || zsys_interrupted) { if (self->verbose) zsys_debug ("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) zsys_debug ("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 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? 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) zsys_debug ("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)) { // Get timer_id back from pointer int timer_id = (byte *) zlist_pop (self->zombies) - (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, strerror (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, strerror (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 } } // 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); break; } timer = (s_timer_t *) zlist_next (self->timers); } } if (rc == -1) break; } return rc; }
// Main int main (int argc, char **argv) { // Do some initial sanity checking assert (TIME_BITLEN + MACHINE_BITLEN + SEQ_BITLEN == 64); // Parse command-line arguments int opt; int has_port_opt = 0; int has_machine_opt = 0; int has_config_file_opt = 0; int has_daemonize_opt = 0; int machine_specified = 0; const char *config_file_path; int port = DEFAULT_PORT; uint64_t machine; while ((opt = getopt (argc, argv, "hp:m:f:d")) != -1) { switch (opt) { case 'h': print_help (); exit (EXIT_SUCCESS); case 'p': has_port_opt = 1; port = atoi (optarg); break; case 'm': has_machine_opt = 1; machine = atoll (optarg); machine_specified = 1; break; case 'f': has_config_file_opt = 1; config_file_path = optarg; break; case 'd': has_daemonize_opt = 1; break; } } // Read the config file if (has_config_file_opt) { config_t cfg; config_init (&cfg); if (!config_read_file (&cfg, config_file_path)) { config_destroy (&cfg); fprintf (stderr, "Invalid config file\n"); exit (EXIT_FAILURE); } long unsigned int machine_from_file; if (config_lookup_int (&cfg, "machine", &machine_from_file) && !has_machine_opt) { machine_specified = 1; machine = (uint64_t) machine_from_file; } long unsigned int port_from_file; if (config_lookup_int (&cfg, "port", &port_from_file) && !has_port_opt) port = (int) port_from_file; } // Sanity check the machine number if (!machine_specified) { fprintf (stderr, "No machine number specified.\n"); exit (EXIT_FAILURE); } else if (machine > MACHINE_MAX) { fprintf (stderr, "Machine number too large. Cannot be greater than %llu\n", MACHINE_MAX); exit (EXIT_FAILURE); } // Daemonize static char *pid_file_path = "/var/run/znowflaked.pid"; int pid_file; if (has_daemonize_opt) { pid_t pid, sid; pid = fork (); if (pid < 0) { exit (EXIT_FAILURE); } if (pid > 0) { exit (EXIT_SUCCESS); } umask (0); sid = setsid (); if (sid < 0) { exit (EXIT_FAILURE); } if ((chdir ("/")) < 0) { exit (EXIT_FAILURE); } // Create and lock the pid file pid_file = open (pid_file_path, O_CREAT | O_RDWR, 0666); if (pid_file > 0) { int rc = lockf (pid_file, F_TLOCK, 0); if (rc) { switch (errno) { case EACCES: case EAGAIN: fprintf (stderr, "PID file already locked\n"); break; case EBADF: fprintf (stderr, "Bad pid file\n"); break; default: fprintf (stderr, "Could not lock pid file\n"); } exit (EXIT_FAILURE); } char *pid_string = NULL; int pid_string_len = asprintf (&pid_string, "%ld", (long) getpid ()); write (pid_file, pid_string, pid_string_len); } close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO); } // Sleep for 1ms to prevent collisions struct timespec ms; ms.tv_sec = 0; ms.tv_nsec = 1000000; nanosleep (&ms, NULL); // Initialize ZeroMQ zctx_t *context = zctx_new (); assert (context); void *socket = zsocket_new (context, ZMQ_REP); assert (socket); assert (streq (zsocket_type_str (socket), "REP")); int rc = zsocket_bind (socket, "tcp://*:%d", port); if (rc != port) { printf ("E: bind failed: %s\n", strerror (errno)); exit (EXIT_FAILURE); } // Start remembering the last timer tick uint64_t ts = 0; uint64_t last_ts = 0; uint64_t seq = 0; // Main loop s_catch_signals (); while (1) { // Wait for the next request zmsg_t *request_msg = zmsg_new (); assert (request_msg); request_msg = zmsg_recv (socket); assert (request_msg); zmsg_destroy (&request_msg); // Grab a time click last_ts = ts; ts = get_ts (); // Make sure the system clock wasn't reversed on us if (ts < last_ts) { // Wait until it catches up while (ts <= last_ts) { nanosleep (&ms, NULL); ts = get_ts (); } } // Increment the sequence number if (ts != last_ts) { // We're in a new time click, so reset the sequence seq = 0; } else if (seq == SEQ_MAX) { // Wrapped sequence, so wait for the next time tick seq = 0; nanosleep (&ms, NULL); } else { // Still in the same time click seq++; } // Build the ID and put it in network byte order uint64_t id = build_id (ts, machine, seq); uint64_t id_be64 = htobe64 (id); // Reply zmsg_t *reply_msg = zmsg_new (); assert (reply_msg); zframe_t *frame = zframe_new (&id_be64, 8); assert (frame); zmsg_push (reply_msg, frame); assert (zmsg_size (reply_msg) == 1); assert (zmsg_content_size (reply_msg) == 8); zmsg_send (&reply_msg, socket); assert (reply_msg == NULL); // Exit program if (s_interrupted) { printf ("interrupt received, killing server…\n"); break; } } zctx_destroy (&context); if (has_daemonize_opt) { if (pid_file > 0) { unlink (pid_file_path); close (pid_file); } } exit (EXIT_SUCCESS); }
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 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) break; // Poller handler signaled break // If the poller handler calls zloop_poller_end on a 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 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; }