Exemple #1
0
void
VTIM_sleep(double t)
{
#ifdef HAVE_NANOSLEEP
	struct timespec ts;

	ts = VTIM_timespec(t);

	(void)nanosleep(&ts, NULL);
#else
	if (t >= 1.) {
		(void)sleep(floor(t));
		t -= floor(t);
	}
	/* XXX: usleep() is not mandated to be thread safe */
	t *= 1e6;
	if (t > 0)
		(void)usleep(floor(t));
#endif
}
static void *
vws_thread(void *priv)
{
	struct sess *sp;
	struct vws *vws;

	CAST_OBJ_NOTNULL(vws, priv, VWS_MAGIC);
	/*
	 * timeouts:
	 *
	 * min_ts : Minimum timeout for port_getn
	 * min_t  : ^ equivalent in floating point representation
	 *
	 * max_ts : Maximum timeout for port_getn
	 * max_t  : ^ equivalent in floating point representation
	 *
	 * with (nevents == 1), we should always choose the correct port_getn
	 * timeout to check session timeouts, so max is just a safety measure
	 * (if this implementation is correct, it could be set to an "infinte"
	 *  value)
	 *
	 * with (nevents > 1), min and max define the acceptable range for
	 * - additional latency of keep-alive connections and
	 * - additional tolerance for handling session timeouts
	 *
	 */
	static struct timespec min_ts = {0L,    100L /*ms*/  * 1000L /*us*/  * 1000L /*ns*/};
	static double          min_t  = 0.1; /* 100    ms*/
	static struct timespec max_ts = {1L, 0L};		/* 1 second */
	static double	       max_t  = 1.0;			/* 1 second */

	/* XXX: These should probably go in vws ? */
	struct timespec ts;
	struct timespec *timeout;

	vws->dport = port_create();
	assert(vws->dport >= 0);

	timeout = &max_ts;

	while (1) {
		port_event_t ev[MAX_EVENTS];
		int nevents, ei, ret;
		double now, deadline;

		/*
		 * XXX Do we want to scale this up dynamically to increase
		 *     efficiency in high throughput situations? - would need to
		 *     start with one to keep latency low at any rate
		 *
		 *     Note: when increasing nevents, we must lower min_ts
		 *	     and max_ts
		 */
		nevents = 1;

		/*
		 * see disucssion in
		 * - https://issues.apache.org/bugzilla/show_bug.cgi?id=47645
		 * - http://mail.opensolaris.org/pipermail/networking-discuss/2009-August/011979.html
		 *
		 * comment from apr/poll/unix/port.c :
		 *
		 * This confusing API can return an event at the same time
		 * that it reports EINTR or ETIME.
		 *
		 */

		ret = port_getn(vws->dport, ev, MAX_EVENTS, &nevents, timeout);

		if (ret < 0)
			assert((errno == EINTR) || (errno == ETIME));

		for (ei = 0; ei < nevents; ei++)
			vws_port_ev(vws, ev + ei);

		/* check for timeouts */
		now = VTIM_real();
		deadline = now - cache_param->sess_timeout;

		/*
		 * This loop assumes that the oldest sessions are always at the
		 * beginning of the list (which is the case if we guarantee to
		 * enqueue at the tail only
		 *
		 */

		for (;;) {
			sp = VTAILQ_FIRST(&vws->sesshead);
			if (sp == NULL)
				break;
			if (sp->t_open > deadline) {
				break;
			}
			VTAILQ_REMOVE(&vws->sesshead, sp, list);
			if(sp->fd != -1) {
				vws_del(vws, sp->fd);
			}
			SES_Delete(sp, "timeout");
		}

		/*
		 * Calculate the timeout for the next get_portn
		 */

		if (sp) {
			double tmo = (sp->t_open + cache_param->sess_timeout) - now;

			/* we should have removed all sps whose timeout has passed */
			assert(tmo > 0.0);

			if (tmo < min_t) {
				timeout = &min_ts;
			} else if (tmo > max_t) {
				timeout = &max_ts;
			} else {
				ts = VTIM_timespec(tmo);
				timeout = &ts;
			}
		} else {
			timeout = &max_ts;
		}
	}
}