return 0;
}
-#ifdef USE_WINSOCK
/**
* This routine polls a socket for readiness.
* @param fd: file descriptor, -1 uses no fd for a timer only.
*event = 1;
return 1;
}
-#endif /* USE_WINSOCK */
+
+/** fast reload convert fast reload notification status to string */
+static const char*
+fr_notification_to_string(enum fast_reload_notification status)
+{
+ switch(status) {
+ case fast_reload_notification_none:
+ return "none";
+ case fast_reload_notification_done:
+ return "done";
+ case fast_reload_notification_done_error:
+ return "done_error";
+ case fast_reload_notification_exit:
+ return "exit";
+ case fast_reload_notification_exited:
+ return "exited";
+ case fast_reload_notification_printout:
+ return "printout";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+/** fast reload, poll for notification incoming. True if quit */
+static int
+fr_poll_for_quit(struct fast_reload_thread* fr)
+{
+ int inevent, loopexit = 0;
+ uint32_t cmd;
+ ssize_t ret;
+
+ /* Is there data? */
+ if(!sock_poll_timeout(fr->commpair[1], 0, 1, 0, &inevent)) {
+ log_err("fr_poll_for_quit: poll failed");
+ return 0;
+ }
+ if(!inevent)
+ return 0;
+
+ /* Read the data */
+ while(1) {
+ if(++loopexit > 200) {
+ log_err("fr_poll_for_quit: recv loops %s",
+ sock_strerror(errno));
+ return 0;
+ }
+ ret = recv(fr->commpair[1], &cmd, sizeof(cmd), 0);
+ if(ret == -1) {
+ if(
+#ifndef USE_WINSOCK
+ errno == EINTR || errno == EAGAIN
+# ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK
+# endif
+#else
+ WSAGetLastError() == WSAEINTR ||
+ WSAGetLastError() == WSAEINPROGRESS ||
+ WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+ )
+ continue; /* Try again. */
+ log_err("fr_poll_for_quit: recv: %s",
+ sock_strerror(errno));
+ return 0;
+ } if(ret != sizeof(cmd)) {
+ log_err("fr_poll_for_quit: partial read");
+ return 0;
+ }
+ break;
+ }
+ if(cmd == fast_reload_notification_exit) {
+ fr->need_to_quit = 1;
+ verbose(VERB_ALGO, "fast reload: exit notification received");
+ return 1;
+ }
+ log_err("fr_poll_for_quit: unknown notification status received: %d %s",
+ cmd, fr_notification_to_string(cmd));
+ return 0;
+}
+
+/** fast reload thread. Send notification from the fast reload thread */
+static void
+fr_send_notification(struct fast_reload_thread* fr,
+ enum fast_reload_notification status)
+{
+ int outevent, loopexit = 0;
+ uint32_t cmd;
+ ssize_t ret;
+ verbose(VERB_ALGO, "fast reload: send notification %s",
+ fr_notification_to_string(status));
+ /* Make a blocking attempt to send. But meanwhile stay responsive,
+ * once in a while for quit commands. In case the server has to quit. */
+ /* see if there is incoming quit signals */
+ if(fr_poll_for_quit(fr))
+ return;
+ while(1) {
+ if(++loopexit > 200) {
+ log_err("fast reload: could not send notification");
+ return;
+ }
+ if(!sock_poll_timeout(fr->commpair[1], 200, 0, 1, &outevent)) {
+ log_err("fast reload: poll failed");
+ return;
+ }
+ if(fr_poll_for_quit(fr))
+ return;
+ if(!outevent)
+ continue;
+ cmd = status;
+ ret = send(fr->commpair[1], &cmd, sizeof(cmd), 0);
+ if(ret == -1) {
+ if(
+#ifndef USE_WINSOCK
+ errno == EINTR || errno == EAGAIN
+# ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK
+# endif
+#else
+ WSAGetLastError() == WSAEINTR ||
+ WSAGetLastError() == WSAEINPROGRESS ||
+ WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+ )
+ continue; /* Try again. */
+ log_err("fast reload send notification: send: %s",
+ sock_strerror(errno));
+ return;
+ } else if(ret != sizeof(cmd)) {
+ log_err("fast reload send notification: partial send");
+ return;
+ }
+ break;
+ }
+}
#ifndef THREADS_DISABLED
/** fast reload thread. the thread main function */
verbose(VERB_ALGO, "start fast reload thread");
+ if(fr_poll_for_quit(fast_reload_thread))
+ goto done;
+
verbose(VERB_ALGO, "stop fast reload thread");
+ /* If this is not an exit due to quit earlier, send regular done. */
+ if(!fast_reload_thread->need_to_quit)
+ fr_send_notification(fast_reload_thread,
+ fast_reload_notification_done);
+ /* If during the fast_reload_notification_done send,
+ * fast_reload_notification_exit was received, ack it. If the
+ * thread is exiting due to quit received earlier, also ack it.*/
+done:
+ if(fast_reload_thread->need_to_quit)
+ fr_send_notification(fast_reload_thread,
+ fast_reload_notification_exited);
return NULL;
}
#endif /* !THREADS_DISABLED */
};
typedef struct remote_stream RES;
+/**
+ * Notification status. This is exchanged between the fast reload thread
+ * and the server thread, over the commpair sockets.
+ */
+enum fast_reload_notification {
+ /** nothing, not used */
+ fast_reload_notification_none = 0,
+ /** the fast reload thread is done */
+ fast_reload_notification_done = 1,
+ /** the fast reload thread is done but with an error, it failed */
+ fast_reload_notification_done_error = 2,
+ /** the fast reload thread is told to exit by the server thread.
+ * Sent on server quit while the reload is running. */
+ fast_reload_notification_exit = 3,
+ /** the fast reload thread has exited, after being told to exit */
+ fast_reload_notification_exited = 4,
+ /** the fast reload thread has information to print out */
+ fast_reload_notification_printout = 5
+};
+
/**
* Fast reload thread structure
*/
ub_thread_type tid;
/** if the io processing has started */
int started;
+ /** if the thread has to quit */
+ int need_to_quit;
/** the event that listens on the remote service worker to the
* commpair, it receives content from the fast reload thread. */