static void deregister_the_client (client_t *self) { // If the client never sent CONNECTION_OPEN then self->address was // never set, so avoid trying to dereference it. Nothing needs to // be cleaned up. if (self->address) { if (*self->address) zsys_info ("client %u address='%s' - de-registering", self->unique_id, self->address); // Cancel all stream subscriptions stream_t *stream = (stream_t *) zlistx_detach (self->readers, NULL); while (stream) { zsock_send (stream->actor, "sp", "CANCEL", self); stream = (stream_t *) zlistx_detach (self->readers, NULL); } // Cancel all service offerings service_t *service = (service_t *) zhashx_first (self->server->services); while (service) { offer_t *offer = (offer_t *) zlistx_first (service->offers); while (offer) { if (offer->client == self) zlistx_delete (service->offers, zlistx_cursor (service->offers)); offer = (offer_t *) zlistx_next (service->offers); } service = (service_t *) zhashx_next (self->server->services); } if (*self->address) zhashx_delete (self->server->clients, self->address); } mlm_proto_set_status_code (self->message, MLM_PROTO_SUCCESS); }
static void deregister_the_client (client_t *self) { if (*self->address) zsys_info ("client address='%s' - de-registering", self->address); // Cancel all stream subscriptions stream_t *stream = (stream_t *) zlistx_detach (self->readers, NULL); while (stream) { zsock_send (stream->actor, "sp", "CANCEL", self); stream = (stream_t *) zlistx_detach (self->readers, NULL); } // Cancel all service offerings service_t *service = (service_t *) zhashx_first (self->server->services); while (service) { offer_t *offer = (offer_t *) zlistx_first (service->offers); while (offer) { if (offer->client == self) zlistx_delete (service->offers, zlistx_cursor (service->offers)); offer = (offer_t *) zlistx_next (service->offers); } service = (service_t *) zhashx_next (self->server->services); } if (*self->address) zhashx_delete (self->server->clients, self->address); mlm_proto_set_status_code (self->message, MLM_PROTO_SUCCESS); }
void zloop_destroy (zloop_t **self_p) { assert (self_p); if (*self_p) { zloop_t *self = *self_p; // If we never started the loop, yet manipulated timers, we'll have // a zombie 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); } zlistx_destroy (&self->zombies); zlistx_destroy (&self->readers); zlistx_destroy (&self->pollers); zlistx_destroy (&self->timers); zlistx_destroy (&self->tickets); free (self->pollset); free (self->readact); free (self->pollact); free (self); *self_p = NULL; } }
void s_service_dispatch (service_t *self) { // for each message, check regexp and dispatch if possible if (zlistx_size (self->offers)) { mlm_msg_t *message = (mlm_msg_t *) zlistx_first (self->queue); while (message) { offer_t *offer = (offer_t *) zlistx_first (self->offers); while (offer) { if (zrex_matches (offer->rex, mlm_msg_subject (message))) { client_t *target = offer->client; assert (target); assert (!target->msg); target->msg = (mlm_msg_t *) zlistx_detach ( self->queue, zlistx_cursor (self->queue)); engine_send_event (target, service_message_event); zlistx_move_end (self->offers, zlistx_cursor (self->offers)); break; } offer = (offer_t *) zlistx_next (self->offers); } message = (mlm_msg_t *) zlistx_next (self->queue); } } }
int zlistx_delete (zlistx_t *self, void *handle) { assert (self); void *item = zlistx_detach (self, handle); if (item) { if (self->destructor) self->destructor (&item); return 0; } else return -1; }
static void cancel_stream_reader (client_t *self) { // Cancel stream subscription stream_t *stream = s_stream_require (self, mlm_proto_stream (self->message)); if (stream) { zsock_send (stream->actor, "sp", "CANCEL", self); stream = (stream_t *) zlistx_detach (self->readers, NULL); } else { engine_set_exception (self, exception_event); zsys_warning ("stream does not exist"); } }
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; }
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"); }
void * zlistx_detach_cur (zlistx_t *self) { return zlistx_detach (self, zlistx_cursor (self)); }
/// // Detach an item from the list, using its handle. The item is not modified, // and the caller is responsible for destroying it if necessary. If handle is // null, detaches the first item on the list. Returns item that was detached, // or null if none was. If cursor was at item, moves cursor to previous item, // so you can detach items while iterating forwards through a list. void * QZlistx::detach (void *handle) { void * rv = zlistx_detach (self, handle); return rv; }