int zloop_poller (zloop_t *self, zmq_pollitem_t *item, zloop_fn handler, void *arg) { assert (self); if (item->socket && streq (zsys_sockname (zsock_type (item->socket)), "UNKNOWN")) return -1; s_poller_t *poller = s_poller_new (item, handler, arg); if (poller) { poller->list_handle = zlistx_add_end (self->pollers, poller); if (!poller->list_handle) { s_poller_destroy (&poller); return -1; } self->need_rebuild = true; if (self->verbose) zsys_debug ("zloop: register %s poller (%p, %d)", item->socket ? zsys_sockname (zsock_type (item->socket)) : "FD", item->socket, item->fd); return 0; } else return -1; }
JNIEXPORT jstring JNICALL Java_org_zeromq_czmq_Zsys__1_1sockname (JNIEnv *env, jclass c, jint socktype) { char *sockname_ = (char *) zsys_sockname ((int) socktype); jstring return_string_ = (*env)->NewStringUTF (env, sockname_); return return_string_; }
void zloop_poller_end (zloop_t *self, zmq_pollitem_t *item) { assert (self); s_poller_t *poller = (s_poller_t *) zlistx_first (self->pollers); while (poller) { bool match = false; if (item->socket) { if (item->socket == poller->item.socket) match = true; } else { if (item->fd == poller->item.fd) match = true; } if (match) { zlistx_delete (self->pollers, poller->list_handle); // Force rebuild to avoid reading from freed poller self->need_rebuild = true; } poller = (s_poller_t *) zlistx_next (self->pollers); } if (self->verbose) zsys_debug ("zloop: cancel %s poller (%p, %d)", item->socket ? zsys_sockname (zsock_type (item->socket)) : "FD", item->socket, item->fd); }
// atexit or manual termination for the process void zsys_shutdown (void) { if (!s_initialized) { return; } s_initialized = false; // The atexit handler is called when the main function exits; // however we may have zactor threads shutting down and still // trying to close their sockets. So if we suspect there are // actors busy (s_open_sockets > 0), then we sleep for a few // hundred milliseconds to allow the actors, if any, to get in // and close their sockets. ZMUTEX_LOCK (s_mutex); size_t busy = s_open_sockets; ZMUTEX_UNLOCK (s_mutex); if (busy) zclock_sleep (200); // No matter, we are now going to shut down // Print the source reference for any sockets the app did not // destroy properly. ZMUTEX_LOCK (s_mutex); s_sockref_t *sockref = (s_sockref_t *) zlist_pop (s_sockref_list); while (sockref) { assert (sockref->filename); zsys_error ("dangling '%s' socket created at %s:%d", zsys_sockname (sockref->type), sockref->filename, (int) sockref->line_nbr); zmq_close (sockref->handle); free (sockref); sockref = (s_sockref_t *) zlist_pop (s_sockref_list); } zlist_destroy (&s_sockref_list); ZMUTEX_UNLOCK (s_mutex); // Close logsender socket if opened (don't do this in critical section) if (s_logsender) { zsys_close (s_logsender, NULL, 0); s_logsender = NULL; } if (s_open_sockets == 0) zmq_term (s_process_ctx); else zsys_error ("dangling sockets: cannot terminate ZMQ safely"); ZMUTEX_DESTROY (s_mutex); // Free dynamically allocated properties free (s_interface); free (s_logident); #if defined (__UNIX__) closelog (); // Just to be pedantic #endif }
const char * zsocket_type_str (void *self) { assert (self); return zsys_sockname (zsocket_type (self)); }
/// // Return ZMQ socket name for socket type // *** This is for CZMQ internal use only and may change arbitrarily *** const QString QmlZsysAttached::sockname (int socktype) { return QString (zsys_sockname (socktype)); };
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; }
/// // Return ZMQ socket name for socket type // *** This is for CZMQ internal use only and may change arbitrarily *** const QString QZsys::sockname (int socktype) { const QString rv = QString (zsys_sockname (socktype)); return rv; }