static int zio_zloop_writer_cb (zloop_t *zl, zmq_pollitem_t *zp, zio_t *zio) { int rc; zio_handler_start (zio); rc = zio_writer_cb (zio); if (!zio_write_pending (zio)) zloop_poller_end (zl, zp); zio_handler_end (zio); return (rc); }
static void peering_poller (peering_t *self, int events) { driver_t *driver = self->driver; if (self->events != events) { zmq_pollitem_t item = { NULL, self->handle, events, 0 }; zloop_poller_end (driver->loop, &item); if (events) zloop_poller (driver->loop, &item, s_peering_activity, self); self->events = events; } }
static int zio_zloop_read_cb (zloop_t *zl, zmq_pollitem_t *zp, zio_t *zio) { int rc; zio_handler_start (zio); rc = zio_read_cb_common (zio); if (rc >= 0 && zio_eof_sent (zio)) { zio_debug (zio, "reader detaching from zloop\n"); zloop_poller_end (zl, zp); rc = zio_close (zio); } zio_handler_end (zio); return (rc); }
// Handle input from client, on frontend int s_handle_frontend(zloop_t *loop, zmq_pollitem_t *poller, void *arg) { lbbroker_t *self = (lbbroker_t *)arg; zmsg_t *msg = zmsg_recv(self->frontend); if (msg) { zmsg_wrap(msg, (zframe_t *)zlist_pop(self->workers)); zmsg_send(&msg, self->backend); // Cancel reader on frontend if we went from 1 to 0 workers if (zlist_size(self->workers) == 0) { zmq_pollitem_t poller = { self->frontend, 0, ZMQ_POLLIN }; zloop_poller_end(loop, &poller); } } return 0; }
static void peering_lower (peering_t *self) { vocket_t *vocket = self->vocket; driver_t *driver = self->driver; if (driver->verbose) zclock_log ("I: (tcp) take down peering to %s", self->address); if (self->alive) { self->alive = FALSE; zlist_remove (vocket->live_peerings, self); if (zlist_size (vocket->live_peerings) < vocket->min_peerings) { // Ask reactor to stop monitoring vocket's msgpipe pipe zmq_pollitem_t item = { vocket->msgpipe, 0, ZMQ_POLLIN, 0 }; zloop_poller_end (driver->loop, &item); } } }
static void vocket_destroy (vocket_t **self_p) { assert (self_p); if (*self_p) { vocket_t *self = *self_p; driver_t *driver = self->driver; if (self->min_peerings == 0) { // Ask reactor to stop monitoring vocket's msgpipe zmq_pollitem_t item = { self->msgpipe, 0, ZMQ_POLLIN, 0 }; zloop_poller_end (driver->loop, &item); } // Close message msgpipe socket zsocket_destroy (driver->ctx, self->msgpipe); // Destroy all bindings for this vocket zhash_destroy (&self->binding_hash); // Destroy all peerings for this vocket zhash_destroy (&self->peering_hash); zlist_destroy (&self->peering_list); zlist_destroy (&self->live_peerings); // Remove vocket from driver list of vockets zlist_remove (driver->vockets, self); #ifdef VOCKET_STATS char *type_name [] = { "PAIR", "PUB", "SUB", "REQ", "REP", "DEALER", "ROUTER", "PULL", "PUSH", "XPUB", "XSUB" }; printf ("I: type=%s sent=%d recd=%d outp=%d inp=%d drop=%d\n", type_name [self->socktype], self->outgoing, self->incoming, self->outpiped, self->inpiped, self->dropped); #endif free (self->vtxname); free (self); *self_p = NULL; } }
static int s_new_master (zloop_t *loop, zmq_pollitem_t *unused, void *args) { clonesrv_t *self = (clonesrv_t *) args; self->master = TRUE; self->slave = FALSE; zmq_pollitem_t poller = { self->subscriber, 0, ZMQ_POLLIN }; zloop_poller_end (bstar_zloop (self->bstar), &poller); // Apply pending list to own hash table while (zlist_size (self->pending)) { kvmsg_t *kvmsg = (kvmsg_t *) zlist_pop (self->pending); kvmsg_set_sequence (kvmsg, ++self->sequence); kvmsg_send (kvmsg, self->publisher); kvmsg_store (&kvmsg, self->kvmap); zclock_log ("I: publishing pending=%d", (int) self->sequence); } return 0; }
static void peering_lower (peering_t *self) { vocket_t *vocket = self->vocket; driver_t *driver = self->driver; if (driver->verbose) zclock_log ("I: (tcp) take down peering to %s", self->address); if (self->alive) { self->alive = FALSE; zlist_remove (vocket->live_peerings, self); if (zlist_size (vocket->live_peerings) < vocket->min_peerings) { // Ask reactor to stop monitoring vocket's msgpipe pipe zmq_pollitem_t item = { vocket->msgpipe, 0, ZMQ_POLLIN, 0 }; zloop_poller_end (driver->loop, &item); } // current_peering cannot receive messages any more if (vocket->current_peering == self) vocket->current_peering = NULL; // Make sure we are not subscribed anymore (makes sense for SUB // socket only) self->subscribed = FALSE; } }
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; }
/// // Cancel a pollitem from the reactor, specified by socket or FD. If both // are specified, uses only socket. If multiple poll items exist for same // socket/FD, cancels ALL of them. void QmlZloop::pollerEnd (zmq_pollitem_t *item) { zloop_poller_end (self, item); };
// This function is called when a message is ready to be read on the specified //connection. The connection is registered with the URI if needed. int maltcp_ctx_socket_receive(zloop_t *loop, zmq_pollitem_t *poller, void *arg) { clog_debug(maltcp_logger, "maltcp_ctx_socket_receive\n"); maltcp_ctx_t *self = (maltcp_ctx_t *) arg; struct sockaddr src_addr; socklen_t addr_size = sizeof(struct sockaddr_in); if (getpeername(poller->fd, (struct sockaddr *)&src_addr, &addr_size) != 0) { clog_error(maltcp_logger, "maltcp_ctx_socket_receive: getpeername failed\n"); return -1; } char src_ipstr[INET6_ADDRSTRLEN]; int src_port; if (src_addr.sa_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&src_addr; src_port = ntohs(s->sin_port); inet_ntop(AF_INET, &s->sin_addr, src_ipstr, sizeof src_ipstr); } else { // AF_INET6 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&src_addr; src_port = ntohs(s->sin6_port); inet_ntop(AF_INET6, &s->sin6_addr, src_ipstr, sizeof src_ipstr); } mal_uri_t peer_uri[strlen(src_ipstr) + 10 + 10 + 1]; sprintf((char*) peer_uri, "%s%s:%d", MALTCP_URI, src_ipstr, src_port); clog_debug(maltcp_logger, "maltcp_ctx: TCP server socket receive from URI: %s\n", peer_uri); char header[FIXED_HEADER_LENGTH]; int nb = 0; while (nb < FIXED_HEADER_LENGTH) { int nbread = recv(poller->fd, &header[nb], FIXED_HEADER_LENGTH-nb, 0); if (nbread == 0) { clog_warning(maltcp_logger, "maltcp_ctx_socket_receive: TCP connection (%d) closed\n", poller->fd); maltcp_ctx_connection_remove_socket(self, poller->fd); zloop_poller_end(loop, poller); close(poller->fd); return 0; } if (nbread <0) { clog_error(maltcp_logger, "maltcp_ctx_socket_receive: Error reading header on TCP connection\n"); maltcp_ctx_connection_remove_socket(self, poller->fd); zloop_poller_end(loop, poller); close(poller->fd); return -1; } nb += nbread; } // First read, get the message size in the header int msg_size = maltcp_decode_variable_length(header, nb) + FIXED_HEADER_LENGTH; clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: should read = %d bytes\n", msg_size); // Allocate the message and copy header char* msg = (char*) malloc(msg_size); memcpy(msg, header, FIXED_HEADER_LENGTH); // Read the whole message while (nb < msg_size) { int nbread = recv(poller->fd, &msg[nb], msg_size-nb, 0); if (nbread <=0) { clog_error(maltcp_logger, "maltcp_ctx_socket_receive: Error reading message on TCP connection\n"); maltcp_ctx_connection_remove_socket(self, poller->fd); zloop_poller_end(loop, poller); close(poller->fd); free(msg); return -1; } nb += nbread; } clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: message received, size = %d\n", msg_size); // Get URIs from message and register connection if needed mal_uri_t *uri_to; mal_uri_t *uri_from; if (maltcp_decode_uris(self->maltcp_header, self->decoder, msg, msg_size, &uri_to, &uri_from) != 0) { clog_error(maltcp_logger, "maltcp_ctx_socket_receive, could not decode uri_to\n"); return -1; } clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: uri_to=%s uri_from=%s\n", uri_to, uri_from); if ((uri_from != NULL) && (strncmp(uri_from, MALTCP_URI, sizeof MALTCP_URI -1) == 0)) { // The complete URI is registered in the message header, use it. int len = strlen(uri_from); char *ptr = strchr(uri_from +sizeof MALTCP_URI, '/'); if (ptr != NULL) len = ptr-uri_from; char uri[len+1]; strncpy(uri, uri_from, len); uri[len] = '\0'; clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: register#1 %s\n", uri); // Register the connection if needed maltcp_ctx_connection_register_incoming(self, poller->fd, uri); } else { clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: register#2 %s\n", peer_uri); // Register the connection if needed maltcp_ctx_connection_register_incoming(self, poller->fd, peer_uri); } // Forward the message to the appropriate endpoint. // Note: Normally the message will be deleted by the appropriate endpoint. // What happens if no endpoint reads this message? It seems that Router socket // discard messages if there are no readers. assert(uri_to != NULL); // Get the service part of URI needed to route the message. mal_uri_t *short_uri_to = maltcp_get_service_from_uri(uri_to); int rc = zmq_send(self->endpoints_socket, short_uri_to, strlen(short_uri_to), ZMQ_SNDMORE); assert(rc == strlen(short_uri_to)); clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: send identity (%d bytes) to endpoint %s\n", rc, short_uri_to); // Send the peer URI rc = zmq_send(self->endpoints_socket, peer_uri, strlen(peer_uri), ZMQ_SNDMORE); assert(rc == strlen(peer_uri)); clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: send peer URI (%d bytes) to endpoint %s\n", rc, peer_uri); // Send the message clog_debug(maltcp_logger, "maltcp_ctx_socket_receive: send message (%d bytes) to endpoint %s\n", msg_size, short_uri_to); rc = zmq_send(self->endpoints_socket, msg, msg_size, ZMQ_DONTWAIT); assert(rc == msg_size); clog_debug(maltcp_logger, "maltcp_ctx: message handled.\n"); // Destroy URIs: Be careful, short_uri_to is simply a pointer in uri_to. mal_uri_destroy(&uri_to); mal_uri_destroy(&uri_from); 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 (!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; // 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; }