Ejemplo n.º 1
0
static int sq_test_random(squeue_t *sq)
{
	unsigned long size, i;
	unsigned long long numbers[EVT_ARY], *d, max = 0;
	struct timeval now;

	size = squeue_size(sq);
	now.tv_sec = time(NULL);
	srand((int)now.tv_sec);
	for (i = 0; i < EVT_ARY; i++) {
		now.tv_usec = (time_t)rand();
		squeue_add_tv(sq, &now, &numbers[i]);
		numbers[i] = evt_compute_pri(&now);
		t(squeue_size(sq) == i + 1 + size);
	}

	t(pqueue_is_valid(sq));

	/*
	 * make sure we pop events in increasing "priority",
	 * since we calculate priority based on time and later
	 * is lower prio
	 */
	for (i = 0; i < EVT_ARY; i++) {
		d = (unsigned long long *)squeue_pop(sq);
		t(max <= *d, "popping randoms. i: %lu; delta: %lld; max: %llu; *d: %llu\n",
		  i, max - *d, max, *d);
		max = *d;
		t(squeue_size(sq) == size + (EVT_ARY - i - 1));
	}
	t(pqueue_is_valid(sq));

	return 0;
}
Ejemplo n.º 2
0
static void adjust_squeue_for_time_change(squeue_t **q, int delta)
{
	timed_event *event;
	squeue_t *sq_new;

	/*
	 * this is pretty inefficient in terms of free() + malloc(),
	 * but it should be pretty rare that we have to adjust times
	 * so we go with the well-tested codepath.
	 */
	sq_new = squeue_create(squeue_size(*q));
	while ((event = squeue_pop(*q))) {
		if (event->compensate_for_time_change == TRUE) {
			if (event->timing_func) {
				time_t (*timingfunc)(void);
				timingfunc = event->timing_func;
				event->run_time = timingfunc();
			} else {
				event->run_time += delta;
			}
		}
		if (event->priority) {
			event->sq_event = squeue_add_usec(sq_new, event->run_time, event->priority - 1, event);
		} else {
			event->sq_event = squeue_add(sq_new, event->run_time, event);
		}
	}
	squeue_destroy(*q, 0);
	*q = sq_new;
}
Ejemplo n.º 3
0
int dump_event_stats(int sd)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(event_count); i++) {
		nsock_printf(sd, "%s=%u;", EVENT_TYPE_STR(i), event_count[i]);
		/*
		 * VERSIONFIX: Make EVENT_SLEEP and EVENT_USER_FUNCTION
		 * appear in linear order in include/nagios.h when we go
		 * from 4.0 -> 4.1, so we can remove this junk.
		 */
		if (i == 16)
			i = 97;
	}
	nsock_printf_nul(sd, "SQUEUE_ENTRIES=%u", squeue_size(nagios_squeue));

	return OK;
}
Ejemplo n.º 4
0
/* this is the main event handler loop */
int event_execution_loop(void)
{
	timed_event *temp_event, *last_event = NULL;
	time_t last_time = 0L;
	time_t current_time = 0L;
	time_t last_status_update = 0L;
	int poll_time_ms;

	log_debug_info(DEBUGL_FUNCTIONS, 0, "event_execution_loop() start\n");

	time(&last_time);

	while (1) {
		struct timeval now;
		const struct timeval *event_runtime;
		int inputs;

		/* super-priority (hardcoded) events come first */

		/* see if we should exit or restart (a signal was encountered) */
		if (sigshutdown == TRUE || sigrestart == TRUE)
			break;

		/* get the current time */
		time(&current_time);

		if (sigrotate == TRUE) {
			rotate_log_file(current_time);
			update_program_status(FALSE);
		}

		/* hey, wait a second...  we traveled back in time! */
		if (current_time < last_time)
			compensate_for_system_time_change((unsigned long)last_time, (unsigned long)current_time);

		/* else if the time advanced over the specified threshold, try and compensate... */
		else if ((current_time - last_time) >= time_change_threshold)
			compensate_for_system_time_change((unsigned long)last_time, (unsigned long)current_time);

		/* get next scheduled event */
		current_event = temp_event = (timed_event *)squeue_peek(nagios_squeue);

		/* if we don't have any events to handle, exit */
		if (!temp_event) {
			log_debug_info(DEBUGL_EVENTS, 0, "There aren't any events that need to be handled! Exiting...\n");
			break;
		}

		/* keep track of the last time */
		last_time = current_time;

		/* update status information occassionally - NagVis watches the NDOUtils DB to see if Nagios is alive */
		if ((unsigned long)(current_time - last_status_update) > 5) {
			last_status_update = current_time;
			update_program_status(FALSE);
		}

		event_runtime = squeue_event_runtime(temp_event->sq_event);
		if (temp_event != last_event) {
			log_debug_info(DEBUGL_EVENTS, 1, "** Event Check Loop\n");
			log_debug_info(DEBUGL_EVENTS, 1, "Next Event Time: %s", ctime(&temp_event->run_time));
			log_debug_info(DEBUGL_EVENTS, 1, "Current/Max Service Checks: %d/%d (%.3lf%% saturation)\n",
			               currently_running_service_checks, max_parallel_service_checks,
			               ((float)currently_running_service_checks / (float)max_parallel_service_checks) * 100);
		}

		last_event = temp_event;

		gettimeofday(&now, NULL);
		poll_time_ms = tv_delta_msec(&now, event_runtime);
		if (poll_time_ms < 0)
			poll_time_ms = 0;
		else if (poll_time_ms >= 1500)
			poll_time_ms = 1500;

		log_debug_info(DEBUGL_SCHEDULING, 2, "## Polling %dms; sockets=%d; events=%u; iobs=%p\n",
		               poll_time_ms, iobroker_get_num_fds(nagios_iobs),
		               squeue_size(nagios_squeue), nagios_iobs);
		inputs = iobroker_poll(nagios_iobs, poll_time_ms);
		if (inputs < 0 && errno != EINTR) {
			logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Polling for input on %p failed: %s", nagios_iobs, iobroker_strerror(inputs));
			break;
		}

		log_debug_info(DEBUGL_IPC, 2, "## %d descriptors had input\n", inputs);

		/*
		 * if the event we peaked was removed from the queue from
		 * one of the I/O operations, we must take care not to
		 * try to run at, as we're (almost) sure to access free'd
		 * or invalid memory if we do.
		 */
		if (!current_event) {
			log_debug_info(DEBUGL_EVENTS, 0, "Event was cancelled by iobroker input\n");
			continue;
		}

		gettimeofday(&now, NULL);
		if (tv_delta_msec(&now, event_runtime) >= 0)
			continue;

		/* move on if we shouldn't run this event */
		if (should_run_event(temp_event) == FALSE)
			continue;

		/* handle the event */
		handle_timed_event(temp_event);

		/*
		 * we must remove the entry we've peeked, or
		 * we'll keep getting the same one over and over.
		 * This also maintains sync with broker modules.
		 */
		remove_event(nagios_squeue, temp_event);

		/* reschedule the event if necessary */
		if (temp_event->recurring == TRUE)
			reschedule_event(nagios_squeue, temp_event);

		/* else free memory associated with the event */
		else
			my_free(temp_event);
	}

	log_debug_info(DEBUGL_FUNCTIONS, 0, "event_execution_loop() end\n");

	return OK;
}
Ejemplo n.º 5
0
static int finish_job(child_process *cp, int reason)
{
	static struct kvvec resp = KVVEC_INITIALIZER;
	struct rusage *ru = &cp->rusage;
	int i, ret;

	/* how many key/value pairs do we need? */
	if (kvvec_init(&resp, 12 + cp->request->kv_pairs) == NULL) {
		/* what the hell do we do now? */
		exit_worker();
	}

	gettimeofday(&cp->stop, NULL);

	if (running_jobs != squeue_size(sq)) {
		wlog("running_jobs(%d) != squeue_size(sq) (%d)\n",
			 running_jobs, squeue_size(sq));
		wlog("started: %d; running: %d; finished: %d\n",
			 started, running_jobs, started - running_jobs);
	}

	/*
	 * we must remove the job's timeout ticker,
	 * or we'll end up accessing an already free()'d
	 * pointer, or the pointer to a different child.
	 */
	squeue_remove(sq, cp->sq_event);

	/* get rid of still open filedescriptors */
	if (cp->outstd.fd != -1)
		iobroker_close(iobs, cp->outstd.fd);
	if (cp->outerr.fd != -1)
		iobroker_close(iobs, cp->outerr.fd);

	cp->runtime = tv_delta_f(&cp->start, &cp->stop);

	/*
	 * Now build the return message.
	 * First comes the request, minus environment variables
	 */
	for (i = 0; i < cp->request->kv_pairs; i++) {
		struct key_value *kv = &cp->request->kv[i];
		/* skip environment macros */
		if (kv->key_len == 3 && !strcmp(kv->key, "env")) {
			continue;
		}
		kvvec_addkv_wlen(&resp, kv->key, kv->key_len, kv->value, kv->value_len);
	}
	kvvec_addkv(&resp, "wait_status", (char *)mkstr("%d", cp->ret));
	kvvec_addkv_wlen(&resp, "outstd", 6, cp->outstd.buf, cp->outstd.len);
	kvvec_addkv_wlen(&resp, "outerr", 6, cp->outerr.buf, cp->outerr.len);
	kvvec_add_tv(&resp, "start", cp->start);
	kvvec_add_tv(&resp, "stop", cp->stop);
	kvvec_addkv(&resp, "runtime", (char *)mkstr("%f", cp->runtime));
	if (!reason) {
		/* child exited nicely */
		kvvec_addkv(&resp, "exited_ok", "1");
		kvvec_add_tv(&resp, "ru_utime", ru->ru_utime);
		kvvec_add_tv(&resp, "ru_stime", ru->ru_stime);
		kvvec_add_long(&resp, "ru_minflt", ru->ru_minflt);
		kvvec_add_long(&resp, "ru_majflt", ru->ru_majflt);
		kvvec_add_long(&resp, "ru_nswap", ru->ru_nswap);
		kvvec_add_long(&resp, "ru_inblock", ru->ru_inblock);
		kvvec_add_long(&resp, "ru_oublock", ru->ru_oublock);
		kvvec_add_long(&resp, "ru_nsignals", ru->ru_nsignals);
	} else {
		/* some error happened */
		kvvec_addkv(&resp, "exited_ok", "0");
		kvvec_addkv(&resp, "error_code", (char *)mkstr("%d", reason));
	}
	ret = send_kvvec(master_sd, &resp);
	if (ret < 0 && errno == EPIPE)
		exit_worker();

	running_jobs--;
	if (cp->outstd.buf) {
		free(cp->outstd.buf);
		cp->outstd.buf = NULL;
	}
	if (cp->outerr.buf) {
		free(cp->outerr.buf);
		cp->outerr.buf = NULL;
	}

	kvvec_destroy(cp->request, KVVEC_FREE_ALL);
	free(cp->cmd);
	free(cp);

	return 0;
}
Ejemplo n.º 6
0
int finish_job(child_process *cp, int reason)
{
	static struct kvvec resp = KVVEC_INITIALIZER;
	struct rusage *ru = &cp->ei->rusage;
	int i, ret;

	/* get rid of still open filedescriptors */
	if (cp->outstd.fd != -1) {
		gather_output(cp, &cp->outstd, 1);
		iobroker_close(iobs, cp->outstd.fd);
	}
	if (cp->outerr.fd != -1) {
		gather_output(cp, &cp->outerr, 1);
		iobroker_close(iobs, cp->outerr.fd);
	}

	/* Make sure network-supplied data doesn't contain nul bytes */
	strip_nul_bytes(cp->outstd);
	strip_nul_bytes(cp->outerr);

	/* how many key/value pairs do we need? */
	if (kvvec_init(&resp, 12 + cp->request->kv_pairs) == NULL) {
		/* what the hell do we do now? */
		exit_worker(1, "Failed to init response key/value vector");
	}

	gettimeofday(&cp->ei->stop, NULL);

	if (running_jobs != squeue_size(sq)) {
		wlog("running_jobs(%d) != squeue_size(sq) (%d)\n",
			 running_jobs, squeue_size(sq));
		wlog("started: %d; running: %d; finished: %d\n",
			 started, running_jobs, started - running_jobs);
	}

	cp->ei->runtime = tv_delta_f(&cp->ei->start, &cp->ei->stop);

	/*
	 * Now build the return message.
	 * First comes the request, minus environment variables
	 */
	for (i = 0; i < cp->request->kv_pairs; i++) {
		struct key_value *kv = &cp->request->kv[i];
		/* skip environment macros */
		if (kv->key_len == 3 && !strcmp(kv->key, "env")) {
			continue;
		}
		kvvec_addkv_wlen(&resp, kv->key, kv->key_len, kv->value, kv->value_len);
	}
	kvvec_addkv(&resp, "wait_status", mkstr("%d", cp->ret));
	kvvec_add_tv(&resp, "start", cp->ei->start);
	kvvec_add_tv(&resp, "stop", cp->ei->stop);
	kvvec_addkv(&resp, "runtime", mkstr("%f", cp->ei->runtime));
	if (!reason) {
		/* child exited nicely (or with a signal, so check wait_status) */
		kvvec_addkv(&resp, "exited_ok", "1");
		kvvec_add_tv(&resp, "ru_utime", ru->ru_utime);
		kvvec_add_tv(&resp, "ru_stime", ru->ru_stime);
		kvvec_add_long(&resp, "ru_minflt", ru->ru_minflt);
		kvvec_add_long(&resp, "ru_majflt", ru->ru_majflt);
		kvvec_add_long(&resp, "ru_inblock", ru->ru_inblock);
		kvvec_add_long(&resp, "ru_oublock", ru->ru_oublock);
	} else {
		/* some error happened */
		kvvec_addkv(&resp, "exited_ok", "0");
		kvvec_addkv(&resp, "error_code", mkstr("%d", reason));
	}
	kvvec_addkv_wlen(&resp, "outerr", 6, cp->outerr.buf, cp->outerr.len);
	kvvec_addkv_wlen(&resp, "outstd", 6, cp->outstd.buf, cp->outstd.len);
	ret = worker_send_kvvec(master_sd, &resp);
	if (ret < 0 && errno == EPIPE)
		exit_worker(1, "Failed to send kvvec struct to master");

	return 0;
}
Ejemplo n.º 7
0
int main(int argc, char **argv)
{
	squeue_t *sq;
	struct timeval tv;
	sq_test_event a, b, c, d, *x;

	t_set_colors(0);
	t_start("squeue tests");

	a.id = 1;
	b.id = 2;
	c.id = 3;
	d.id = 4;

	gettimeofday(&tv, NULL);
	/* Order in is a, b, c, d, but we should get b, c, d, a out. */
	srand(tv.tv_usec ^ tv.tv_sec);
	t((sq = squeue_create(1024)) != NULL);
	t(squeue_size(sq) == 0);

	/* we fill and empty the squeue completely once before testing */
	sq_test_random(sq);
	t(squeue_size(sq) == 0, "Size should be 0 after first sq_test_random");

	t((a.evt = squeue_add(sq, time(NULL) + 9, &a)) != NULL);
	t(squeue_size(sq) == 1);
	t((b.evt = squeue_add(sq, time(NULL) + 3, &b)) != NULL);
	t(squeue_size(sq) == 2);
	t((c.evt = squeue_add_msec(sq, time(NULL) + 5, 0, &c)) != NULL);
	t(squeue_size(sq) == 3);
	t((d.evt = squeue_add_usec(sq, time(NULL) + 5, 1, &d)) != NULL);
	t(squeue_size(sq) == 4);

	/* add and remove lots. remainder should be what we have above */
	sq_test_random(sq);

	/* testing squeue_peek() */
	t((x = (sq_test_event *)squeue_peek(sq)) != NULL);
	t(x == &b, "x: %p; a: %p; b: %p; c: %p; d: %p\n", x, &a, &b, &c, &d);
	t(x->id == b.id);
	t(squeue_size(sq) == 4);

	/* testing squeue_remove() and re-add */
	t(squeue_remove(sq, b.evt) == 0);
	t(squeue_size(sq) == 3);
	t((x = squeue_peek(sq)) != NULL);
	t(x == &c);
	t((b.evt = squeue_add(sq, time(NULL) + 3, &b)) != NULL);
	t(squeue_size(sq) == 4);

	/* peek should now give us the &b event (again) */
	t((x = squeue_peek(sq)) != NULL);
	if (x != &b) {
		printf("about to fail pretty f*****g hard...\n");
		printf("ea: %p; &b: %p; &c: %p; ed: %p; x: %p\n",
		       &a, &b, &c, &d, x);
	}
	t(x == &b);
	t(x->id == b.id);
	t(squeue_size(sq) == 4);

	/* testing squeue_pop(), lifo manner */
	t((x = squeue_pop(sq)) != NULL);
	t(squeue_size(sq) == 3,
	  "squeue_size(sq) = %d\n", squeue_size(sq));
	t(x == &b, "x: %p; &b: %p\n", x, &b);
	t(x->id == b.id, "x->id: %lu; d.id: %lu\n", x->id, d.id);

	/* Test squeue_pop() */
	t((x = squeue_pop(sq)) != NULL);
	t(squeue_size(sq) == 2);
	t(x == &c, "x->id: %lu; c.id: %lu\n", x->id, c.id);
	t(x->id == c.id, "x->id: %lu; c.id: %lu\n", x->id, c.id);

	/* this should fail gracefully (-1 return from squeue_remove()) */
	t(squeue_remove(NULL, NULL) == -1);
	t(squeue_remove(NULL, a.evt) == -1);

	squeue_foreach(sq, sq_walker, NULL);

	/* clean up to prevent false valgrind positives */
	squeue_destroy(sq, 0);

	return t_end();
}
Ejemplo n.º 8
0
int main(void)
{
  struct object obj;
  struct object *obp;
  const void *vp;
  unsigned long num;
  unsigned long cmp;

  squeue_init(&sq, buf, QUEUE_SIZE, sizeof(struct object));

  printf("h t u\n");
  dump();

  /* check size is zero */
  test_assert(squeue_size(&sq) == 0);
  test_assert(squeue_SIZE(&sq) == 0);
  printf("\n");

  /* check enq works */
  for (num = 0; num < QUEUE_SIZE; ++num) {
    obj.num = num << 1;
    test_assert(squeue_enq(&sq, &obj) == 1);
    dump();
  }
  printf("\n");

  /* check size is correct */
  test_assert(squeue_bytes(&sq) == QUEUE_SIZE * sizeof(struct object));
  test_assert(squeue_BYTES(&sq) == QUEUE_SIZE * sizeof(struct object));
  test_assert(squeue_size(&sq) == QUEUE_SIZE);
  test_assert(squeue_SIZE(&sq) == QUEUE_SIZE);

  /* check deny overflow */
  test_assert(squeue_enq(&sq, 0) == 0);
  dump();
  printf("\n");

  /* check deq works */
  for (num = 0; num < QUEUE_SIZE; ++num) {
    test_assert(squeue_peek(&sq, (void **) &obp) == 1);
    cmp = obp->num;
    test_assert(cmp == num << 1);
    test_assert(squeue_deq(&sq, (void **) &obp));
    cmp = obp->num;
    test_assert(cmp == num << 1);
    dump();
  }
  printf("\n");

  /* check deny underflow */
  test_assert(squeue_deq(&sq, 0) == 0);
  dump();
  printf("\n");

  /* check enq works */
  for (num = 0; num < QUEUE_SIZE; ++num) {
    obj.num = num << 1;
    test_assert(squeue_enq(&sq, &obj) == 1);
    dump();
  }
  printf("\n");

  /* check size is correct */
  test_assert(squeue_bytes(&sq) == QUEUE_SIZE * sizeof(struct object));
  test_assert(squeue_BYTES(&sq) == QUEUE_SIZE * sizeof(struct object));
  test_assert(squeue_size(&sq) == QUEUE_SIZE);
  test_assert(squeue_SIZE(&sq) == QUEUE_SIZE);

  /* check deny overflow */
  test_assert(squeue_enq(&sq, 0) == 0);
  dump();
  printf("\n");

  /* check deq works */
  for (num = 0; num < QUEUE_SIZE; ++num) {
    test_assert(squeue_peek(&sq, (void **) &obp) == 1);
    cmp = obp->num;
    test_assert(cmp == num << 1);
    test_assert(squeue_deq(&sq, (void **) &obp));
    cmp = obp->num;
    test_assert(cmp == num << 1);
    dump();
  }
  printf("\n");

  /* check data works */
  vp = squeue_data(&sq);
  test_assert(vp == buf);
  vp = squeue_DATA(&sq);
  test_assert(vp == buf);

  return 0;
}