NN_C99_INLINE void thread_state_awake (struct thread_state1 *ts1) { vtime_t vt = ts1->vtime; vtime_t wd = ts1->watchdog; if (vtime_asleep_p (vt)) ts1->vtime = vt + 1; else { pa_membar_exit (); ts1->vtime = vt + 2; } pa_membar_enter (); if ( wd % 2 ){ ts1->watchdog = wd + 1; } else { ts1->watchdog = wd + 2; } }
static void *lease_renewal_thread (struct nn_servicelease *sl) { /* Do not check more often than once every 100ms (no particular reason why it has to be 100ms), regardless of the lease settings. Note: can't trust sl->self, may have been scheduled before the assignment. */ const os_int64 min_progress_check_intv = 100 * T_MILLISECOND; struct thread_state1 *self = lookup_thread_state (); nn_mtime_t next_thread_cputime = { 0 }; nn_mtime_t tlast = { 0 }; int was_alive = 1; unsigned i; for (i = 0; i < thread_states.nthreads; i++) { sl->av_ary[i].alive = 1; sl->av_ary[i].wd = thread_states.ts[i].watchdog - 1; } os_mutexLock (&sl->lock); while (sl->keepgoing) { unsigned n_alive = 0; nn_mtime_t tnow = now_mt (); LOG_THREAD_CPUTIME (next_thread_cputime); TRACE (("servicelease: tnow %"PA_PRId64":", tnow.v)); /* Check progress only if enough time has passed: there is no guarantee that os_cond_timedwait wont ever return early, and we do want to avoid spurious warnings. */ if (tnow.v < tlast.v + min_progress_check_intv) { n_alive = thread_states.nthreads; } else { tlast = tnow; for (i = 0; i < thread_states.nthreads; i++) { if (thread_states.ts[i].state != THREAD_STATE_ALIVE) n_alive++; else { vtime_t vt = thread_states.ts[i].vtime; vtime_t wd = thread_states.ts[i].watchdog; int alive = vtime_asleep_p (vt) || vtime_asleep_p (wd) || vtime_gt (wd, sl->av_ary[i].wd); n_alive += (unsigned) alive; TRACE ((" %d(%s):%c:%u:%u->%u:", i, thread_states.ts[i].name, alive ? 'a' : 'd', vt, sl->av_ary[i].wd, wd)); sl->av_ary[i].wd = wd; if (sl->av_ary[i].alive != alive) { const char *name = thread_states.ts[i].name; const char *msg; if (!alive) msg = "failed to make progress"; else msg = "once again made progress"; NN_WARNING2 ("thread %s %s\n", name ? name : "(anon)", msg); sl->av_ary[i].alive = (char) alive; } } } } /* Only renew the lease if all threads are alive, so that one thread blocking for a while but not too extremely long will cause warnings for that thread in the log file, but won't cause the DDSI2 service to be marked as dead. */ if (n_alive == thread_states.nthreads) { TRACE ((": [%d] renewing\n", n_alive)); /* FIXME: perhaps it would be nice to control automatic liveliness updates from here. FIXME: should terminate failure of renew_cb() */ sl->renew_cb (sl->renew_arg); was_alive = 1; } else { TRACE ((": [%d] NOT renewing\n", n_alive)); if (was_alive) log_stack_traces (); was_alive = 0; } #if SYSDEPS_HAVE_GETRUSAGE /* If getrusage() is available, use it to log CPU and memory statistics to the trace. Getrusage() can't fail if the parameters are valid, and these are by the book. Still we check. */ if (config.enabled_logcats & LC_TIMING) { struct rusage u; if (getrusage (RUSAGE_SELF, &u) == 0) { nn_log (LC_TIMING, "rusage: utime %d.%06d stime %d.%06d maxrss %ld data %ld vcsw %ld ivcsw %ld\n", (int) u.ru_utime.tv_sec, (int) u.ru_utime.tv_usec, (int) u.ru_stime.tv_sec, (int) u.ru_stime.tv_usec, u.ru_maxrss, u.ru_idrss, u.ru_nvcsw, u.ru_nivcsw); } } #endif os_condTimedWait (&sl->cond, &sl->lock, sl->sleepTime); /* We are never active in a way that matters for the garbage collection of old writers, &c. */ thread_state_asleep (self); } os_mutexUnlock (&sl->lock); return NULL; }