xmlNodePtr noit_check_state_as_xml(noit_check_t *check) { xmlNodePtr state, tmp, metrics; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *k; int klen; void *data; stats_t *c = &check->stats.current; state = xmlNewNode(NULL, (xmlChar *)"state"); NODE_CONTENT(state, "running", NOIT_CHECK_RUNNING(check)?"true":"false"); NODE_CONTENT(state, "killed", NOIT_CHECK_KILLED(check)?"true":"false"); NODE_CONTENT(state, "configured", NOIT_CHECK_CONFIGURED(check)?"true":"false"); NODE_CONTENT(state, "disabled", NOIT_CHECK_DISABLED(check)?"true":"false"); NODE_CONTENT(state, "target_ip", check->target_ip); xmlAddChild(state, (tmp = xmlNewNode(NULL, (xmlChar *)"last_run"))); if(check->stats.current.whence.tv_sec) { struct timeval f = check->stats.current.whence; struct timeval n; char timestr[20]; gettimeofday(&n, NULL); snprintf(timestr, sizeof(timestr), "%0.3f", n.tv_sec + (n.tv_usec / 1000000.0)); xmlSetProp(tmp, (xmlChar *)"now", (xmlChar *)timestr); snprintf(timestr, sizeof(timestr), "%0.3f", f.tv_sec + (f.tv_usec / 1000000.0)); xmlNodeAddContent(tmp, (xmlChar *)timestr); } if(c->available) { /* truth here means the check has been run */ char buff[20], *compiler_warning; snprintf(buff, sizeof(buff), "%0.3f", (float)c->duration/1000.0); compiler_warning = buff; NODE_CONTENT(state, "runtime", compiler_warning); } NODE_CONTENT(state, "availability", noit_check_available_string(c->available)); NODE_CONTENT(state, "state", noit_check_state_string(c->state)); NODE_CONTENT(state, "status", c->status ? c->status : ""); memset(&iter, 0, sizeof(iter)); xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics"))); while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) { char buff[256]; metric_t *m = (metric_t *)data; xmlAddChild(metrics, (tmp = xmlNewNode(NULL, (xmlChar *)"metric"))); xmlSetProp(tmp, (xmlChar *)"name", (xmlChar *)m->metric_name); buff[0] = m->metric_type; buff[1] = '\0'; xmlSetProp(tmp, (xmlChar *)"type", (xmlChar *)buff); if(m->metric_value.s) { int rv; rv = noit_stats_snprint_metric_value(buff, sizeof(buff), m); if(rv < 0) xmlSetProp(tmp, (xmlChar *)"error", (xmlChar *)"unknown type"); else xmlNodeAddContent(tmp, (xmlChar *)buff); } } return state; }
static int check_test_sweeper(eventer_t e, int mask, void *closure, struct timeval *now) { int left = 0; noit_skiplist_node *iter = NULL; sweeper_event = NULL; iter = noit_skiplist_getlist(&in_progress); while(iter) { struct check_test_closure *cl = iter->data; /* advance here, we might delete */ noit_skiplist_next(&in_progress,&iter); if(NOIT_CHECK_DISABLED(cl->check)) { if(NOIT_CHECK_SHOULD_RESOLVE(cl->check)) noit_check_resolve(cl->check); if(NOIT_CHECK_RESOLVED(cl->check)) { noit_module_t *m = noit_module_lookup(cl->check->module); cl->check->flags &= ~NP_DISABLED; if(NOIT_CHECK_SHOULD_RESOLVE(cl->check)) noitL(nldeb, "translated to %s\n", cl->check->target_ip); if(m) m->initiate_check(m, cl->check, 1, NULL); } left++; } else if(NOIT_CHECK_RUNNING(cl->check)) left++; else noit_skiplist_remove(&in_progress, cl->restc, (noit_freefunc_t)rest_test_check_result); } if(left) check_test_schedule_sweeper(); return 0; }
xmlNodePtr noit_check_state_as_xml(noit_check_t *check, int full) { xmlNodePtr state, tmp, metrics; struct timeval now, *whence; stats_t *c = noit_check_get_stats_current(check); gettimeofday(&now, NULL); state = xmlNewNode(NULL, (xmlChar *)"state"); NODE_CONTENT(state, "running", NOIT_CHECK_RUNNING(check)?"true":"false"); NODE_CONTENT(state, "killed", NOIT_CHECK_KILLED(check)?"true":"false"); NODE_CONTENT(state, "configured", NOIT_CHECK_CONFIGURED(check)?"true":"false"); NODE_CONTENT(state, "disabled", NOIT_CHECK_DISABLED(check)?"true":"false"); NODE_CONTENT(state, "target_ip", check->target_ip); xmlAddChild(state, (tmp = xmlNewNode(NULL, (xmlChar *)"last_run"))); whence = noit_check_stats_whence(c, NULL); if(whence->tv_sec) { char timestr[20]; snprintf(timestr, sizeof(timestr), "%0.3f", now.tv_sec + (now.tv_usec / 1000000.0)); xmlSetProp(tmp, (xmlChar *)"now", (xmlChar *)timestr); snprintf(timestr, sizeof(timestr), "%0.3f", whence->tv_sec + (whence->tv_usec / 1000000.0)); xmlNodeAddContent(tmp, (xmlChar *)timestr); } if(full) { stats_t *previous; struct timeval *whence; uint8_t available = noit_check_stats_available(c, NULL); if(available) { /* truth here means the check has been run */ char buff[20], *compiler_warning; snprintf(buff, sizeof(buff), "%0.3f", (float)noit_check_stats_duration(c, NULL)/1000.0); compiler_warning = buff; NODE_CONTENT(state, "runtime", compiler_warning); } NODE_CONTENT(state, "availability", noit_check_available_string(available)); NODE_CONTENT(state, "state", noit_check_state_string(noit_check_stats_state(c, NULL))); NODE_CONTENT(state, "status", noit_check_stats_status(c, NULL)); xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics"))); add_metrics_to_node(noit_check_get_stats_inprogress(check), metrics, "inprogress", 0); whence = noit_check_stats_whence(c, NULL); if(whence->tv_sec) { xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics"))); add_metrics_to_node(c, metrics, "current", 1); } previous = noit_check_get_stats_previous(check); whence = noit_check_stats_whence(previous, NULL); if(whence->tv_sec) { xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics"))); add_metrics_to_node(previous, metrics, "previous", 1); } } return state; }
int noit_check_schedule_next(noit_module_t *self, struct timeval *last_check, noit_check_t *check, struct timeval *now, dispatch_func_t dispatch, noit_check_t *cause) { eventer_t newe; struct timeval period, earliest; recur_closure_t *rcl; assert(cause == NULL); assert(check->fire_event == NULL); if(check->period == 0) return 0; if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) { if(!(check->flags & NP_TRANSIENT)) check_slots_dec_tv(last_check); return 0; } /* If we have an event, we know when we intended it to fire. This means * we should schedule that point + period. */ if(now) memcpy(&earliest, now, sizeof(earliest)); else gettimeofday(&earliest, NULL); /* If the check is unconfigured and needs resolving, we'll set the * period down a bit lower so we can pick up the resolution quickly. */ if(!NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) && check->period > 1000) { period.tv_sec = 1; period.tv_usec = 0; } else { period.tv_sec = check->period / 1000; period.tv_usec = (check->period % 1000) * 1000; } newe = eventer_alloc(); memcpy(&newe->whence, last_check, sizeof(*last_check)); add_timeval(newe->whence, period, &newe->whence); if(compare_timeval(newe->whence, earliest) < 0) memcpy(&newe->whence, &earliest, sizeof(earliest)); newe->mask = EVENTER_TIMER; newe->callback = noit_check_recur_handler; rcl = calloc(1, sizeof(*rcl)); rcl->self = self; rcl->check = check; rcl->cause = cause; rcl->dispatch = dispatch; newe->closure = rcl; eventer_add(newe); check->fire_event = newe; return 0; }
static int statsd_submit(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { statsd_closure_t *ccl; struct timeval duration; statsd_mod_config_t *conf; conf = noit_module_get_userdata(self); if(!conf->primary_active) conf->check = NULL; if(0 == memcmp(conf->primary, check->checkid, sizeof(uuid_t))) { conf->check = check; if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) { conf->check = NULL; return 0; } } /* We are passive, so we don't do anything for transient checks */ if(check->flags & NP_TRANSIENT) return 0; if(!check->closure) { ccl = check->closure = calloc(1, sizeof(*ccl)); ccl->self = self; memset(&check->stats.inprogress, 0, sizeof(check->stats.inprogress)); } else { // Don't count the first run char human_buffer[256]; ccl = (statsd_closure_t*)check->closure; gettimeofday(&check->stats.inprogress.whence, NULL); sub_timeval(check->stats.inprogress.whence, check->last_fire_time, &duration); check->stats.inprogress.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000; snprintf(human_buffer, sizeof(human_buffer), "dur=%d,run=%d,stats=%d", check->stats.inprogress.duration, check->generation, ccl->stats_count); noitL(nldeb, "statsd(%s) [%s]\n", check->target, human_buffer); // Not sure what to do here check->stats.inprogress.available = (ccl->stats_count > 0) ? NP_AVAILABLE : NP_UNAVAILABLE; check->stats.inprogress.state = (ccl->stats_count > 0) ? NP_GOOD : NP_BAD; check->stats.inprogress.status = human_buffer; if(check->last_fire_time.tv_sec) noit_check_passive_set_stats(check, &check->stats.inprogress); memcpy(&check->last_fire_time, &check->stats.inprogress.whence, sizeof(duration)); } ccl->stats_count = 0; noit_check_stats_clear(check, &check->stats.inprogress); return 0; }
static int external_timeout(eventer_t e, int mask, void *closure, struct timeval *now) { external_closure_t *ecl = (external_closure_t *)closure; struct check_info *data; if(!NOIT_CHECK_KILLED(ecl->check) && !NOIT_CHECK_DISABLED(ecl->check)) { data = (struct check_info *)ecl->check->closure; data->timedout = 1; data->exit_code = 3; external_log_results(ecl->self, ecl->check); data->timeout_event = NULL; } ecl->check->flags &= ~NP_RUNNING; free(ecl); return 0; }
static int ping_icmp_timeout(eventer_t e, int mask, void *closure, struct timeval *now) { struct ping_closure *pcl = (struct ping_closure *)closure; struct ping_session_key k; struct check_info *data; ping_icmp_data_t *ping_data; if(!NOIT_CHECK_KILLED(pcl->check) && !NOIT_CHECK_DISABLED(pcl->check)) { ping_icmp_log_results(pcl->self, pcl->check); } data = (struct check_info *)pcl->check->closure; data->timeout_event = NULL; pcl->check->flags &= ~NP_RUNNING; ping_data = noit_module_get_userdata(pcl->self); k.addr_of_check = (vpsized_uint)pcl->check ^ random_num; uuid_copy(k.checkid, pcl->check->checkid); mtev_hash_delete(ping_data->in_flight, (const char *)&k, sizeof(k), free, NULL); free(pcl); return 0; }
static int noit_console_show_check(noit_console_closure_t ncct, int argc, char **argv, noit_console_state_t *state, void *closure) { int i, cnt; noit_conf_t_userdata_t *info; char xpath[1024]; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL; noit_conf_xml_xpath(NULL, &xpath_ctxt); if(argc > 1) { nc_printf(ncct, "requires zero or one arguments\n"); return -1; } info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA); /* We many not be in conf-t mode -- that's fine */ if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, argc ? argv[0] : NULL)) { nc_printf(ncct, "could not find check '%s'\n", argv[0]); return -1; } pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); if(!pobj || pobj->type != XPATH_NODESET || xmlXPathNodeSetIsEmpty(pobj->nodesetval)) { nc_printf(ncct, "no checks found\n"); goto out; } cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(info && cnt != 1) { nc_printf(ncct, "Ambiguous check specified\n"); goto out; } for(i=0; i<cnt; i++) { noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *k; int klen; void *data; uuid_t checkid; noit_check_t *check; noit_hash_table *config; xmlNodePtr node, anode, mnode = NULL; char *uuid_conf; char *module, *value; node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i); uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); if(!uuid_conf || uuid_parse(uuid_conf, checkid)) { nc_printf(ncct, "%s has invalid or missing UUID!\n", (char *)xmlGetNodePath(node) + strlen("/noit")); continue; } nc_printf(ncct, "==== %s ====\n", uuid_conf); #define MYATTR(a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b)) #define INHERIT(a,n,b) \ _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b)) #define SHOW_ATTR(a) do { \ anode = NULL; \ value = NULL; \ INHERIT(a, anode, value); \ nc_attr_show(ncct, #a, node, anode, value); \ } while(0) if(!INHERIT(module, mnode, module)) module = NULL; if(MYATTR(name, anode, value)) nc_printf(ncct, " name: %s\n", value); else nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]"); nc_attr_show(ncct, "module", node, mnode, module); SHOW_ATTR(target); SHOW_ATTR(period); SHOW_ATTR(timeout); SHOW_ATTR(oncheck); SHOW_ATTR(filterset); SHOW_ATTR(disable); /* Print out all the config settings */ config = noit_conf_get_hash(node, "config"); while(noit_hash_next(config, &iter, &k, &klen, &data)) { nc_printf(ncct, " config::%s: %s\n", k, (const char *)data); } noit_hash_destroy(config, free, free); free(config); check = noit_poller_lookup(checkid); if(!check) { nc_printf(ncct, " ERROR: not in running system\n"); } else { int idx = 0; nc_printf(ncct, " currently: "); if(NOIT_CHECK_RUNNING(check)) nc_printf(ncct, "%srunning", idx++?",":""); if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":""); if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":""); if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":""); if(!idx) nc_printf(ncct, "idle"); nc_write(ncct, "\n", 1); if(check->stats.current.whence.tv_sec == 0) { nc_printf(ncct, " last run: never\n"); } else { stats_t *c = &check->stats.current; struct timeval now, diff; gettimeofday(&now, NULL); sub_timeval(now, c->whence, &diff); nc_printf(ncct, " last run: %0.3f seconds ago\n", diff.tv_sec + (diff.tv_usec / 1000000.0)); nc_printf(ncct, " availability/state: %s/%s\n", noit_check_available_string(c->available), noit_check_state_string(c->state)); nc_printf(ncct, " status: %s\n", c->status ? c->status : "[[null]]"); nc_printf(ncct, " metrics:\n"); memset(&iter, 0, sizeof(iter)); while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) { char buff[256]; noit_boolean filtered; noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data); filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data); nc_printf(ncct, " %c%s\n", filtered ? '*' : ' ', buff); } } } } out: if(pobj) xmlXPathFreeObject(pobj); return 0; }
static int noit_console_show_check(mtev_console_closure_t ncct, int argc, char **argv, mtev_console_state_t *state, void *closure) { int i, cnt; mtev_conf_t_userdata_t *info; char xpath[1024]; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL; mtev_conf_xml_xpath(NULL, &xpath_ctxt); if(argc > 1) { nc_printf(ncct, "requires zero or one arguments\n"); return -1; } info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA); /* We many not be in conf-t mode -- that's fine */ if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, argc ? argv[0] : NULL)) { nc_printf(ncct, "could not find check '%s'\n", argv[0]); return -1; } pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); if(!pobj || pobj->type != XPATH_NODESET || xmlXPathNodeSetIsEmpty(pobj->nodesetval)) { nc_printf(ncct, "no checks found\n"); goto out; } cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(info && cnt != 1) { nc_printf(ncct, "Ambiguous check specified\n"); goto out; } for(i=0; i<cnt; i++) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; uuid_t checkid; noit_check_t *check; mtev_hash_table *config; xmlNodePtr node, anode, mnode = NULL; char *uuid_conf; char *module, *value; node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i); uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); if(!uuid_conf || uuid_parse(uuid_conf, checkid)) { nc_printf(ncct, "%s has invalid or missing UUID!\n", (char *)xmlGetNodePath(node) + strlen("/noit")); continue; } nc_printf(ncct, "==== %s ====\n", uuid_conf); xmlFree(uuid_conf); #define MYATTR(a,n,b) _mtev_conf_get_string(node, &(n), "@" #a, &(b)) #define INHERIT(a,n,b) \ _mtev_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b)) #define SHOW_ATTR(a) do { \ anode = NULL; \ value = NULL; \ INHERIT(a, anode, value); \ nc_attr_show(ncct, #a, node, anode, value); \ if(value != NULL) free(value); \ } while(0) if(!INHERIT(module, mnode, module)) module = NULL; if(MYATTR(name, anode, value)) { nc_printf(ncct, " name: %s\n", value); free(value); } else nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]"); nc_attr_show(ncct, "module", node, mnode, module); if(module) free(module); SHOW_ATTR(target); SHOW_ATTR(seq); SHOW_ATTR(resolve_rtype); SHOW_ATTR(period); SHOW_ATTR(timeout); SHOW_ATTR(oncheck); SHOW_ATTR(filterset); SHOW_ATTR(disable); /* Print out all the config settings */ config = mtev_conf_get_hash(node, "config"); while(mtev_hash_next(config, &iter, &k, &klen, &data)) { nc_printf(ncct, " config::%s: %s\n", k, (const char *)data); } mtev_hash_destroy(config, free, free); free(config); check = noit_poller_lookup(checkid); if(!check) { nc_printf(ncct, " ERROR: not in running system\n"); } else { int idx = 0; stats_t *c; struct timeval *whence; mtev_hash_table *metrics; nc_printf(ncct, " target_ip: %s\n", check->target_ip); nc_printf(ncct, " currently: %08x ", check->flags); if(NOIT_CHECK_RUNNING(check)) { nc_printf(ncct, "running"); idx++; } if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":""); if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":""); if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":""); if(!idx) nc_printf(ncct, "idle"); nc_write(ncct, "\n", 1); if (check->fire_event != NULL) { struct timeval now, diff; mtev_gettimeofday(&now, NULL); sub_timeval(check->fire_event->whence, now, &diff); nc_printf(ncct, " next run: %0.3f seconds\n", diff.tv_sec + (diff.tv_usec / 1000000.0)); } else { nc_printf(ncct, " next run: unscheduled\n"); } c = noit_check_get_stats_current(check); whence = noit_check_stats_whence(c, NULL); if(whence->tv_sec == 0) { nc_printf(ncct, " last run: never\n"); } else { const char *status; struct timeval now, *then, diff; mtev_gettimeofday(&now, NULL); then = noit_check_stats_whence(c, NULL); sub_timeval(now, *then, &diff); nc_printf(ncct, " last run: %0.3f seconds ago\n", diff.tv_sec + (diff.tv_usec / 1000000.0)); nc_printf(ncct, " availability/state: %s/%s\n", noit_check_available_string(noit_check_stats_available(c, NULL)), noit_check_state_string(noit_check_stats_state(c, NULL))); status = noit_check_stats_status(c, NULL); nc_printf(ncct, " status: %s\n", status); nc_printf(ncct, " feeds: %d\n", check->feeds ? check->feeds->size : 0); } c = noit_check_get_stats_inprogress(check); metrics = noit_check_stats_metrics(c); if(mtev_hash_size(metrics) > 0) { nc_printf(ncct, " metrics (inprogress):\n"); nc_print_stat_metrics(ncct, check, c); } c = noit_check_get_stats_current(check); metrics = noit_check_stats_metrics(c); if(mtev_hash_size(metrics)) { nc_printf(ncct, " metrics (current):\n"); nc_print_stat_metrics(ncct, check, c); } c = noit_check_get_stats_previous(check); metrics = noit_check_stats_metrics(c); if(mtev_hash_size(metrics) > 0) { nc_printf(ncct, " metrics (previous):\n"); nc_print_stat_metrics(ncct, check, c); } } } out: if(pobj) xmlXPathFreeObject(pobj); return 0; }
int noit_check_schedule_next(noit_module_t *self, struct timeval *last_check, noit_check_t *check, struct timeval *now, dispatch_func_t dispatch, noit_check_t *cause) { eventer_t newe; struct timeval period, earliest, diff; int64_t diffms, periodms, offsetms; recur_closure_t *rcl; int initial = last_check ? 1 : 0; assert(cause == NULL); assert(check->fire_event == NULL); if(check->period == 0) return 0; /* if last_check is not passed, we use the initial_schedule_time * otherwise, we set the initial_schedule_time */ if(!last_check) last_check = &check->initial_schedule_time; else memcpy(&check->initial_schedule_time, last_check, sizeof(*last_check)); if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) { if(!(check->flags & NP_TRANSIENT)) check_slots_dec_tv(last_check); memset(&check->initial_schedule_time, 0, sizeof(struct timeval)); return 0; } /* If we have an event, we know when we intended it to fire. This means * we should schedule that point + period. */ if(now) memcpy(&earliest, now, sizeof(earliest)); else gettimeofday(&earliest, NULL); /* If the check is unconfigured and needs resolving, we'll set the * period down a bit lower so we can pick up the resolution quickly. * The one exception is if this is the initial run. */ if(!initial && !NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) && check->period > 1000) { period.tv_sec = 1; period.tv_usec = 0; } else { period.tv_sec = check->period / 1000; period.tv_usec = (check->period % 1000) * 1000; } periodms = period.tv_sec * 1000 + period.tv_usec / 1000; newe = eventer_alloc(); /* calculate the differnet between the initial schedule time and "now" */ if(compare_timeval(earliest, *last_check) >= 0) { sub_timeval(earliest, *last_check, &diff); diffms = (int64_t)diff.tv_sec * 1000 + diff.tv_usec / 1000; } else { noitL(noit_error, "time is going backwards. abort.\n"); abort(); } /* determine the offset from initial schedule time that would place * us at the next period-aligned point past "now" */ offsetms = ((diffms / periodms) + 1) * periodms; diff.tv_sec = offsetms / 1000; diff.tv_usec = (offsetms % 1000) * 1000; memcpy(&newe->whence, last_check, sizeof(*last_check)); add_timeval(newe->whence, diff, &newe->whence); sub_timeval(newe->whence, earliest, &diff); diffms = (int64_t)diff.tv_sec * 1000 + (int)diff.tv_usec / 1000; assert(compare_timeval(newe->whence, earliest) > 0); newe->mask = EVENTER_TIMER; newe->callback = noit_check_recur_handler; rcl = calloc(1, sizeof(*rcl)); rcl->self = self; rcl->check = check; rcl->cause = cause; rcl->dispatch = dispatch; newe->closure = rcl; eventer_add(newe); check->fire_event = newe; return diffms; }