/* Timer pops every 1 ms, writing a new value to key. * After 10 calls, it calls kvs_unwatch(). * After 20 calls, it calls flux_reactor_stop(). * The kvs_unwatch_cb() counts the number of times it is called, should be 10. */ void test_unwatch (int argc, char **argv) { struct timer_ctx ctx; flux_reactor_t *r; int count = 0; flux_watcher_t *timer; if (argc != 1) { fprintf (stderr, "Usage: unwatch key\n"); exit (1); } ctx.key = argv[0]; if (!(ctx.h = flux_open (NULL, 0))) log_err_exit ("flux_open"); r = flux_get_reactor (ctx.h); if (kvs_watch_int (ctx.h, ctx.key, unwatch_watch_cb, &count) < 0) log_err_exit ("kvs_watch_int %s", ctx.key); if (!(timer = flux_timer_watcher_create (r, 0.001, 0.001, unwatch_timer_cb, &ctx))) log_err_exit ("flux_timer_watcher_create"); flux_watcher_start (timer); if (flux_reactor_run (r, 0) < 0) log_err_exit ("flux_reactor_run"); if (count != 10) log_msg_exit ("watch called %d times (should be 10)", count); flux_watcher_destroy (timer); flux_close (ctx.h); }
int hello_start (hello_t *hello) { int rc = -1; uint32_t rank; if (flux_get_rank (hello->h, &rank) < 0) goto done; if (rank == 0) { monotime (&hello->start); if (!(hello->timer = flux_timer_watcher_create (hello->reactor, hello->timeout, hello->timeout, timer_cb, hello))) goto done; flux_watcher_start (hello->timer); if (hello_add_rank (hello, 0) < 0) goto done; } else { if (hello_sendmsg (hello, rank) < 0) goto done; } rc = 0; done: return rc; }
int heartbeat_start (heartbeat_t *hb) { uint32_t rank; struct flux_match match = FLUX_MATCH_EVENT; if (!hb->h) { errno = EINVAL; return -1; } if (flux_get_rank (hb->h, &rank) < 0) return -1; if (rank == 0) { flux_reactor_t *r = flux_get_reactor (hb->h); flux_reactor_now_update (r); if (!(hb->timer = flux_timer_watcher_create (r, hb->rate, hb->rate, timer_cb, hb))) return -1; flux_watcher_start (hb->timer); } match.topic_glob = "hb"; if (!(hb->mh = flux_msg_handler_create (hb->h, match, event_cb, hb))) return -1; flux_msg_handler_start (hb->mh); return 0; }
static ctx_t *getctx (flux_t *h) { ctx_t *ctx = (ctx_t *)flux_aux_get (h, "flux::barrier"); if (!ctx) { ctx = xzmalloc (sizeof (*ctx)); if (!(ctx->barriers = zhash_new ())) { errno = ENOMEM; goto error; } if (flux_get_rank (h, &ctx->rank) < 0) { flux_log_error (h, "flux_get_rank"); goto error; } if (!(ctx->timer = flux_timer_watcher_create (flux_get_reactor (h), barrier_reduction_timeout_sec, 0., timeout_cb, ctx) )) { flux_log_error (h, "flux_timer_watacher_create"); goto error; } ctx->h = h; flux_aux_set (h, "flux::barrier", ctx, freectx); } return ctx; error: freectx (ctx); return NULL; }
static void test_timer (flux_reactor_t *reactor) { flux_watcher_t *w; errno = 0; ok (!flux_timer_watcher_create (reactor, -1, 0, oneshot, NULL) && errno == EINVAL, "timer: creating negative timeout fails with EINVAL"); ok (!flux_timer_watcher_create (reactor, 0, -1, oneshot, NULL) && errno == EINVAL, "timer: creating negative repeat fails with EINVAL"); ok ((w = flux_timer_watcher_create (reactor, 0, 0, oneshot, NULL)) != NULL, "timer: creating zero timeout works"); flux_watcher_start (w); ok (flux_reactor_run (reactor, 0) == 0, "timer: reactor ran to completion (single oneshot)"); ok (oneshot_ran == true, "timer: oneshot was executed"); oneshot_ran = false; ok (flux_reactor_run (reactor, 0) == 0, "timer: reactor ran to completion (expired oneshot)"); ok (oneshot_ran == false, "timer: expired oneshot was not re-executed"); errno = 0; oneshot_errno = ESRCH; flux_watcher_start (w); ok (flux_reactor_run (reactor, 0) < 0 && errno == ESRCH, "general: reactor stop_error worked with errno passthru"); flux_watcher_stop (w); flux_watcher_destroy (w); ok ((w = flux_timer_watcher_create (reactor, 0.01, 0.01, repeat, NULL)) != NULL, "timer: creating 1ms timeout with 1ms repeat works"); flux_watcher_start (w); ok (flux_reactor_run (reactor, 0) == 0, "timer: reactor ran to completion (single repeat)"); ok (repeat_countdown == 0, "timer: repeat timer stopped itself after countdown"); flux_watcher_stop (w); flux_watcher_destroy (w); }
void *watchthread (void *arg) { thd_t *t = arg; watch_count_t wc; flux_kvs_txn_t *txn; flux_future_t *f; flux_reactor_t *r; flux_watcher_t *pw = NULL; flux_watcher_t *tw = NULL; if (!(t->h = flux_open (NULL, 0))) log_err_exit ("flux_open"); /* Make sure key doesn't already exist, initial value may affect * test by chance (i.e. initial value = 0, commit 0 and thus no * change) */ if (!(txn = flux_kvs_txn_create ())) log_err_exit ("flux_kvs_txn_create"); if (flux_kvs_txn_unlink (txn, 0, key) < 0) log_err_exit ("flux_kvs_txn_unlink"); if (!(f = flux_kvs_commit (t->h, 0, txn)) || flux_future_get (f, NULL) < 0) log_err_exit ("flux_kvs_commit"); flux_future_destroy (f); flux_kvs_txn_destroy (txn); r = flux_get_reactor (t->h); if (flux_kvs_watch (t->h, key, watch_count_cb, t) < 0) log_err_exit ("flux_kvs_watch %s", key); pw = flux_prepare_watcher_create (r, watch_prepare_cb, NULL); wc.t = t; wc.lastcount = -1; /* So test won't hang if there's a bug */ tw = flux_timer_watcher_create (r, WATCH_TIMEOUT, WATCH_TIMEOUT, watch_timeout_cb, &wc); flux_watcher_start (pw); flux_watcher_start (tw); if (flux_reactor_run (r, 0) < 0) log_err_exit ("flux_reactor_run"); flux_watcher_destroy (pw); flux_watcher_destroy (tw); flux_close (t->h); return NULL; }
static int runlevel_start_subprocess (runlevel_t *r, int level) { flux_subprocess_t *p = NULL; assert (r->h != NULL); if (r->rc[level].cmd) { flux_subprocess_ops_t ops = { .on_completion = completion_cb, .on_state_change = NULL, .on_channel_out = NULL, .on_stdout = NULL, .on_stderr = NULL, }; flux_reactor_t *reactor = flux_get_reactor (r->h); int flags = 0; /* set alternate io callback for levels 1 and 3 */ if (level == 1 || level == 3) { ops.on_stdout = io_cb; ops.on_stderr = io_cb; } else flags |= FLUX_SUBPROCESS_FLAGS_STDIO_FALLTHROUGH; if (!(p = flux_exec (r->h, flags, r->rc[level].cmd, &ops))) goto error; if (flux_subprocess_aux_set (p, "runlevel", r, NULL) < 0) goto error; monotime (&r->rc[level].start); if (r->rc[level].timeout > 0.) { flux_watcher_t *w; if (!(w = flux_timer_watcher_create (reactor, r->rc[level].timeout, 0., runlevel_timeout, r))) goto error; flux_watcher_start (w); r->rc[level].timer = w; flux_log (r->h, LOG_INFO, "runlevel %d (%.1fs) timer started", level, r->rc[level].timeout); } r->rc[level].p = p; } else {
static void event_handler (flux_t *h, flux_msg_handler_t *w, const flux_msg_t *msg, void *arg) { cron_entry_t *e = arg; struct cron_event *ev = cron_entry_type_data (e); ev->counter++; if (ev->paused) return; /* * Determine if we should run the cron task on this event * based on the current values for "after" and "nth". * If ev->after is set, then only run for the first time * after we've seen this many events. If ev->nth is set, * only run every nth event starting with 'after'. */ if (ev->counter < ev->after) return; if (ev->nth && ((ev->counter - ev->after) % ev->nth)) return; if (ev->min_interval > 0.) { double now = get_timestamp (); double remaining = ev->min_interval - (now - e->stats.lastrun); if (remaining > 1e-5) { flux_reactor_t *r = flux_get_reactor (h); flux_watcher_t *w; if (!(w = flux_timer_watcher_create (r, remaining, 0., ev_timer_cb, (void *) e))) flux_log_error (h, "timer_watcher_create"); else { /* Pause the event watcher. Continue to count events but * don't run anything until we unpause. */ ev->paused = 1; flux_watcher_start (w); flux_log (h, LOG_DEBUG, "cron-%ju: delaying %4.03fs due to min interval", e->id, remaining); } return; } } cron_entry_schedule_task (e); }
int shutdown_recvmsg (shutdown_t *s, const flux_msg_t *msg) { int rc = -1; if (!s->w) { if (shutdown_decode (msg, &s->grace, &s->rc, &s->rank, s->reason, sizeof (s->reason)) < 0) goto done; if (!(s->w = flux_timer_watcher_create (s->grace, 0., shutdown_cb, s))) goto done; flux_timer_watcher_start (s->h, s->w); if (flux_rank (s->h) == 0) flux_log (s->h, LOG_INFO, "%d: shutdown in %.3fs: %s", s->rank, s->grace, s->reason); } rc = 0; done: return rc; }
/* On receipt of the shutdown event message, begin the grace timer, * and log the "shutdown in..." message on rank 0. */ void shutdown_handler (flux_t h, flux_msg_handler_t *w, const flux_msg_t *msg, void *arg) { shutdown_t *s = arg; if (!s->timer) { if (shutdown_decode (msg, &s->grace, &s->rc, &s->rank, s->reason, sizeof (s->reason)) < 0) { flux_log_error (h, "shutdown event"); return; } if (!(s->timer = flux_timer_watcher_create (flux_get_reactor (s->h), s->grace, 0., timer_handler, s))) { flux_log_error (h, "shutdown timer creation"); return; } flux_watcher_start (s->timer); if (s->myrank == 0) flux_log (s->h, LOG_INFO, "shutdown in %.3fs: %s", s->grace, s->reason); } }
int main (int argc, char *argv[]) { int ch; int pad_bytes = 0; char *target; flux_watcher_t *tw = NULL; struct ping_ctx ctx = { .period = 1.0, .rank = NULL, .nodeid = FLUX_NODEID_ANY, .topic = NULL, .pad = NULL, .count = -1, .send_count = 0, .batch = false, }; log_init ("flux-ping"); while ((ch = getopt_long (argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (ch) { case 'h': /* --help */ usage (); break; case 'p': /* --pad bytes */ pad_bytes = strtoul (optarg, NULL, 10); break; case 'd': /* --delay seconds */ ctx.period = strtod (optarg, NULL); if (ctx.period < 0) usage (); break; case 'r': /* --rank NODESET */ ctx.rank = optarg; break; case 'c': /* --count N */ ctx.count = strtoul (optarg, NULL, 10); break; case 'b': /* --batch-request */ ctx.batch = true; break; default: usage (); break; } } if (optind != argc - 1) usage (); if (ctx.batch && ctx.count == -1) log_msg_exit ("--batch should only be used with --count"); target = argv[optind++]; /* Create null terminated pad string for reuse in each message. * By default it's the empty string. */ ctx.pad = xzmalloc (pad_bytes + 1); memset (ctx.pad, 'p', pad_bytes); /* If "rank!" is prepended to the target, and there is no --rank * argument, snip it off and set the rank. If it's just the bare * rank, assume the target is "cmb". */ if (ctx.rank == NULL) { char *p; nodeset_t *ns = NULL; if ((p = strchr (target, '!'))) { *p++ = '\0'; ctx.rank = target; target = p; } else if ((ns = nodeset_create_string (target)) != NULL) { ctx.rank = target; target = "cmb"; nodeset_destroy (ns); } else if (!strcmp (target, "all")) { ctx.rank = target; target = "cmb"; } } /* Use singleton rpc if there's only one nodeid */ if (ctx.rank != NULL) { nodeset_t *ns = nodeset_create_string (ctx.rank); if (ns) { if (nodeset_count (ns) == 1) { ctx.nodeid = nodeset_min (ns); ctx.rank = NULL; } nodeset_destroy (ns); } } ctx.topic = xasprintf ("%s.ping", target); if (!(ctx.h = flux_open (NULL, 0))) log_err_exit ("flux_open"); if (!(ctx.reactor = flux_get_reactor (ctx.h))) log_err_exit ("flux_get_reactor"); /* In batch mode, requests are sent before reactor is started * to process responses. o/w requests are set in a timer watcher. */ if (ctx.batch) { while (ctx.send_count < ctx.count) { send_ping (&ctx); usleep ((useconds_t)(ctx.period * 1E6)); } } else { tw = flux_timer_watcher_create (ctx.reactor, ctx.period, ctx.period, timer_cb, &ctx); if (!tw) log_err_exit ("error creating watchers"); flux_watcher_start (tw); } if (flux_reactor_run (ctx.reactor, 0) < 0) log_err_exit ("flux_reactor_run"); /* Clean up. */ flux_watcher_destroy (tw); free (ctx.topic); free (ctx.pad); flux_close (ctx.h); log_fini (); return 0; }