+ /* clean up any processes that have completed */
+ tids_sweep_procs(tids);
+ return 0;
+}
+
+/**
+ * Clean up any finished TID request processes
+ *
+ * This is called by the main process after forking each TID request. If you want to be
+ * sure finished processes are cleaned up promptly even during a lull in TID requests,
+ * this can be called from the main thread of the main process. It is not thread-safe,
+ * so should not be used from sub-threads. It should not be called by child processes -
+ * this would probably be harmless but ineffective.
+ *
+ * @param tids
+ */
+void tids_sweep_procs(TIDS_INSTANCE *tids)
+{
+ guint ii;
+ struct tid_process tp = {0};
+ char result[TIDS_MAX_MESSAGE_LEN] = {0};
+ ssize_t result_len;
+ int status;
+ int wait_rc;
+
+ /* loop backwards over the array so we can remove elements as we go */
+ for (ii=tids->pids->len; ii > 0; ii--) {
+ /* ii-1 is the current index - get our own copy, we may destroy the list's copy */
+ tp = g_array_index(tids->pids, struct tid_process, ii-1);
+
+ wait_rc = waitpid(tp.pid, &status, WNOHANG);
+ if (wait_rc == 0)
+ continue; /* process still running */
+
+ if (wait_rc < 0) {
+ /* invalid options will probably keep being invalid, report that condition */
+ if(errno == EINVAL)
+ tr_crit("tids_sweep_procs: waitpid called with invalid options");
+
+ /* If we got ECHILD, that means the PID was invalid; we'll assume the process was
+ * terminated and we missed it. For all other errors, move on
+ * to the next PID to check. */
+ if (errno != ECHILD)
+ continue;
+
+ tr_warning("tid_sweep_procs: TID process %d disappeared", tp.pid);
+ }
+
+ /* remove the item (we still have a copy of the data) */
+ g_array_remove_index_fast(tids->pids, ii-1); /* disturbs only indices >= ii-1 which we've already handled */
+
+ /* Report exit status unless we got ECHILD above or somehow waitpid returned the wrong pid */
+ if (wait_rc == tp.pid) {
+ if (WIFEXITED(status)) {
+ tr_debug("tids_sweep_procs: TID process %d exited with status %d.", tp.pid, WTERMSIG(status));
+ } else if (WIFSIGNALED(status)) {
+ tr_debug("tids_sweep_procs: TID process %d terminated by signal %d.", tp.pid, WTERMSIG(status));
+ }
+ } else if (wait_rc > 0) {
+ tr_err("tids_sweep_procs: waitpid returned pid %d, expected %d", wait_rc, tp.pid);
+ }
+
+ /* read the pipe - if the TID request worked, it will have written status before terminating */
+ result_len = read(tp.read_fd, result, TIDS_MAX_MESSAGE_LEN);
+ close(tp.read_fd);
+
+ if ((result_len > 0) && (strcmp(result, TIDS_SUCCESS_MESSAGE) == 0)) {
+ tids->req_count++;
+ tr_info("tids_sweep_procs: TID process %d exited successfully.", tp.pid);
+ } else {
+ tids->error_count++;
+ tr_info("tids_sweep_procs: TID process %d exited with an error.", tp.pid);
+ }
+ }
+}
+
+/* Process tids requests forever. Should not return except on error. */
+int tids_start (TIDS_INSTANCE *tids,
+ TIDS_REQ_FUNC *req_handler,
+ tids_auth_func *auth_handler,
+ const char *hostname,
+ unsigned int port,
+ void *cookie)
+{
+ int fd[TR_MAX_SOCKETS]={0};
+ nfds_t n_fd=0;
+ struct pollfd poll_fd[TR_MAX_SOCKETS]={{0}};
+ int ii=0;
+
+ n_fd = tids_get_listener(tids, req_handler, auth_handler, hostname, port, cookie, fd, TR_MAX_SOCKETS);
+ if (n_fd <= 0) {