/* * 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; }
/* * 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); }
/** * 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); }
/** * 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); }