/*
 * Recursively check that the treap (btree) is
 * internally consistent.
 */
int
schedule_debug_entry (const struct schedule_entry* e,
		      int depth,
		      int *count,
		      struct timeval *least,
		      const struct timeval *min,
		      const struct timeval *max)
{
  struct gc_arena gc = gc_new ();
  int maxdepth = depth;
  if (e)
    {
      int d;

      ASSERT (e != e->lt);
      ASSERT (e != e->gt);
      ASSERT (e != e->parent);
      ASSERT (!e->parent || e->parent != e->lt);
      ASSERT (!e->parent || e->parent != e->gt);
      ASSERT (!e->lt || e->lt != e->gt);

      if (e->lt)
	{
	  ASSERT (e->lt->parent == e);
	  ASSERT (schedule_entry_compare (e->lt, e) == -1);
	  ASSERT (e->lt->pri >= e->pri);
	}

      if (e->gt)
	{
	  ASSERT (e->gt->parent == e);
	  ASSERT (schedule_entry_compare (e->gt, e));
	  ASSERT (e->gt->pri >= e->pri);
	}

      ASSERT (tv_le (min, &e->tv));
      ASSERT (tv_le (&e->tv, max));

      if (count)
	++(*count);

      if (least && tv_lt (&e->tv, least))
	*least = e->tv;

      d = schedule_debug_entry (e->lt, depth+1, count, least, min, &e->tv);
      if (d > maxdepth)
	maxdepth = d;

      d = schedule_debug_entry (e->gt, depth+1, count, least, &e->tv, max);
      if (d > maxdepth)
	maxdepth = d;
    }
  gc_free (&gc);
  return maxdepth;
}
Пример #2
0
/*
 * Return a string suitable for use as a timestamp in the xplot output.
 * sdo fix: originally, we were just plotting to the accuracy of 1/10 ms
 *   this was mostly to help keep the .xpl files from being too large.  However,
 *   on faster networks this just isn't enough, so we'll now use all 6 digits
 *   of the microsecond counter.  Note that there's no guarantee that the
 *   timestamps are really all that accurate!
 */
static char *
xp_timestamp(
    PLOTTER pl,
    struct timeval time)
{
    static char bufs[4][20];	/* several of them for multiple calls in one printf */
    static int bufix = 0;
    unsigned secs;
    unsigned usecs;
    unsigned decimal;
    char *pbuf;
    struct plotter_info *ppi;
   
    ppi = &pplotters[pl];
   
    /* see if we're graphing from "0" OR if the axis type is switched */
    if (graph_time_zero || ppi->axis_switched) {


	if (ZERO_TIME(&ppi->zerotime)) {
	    /* set "zero point" */
	    ppi->zerotime = time;
	}

	/* (in)sanity check */
	if (tv_lt(time,ppi->zerotime)) {
	    fprintf(stderr,"Internal error in plotting (plot file '%s')...\n\
ZERO-based X-axis plotting requested and elements are not plotted in\n\
increasing time order.  Try without the '-z' flag\n",
		    ppi->filename);
/* 	    exit(-5); */
	    time.tv_sec = time.tv_usec = 0;
	} else {
	    /* computer offset from first plotter point */
	    tv_sub(&time, ppi->zerotime);
	}
    }

    /* calculate time components */
    secs = time.tv_sec;
    usecs = time.tv_usec;
    decimal = usecs;

    /* use one of 4 rotating static buffers (for multiple calls per printf) */
    bufix = (bufix+1)%4;
    pbuf = bufs[bufix];

    snprintf(pbuf,sizeof(bufs[bufix]),"%u.%06u",secs,decimal);

    return(pbuf);
}
Пример #3
0
/**
 * network_buf(fd, buf, buflen, to0, to1, callback, cookie, sendrecv, netop,
 *     flags):
 * Asynchronously read/write the provided buffer from/to ${fd}, and call
 * callback(cookie, status) where status is a NETWORK_STATUS_* value.  Time
 * out if no data can be read/writ for a period of time to0, or if the
 * complete buffer has not been read/writ after time to1.
 */
static int
network_buf(int fd, uint8_t * buf, size_t buflen,
    struct timeval * to0, struct timeval * to1,
    network_callback * callback, void * cookie,
    ssize_t (* sendrecv)(int, void *, size_t, int), int netop,
    int flags)
{
	struct network_buf_cookie * C;
	struct timeval timeo;

	/* Create a cookie to be passed to callback_buf. */
	if ((C = malloc(sizeof(struct network_buf_cookie))) == NULL)
		goto err0;
	C->callback = callback;
	C->cookie = cookie;
	C->fd = fd;
	C->buf = buf;
	C->buflen = buflen;
	C->bufpos = 0;
	C->sendrecv = sendrecv;
	C->netop = netop;
	C->flags = flags;

	/* Figure out when we should give up waiting. */
	memcpy(&C->timeout, to1, sizeof(struct timeval));
	if (tvmath_addctime(&C->timeout))
		goto err1;

	/* Record the maximum time that any single send/recv will wait. */
	memcpy(&C->timeout_max, to0, sizeof(struct timeval));

	/* Set up the callback. */
	memcpy(&timeo, to1, sizeof(struct timeval));
	if (tv_lt(to0, &timeo))
		memcpy(&timeo, to0, sizeof(struct timeval));
	if (network_register(fd, netop, &timeo, callback_buf, C))
		goto err1;

	/* Success! */
	return (0);

err1:
	free(C);
err0:
	/* Failure! */
	return (-1);
}
Пример #4
0
/**
 * callback_buf(cookie, status):
 * Callback helper for tsnetwork_read and network_write.
 */
static int
callback_buf(void * cookie, int status)
{
	struct network_buf_cookie * C = cookie;
	struct timeval timeo;
	size_t bwlimit;
	size_t oplen;
	ssize_t len;
	int rc = -1;	/* If not callback or reset, we have an error. */
#ifndef HAVE_MSG_NOSIGNAL
#ifdef SO_NOSIGPIPE
	int val;
#else
	void (*oldsig)(int);
#endif
#endif

	if (status != NETWORK_STATUS_OK) {
		/* If we have no data, mark a timeout as "no data" instead. */
		if ((C->bufpos != 0) && (status == NETWORK_STATUS_TIMEOUT))
			status = NETWORK_STATUS_NODATA;
		goto docallback;
	}

	/* Figure out how far we have bandwidth quota for. */
	if (network_bwlimit_get(C->netop, &bwlimit)) {
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}

	/* If we have no bandwidth, schedule another callback. */
	if (bwlimit == 0)
		goto tryagain;

	/* Try to read/write data to/from the buffer. */
#ifndef HAVE_MSG_NOSIGNAL
#ifdef SO_NOSIGPIPE
	val = 1;

	if (setsockopt(C->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int))) {
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}
#else
	if ((oldsig = signal(SIGPIPE, SIG_IGN)) == SIG_ERR) {
		warnp("signal(SIGPIPE)");
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}
#endif
#endif

	oplen = C->buflen - C->bufpos;
	if (oplen > bwlimit)
		oplen = bwlimit;
	len = (C->sendrecv)(C->fd, C->buf + C->bufpos, oplen, C->flags);
#ifndef HAVE_MSG_NOSIGNAL
#ifdef SO_NOSIGPIPE
	val = 0;

	if (setsockopt(C->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int))) {
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}
#else
	if (signal(SIGPIPE, oldsig) == SIG_ERR) {
		warnp("signal(SIGPIPE)");
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}
#endif
#endif

	/* Failure, closed, or success? */
	if (len == -1) {
		/* If no data is available, reset the callback. */
		if ((errno == EAGAIN) ||
		    (errno == EWOULDBLOCK) ||
		    (errno == EINTR))
			goto tryagain;

		/* An error occurred.  Let the callback handle it. */
		status = NETWORK_STATUS_ERR;
		goto docallback;
	} else if (len == 0) {
		/* Socket has been shut down by remote host. */
		/* This should occur only when receiving, not when sending. */
		status = NETWORK_STATUS_CLOSED;
		goto docallback;
	} else {
		/* Adjust bandwidth limit. */
		if (network_bwlimit_eat(C->netop, len)) {
			status = NETWORK_STATUS_ERR;
			goto docallback;
		}

		/* Data has been read/written into/from buffer. */
		C->bufpos += len;
		if (C->bufpos == C->buflen) {
			status = NETWORK_STATUS_OK;
			goto docallback;
		}

		/* Fall through to resetting the callback. */
	}

tryagain:
	/* We need more data.  Reset the callback. */
	memcpy(&timeo, &C->timeout, sizeof(struct timeval));
	if (tvmath_subctime(&timeo)) {
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}
	if (tv_lt(&C->timeout_max, &timeo))
		memcpy(&timeo, &C->timeout_max, sizeof(struct timeval));
	if (network_register(C->fd, C->netop, &timeo, callback_buf, C)) {
		status = NETWORK_STATUS_ERR;
		goto docallback;
	}

	/* Callback has been reset. */
	return (0);

docallback:
	/*
	 * If there was a network error and we're being verbose, print the
	 * error now in case errno gets mangled later.
	 */
	if ((tarsnap_opt_noisy_warnings) && (status == NETWORK_STATUS_ERR))
		warnp("Network error");

	/* Call the user callback. */
	rc = (C->callback)(C->cookie, status);

	/* Free the cookie. */
	free(C);

	/* Return error or value from user callback. */
	return (rc);
}