Exemple #1
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp;
	ACL_EVENT_NOTIFY_TIME timer_fn;
	void    *timer_arg;
	ACL_EVENT_TIMER *timer;
	int   delay, nready;
	ACL_EVENT_FDTABLE *fdp;
	EVENT_BUFFER *bp;

	delay = (int) (eventp->delay_sec * 1000 + eventp->delay_usec / 1000);
	if (delay < 0)
		delay = 0; /* 0 milliseconds at least */

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 根据定时器任务的最近任务计算 epoll/kqueue/devpoll 的检测超时上限 */

	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = (timer->when - eventp->present) / 1000;

		if (n <= 0)
			delay = 0;
		else if ((int) n < delay) {
			delay = (int) n;
			if (delay <= 0)  /* xxx */
				delay = 100;
		}
	}

	/* 设置描述字对象的状态,添加/删除之前设置的描述字对象 */

	event_set_all(eventp);

	if (eventp->fdcnt == 0) {
		if (eventp->fdcnt_ready == 0)
			sleep(1);
		goto TAG_DONE;
	}

	/* 如果已经有描述字准备好则检测超时时间置 0 */

	if (eventp->fdcnt_ready > 0)
		delay = 0;

	/* 调用 epoll/kquque/devpoll 系统调用检测可用描述字 */

	EVENT_BUFFER_READ(nready, ev->event_fd, ev->event_buf,
		ev->event_fdslots, delay);

	if (eventp->nested++ > 0)
		acl_msg_fatal("%s(%d): recursive call, nested: %d",
			myname, __LINE__, eventp->nested);
	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			acl_msg_fatal("%s(%d), %s: select: %s", __FILE__,
				__LINE__, myname, acl_last_serror());
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	/* 检查检测结果 */

	for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) {
#ifdef	USE_FDMAP
		ACL_SOCKET sockfd;

		sockfd = EVENT_GET_FD(bp);
		fdp = acl_fdmap_ctx(ev->fdmap, sockfd);
		if (fdp == NULL || fdp->stream == NULL)
			continue;
		if (sockfd != ACL_VSTREAM_SOCK(fdp->stream))
			acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname,
				__LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream));
#else
		fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp);
		if (fdp == NULL || fdp->stream == NULL)
			continue;
#endif

		/* 如果该描述字对象已经在被设置为异常或超时状态则继续 */

		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		/* 检查描述字是否可读 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) {

			/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发
			 * ACL_VSTREAM 流在读时调用系统的 read 函数
			 */

			fdp->stream->sys_read_ready = 1;

			/* 给该描述字对象附加可读属性 */

			if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				if (fdp->listener)
					fdp->event_type |= ACL_EVENT_ACCEPT;

				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		}

		/* 检查描述字是否可写 */

		if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) {

			/* 给该描述字对象附加可写属性 */

			if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		}

#ifdef	EVENT_TEST_ERROR
		if (EVENT_TEST_ERROR(bp)) {
			/* 如果出现异常则设置异常属性 */

			if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_XCPT;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		}
#endif
	}

TAG_DONE:

	/*
	 * Deliver timer events. Requests are sorted: we can stop when we reach
	 * the future or the list end. Allow the application to update the timer
	 * queue while it is being called back. To this end, we repeatedly pop
	 * the first request off the timer queue before delivering the event to
	 * the application.
	 */

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->present)
			break;
		timer_fn  = timer->callback;
		timer_arg = timer->context;

		/* 定时器时间间隔 > 0 且允许定时器被循环调用,则重设定时器 */
		if (timer->delay > 0 && timer->keep) {
			timer->ncount++;
			eventp->timer_request(eventp, timer->callback,
				timer->context, timer->delay, timer->keep);
		} else {
			acl_ring_detach(&timer->ring);	/* first this */
			timer->nrefer--;
			if (timer->nrefer != 0)
				acl_msg_fatal("%s(%d): nrefer(%d) != 0",
					myname, __LINE__, timer->nrefer);
			acl_myfree(timer);
		}
		timer_fn(ACL_EVENT_TIME, eventp, timer_arg);
	}

	/* 处理准备好的描述字事件 */

	if (eventp->fdcnt_ready > 0)
		event_fire(eventp);

	eventp->nested--;
}
Exemple #2
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp;
	ACL_EVENT_NOTIFY_TIME timer_fn;
	void    *timer_arg;
	ACL_EVENT_TIMER *timer;
	int   delay;
	ACL_EVENT_FDTABLE *fdp;

	delay = (int) (eventp->delay_sec * 1000 + eventp->delay_usec / 1000);
	if (delay < 0)
		delay = 0; /* 0 milliseconds at least */

	SET_TIME(eventp->present);

	/*
	 * Find out when the next timer would go off. Timer requests are sorted.
	 * If any timer is scheduled, adjust the delay appropriately.
	 */
	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = (timer->when - eventp->present) / 1000;

		if (n <= 0)
			delay = 0;
		else if ((int) n < delay)
			delay = (int) n;
	}

	eventp->nested++;

	event_set_all(eventp);

	if (eventp->fdcnt == 0) {
		if (eventp->fdcnt_ready == 0)
			sleep(1);
		goto TAG_DONE;
	}

	if (eventp->fdcnt_ready > 0)
		delay = 0;

TAG_DONE:

	/*
	* Deliver timer events. Requests are sorted: we can stop when we reach
	* the future or the list end. Allow the application to update the timer
	* queue while it is being called back. To this end, we repeatedly pop
	* the first request off the timer queue before delivering the event to
	* the application.
	*/
	SET_TIME(eventp->present);
	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->present)
			break;
		timer_fn  = timer->callback;
		timer_arg = timer->context;

		/* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */
		if (timer->delay > 0 && timer->keep) {
			timer->ncount++;
			eventp->timer_request(eventp, timer->callback,
				timer->context, timer->delay, timer->keep);
		} else {
			acl_ring_detach(&timer->ring);		/* first this */
			timer->nrefer--;
			if (timer->nrefer != 0)
				acl_msg_fatal("%s(%d): nrefer(%d) != 0",
					myname, __LINE__, timer->nrefer);
			acl_myfree(timer);
		}
		timer_fn(ACL_EVENT_TIME, eventp, timer_arg);
	}

	for (;;) {
		BOOL isSuccess = FALSE;
		DWORD bytesTransferred = 0;
		DWORD iocpKey = 0;
		DWORD lastError = 0;
		IOCP_EVENT *iocp_event = NULL;

		isSuccess = GetQueuedCompletionStatus(ev->h_iocp,
			&bytesTransferred, (DWORD*) &fdp,
			(OVERLAPPED**) &iocp_event, delay);

		if (!isSuccess) {

			if (iocp_event == NULL)
				break;
			if (iocp_event->type == IOCP_EVENT_DEAD)
				acl_myfree(iocp_event);
			else if (iocp_event->fdp == NULL) {
				acl_msg_warn("%s(%d): fdp null",
					myname, __LINE__);
				acl_myfree(iocp_event);
			} else if (iocp_event->fdp != fdp)
				acl_msg_fatal("%s(%d): invalid fdp",
					myname, __LINE__);
			else if (!(fdp->event_type & (ACL_EVENT_XCPT
				| ACL_EVENT_RW_TIMEOUT)))
			{
				fdp->event_type |= ACL_EVENT_XCPT;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready] = fdp;
				eventp->fdcnt_ready++;
			}
			continue;
		}

		acl_assert(fdp == iocp_event->fdp);

		if ((fdp->event_type & (ACL_EVENT_XCPT
			| ACL_EVENT_RW_TIMEOUT)))
		{
			continue;
		}

		if (iocp_event->type == IOCP_EVENT_READ) {
			acl_assert(fdp->event_read == iocp_event);
			iocp_event->type &= ~IOCP_EVENT_READ;
			fdp->stream->sys_read_ready = 1;
			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready] = fdp;
				eventp->fdcnt_ready++;
			}
		}
		if (iocp_event->type == IOCP_EVENT_WRITE) {
			acl_assert(fdp->event_write == iocp_event);
			iocp_event->type &= ~IOCP_EVENT_WRITE;
			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready] = fdp;
				eventp->fdcnt_ready++;
			}
		}
		delay = 0;
	}

	if (eventp->fdcnt_ready > 0)
		event_fire(eventp);
	eventp->nested--;
}
Exemple #3
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_SELECT *ev = (EVENT_SELECT *) eventp;
	ACL_EVENT_NOTIFY_TIME timer_fn;
	void    *timer_arg;
	ACL_SOCKET sockfd;
	ACL_EVENT_TIMER *timer;
	int   nready, i;
	acl_int64 delay;
	ACL_EVENT_FDTABLE *fdp;
	struct timeval tv, *tvp;
	fd_set rmask;  /* enabled read events */
	fd_set wmask;  /* enabled write events */
	fd_set xmask;  /* for bad news mostly */

	delay = eventp->delay_sec * 1000000 + eventp->delay_usec;

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 根据定时器任务的最近任务计算 select 的检测超时上限 */

	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		acl_int64 n = timer->when - eventp->present;

		if (n <= 0)
			delay = 0;
		else if (n < delay)
			delay = n;
	}

	/* 调用 event_prepare 检查有多少个描述字需要通过 select 进行检测 */

	if (event_prepare(eventp) == 0) {
		if (eventp->ready_cnt == 0) {
			delay /= 1000000;
			if (delay <= 0)
				delay = 1;
			/* 为避免循环过快,休眠一下 */
			sleep((int) delay);
		}

		goto TAG_DONE;
	}

	if (eventp->ready_cnt > 0) {
		tv.tv_sec  = 0;
		tv.tv_usec = 0;
		tvp = &tv;
	} else if (delay >= 0) {
#if defined(ACL_WINDOWS)
		tv.tv_sec  = (long) delay / 1000000;
		tv.tv_usec = (unsigned long) (delay - tv.tv_sec * 1000000);
#else
		tv.tv_sec  = (time_t) delay / 1000000;
		tv.tv_usec = (suseconds_t) (delay - tv.tv_sec * 1000000);
#endif
		tvp = &tv;
	} else
		tvp = NULL;

	rmask = ev->rmask;
	wmask = ev->wmask;
	xmask = ev->xmask;

	/* 调用 select 系统调用检测可用描述字 */

#ifdef ACL_WINDOWS
	nready = select(0, &rmask, &wmask, &xmask, tvp);
#else
	nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp);
#endif

	if (eventp->nested++ > 0)
		acl_msg_fatal("%s(%d): recursive call(%d)",
			myname, __LINE__, eventp->nested);
	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			acl_msg_fatal("%s(%d), %s: select: %s", __FILE__,
				__LINE__, myname, acl_last_serror());
		}
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	/* 检查 select 的检测结果集合 */

	/* if some fdp was cleared from eventp->fdtabs in timer callback,
	 * which has no effection on the rest fdp in eventp->fdtabs
	 */

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = eventp->fdtabs[i];

		/* 如果该描述字对象已经在被设置为异常或超时状态则继续 */

		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		sockfd = ACL_VSTREAM_SOCK(fdp->stream);

		/* 检查描述字是否出现异常 */

		if (FD_ISSET(sockfd, &xmask)) {
			fdp->event_type |= ACL_EVENT_XCPT;
			fdp->fdidx_ready = eventp->ready_cnt;
			eventp->ready[eventp->ready_cnt++] = fdp;
			continue;
		}

		/* 检查描述字是否可读 */

		if (FD_ISSET(sockfd, &rmask)) {
			/* 给该描述字对象附加可读属性 */
			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}

			if (fdp->listener)
				fdp->event_type |= ACL_EVENT_ACCEPT;

			/* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而
			 * 触发 ACL_VSTREAM 流在读时调用系统的 read 函数
			 */
			else
				fdp->stream->read_ready = 1;
		}

		/* 检查描述字是否可写 */

		if (FD_ISSET(sockfd, &wmask)) {

			/* 给该描述字对象附加可写属性 */

			if ((fdp->event_type & (ACL_EVENT_READ
				| ACL_EVENT_WRITE)) == 0)
			{
				fdp->event_type |= ACL_EVENT_WRITE;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}
		}
	}

TAG_DONE:

	/* 调整事件引擎的时间截 */

	SET_TIME(eventp->present);

	/* 优先处理定时器中的任务 */

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->present)
			break;
		timer_fn  = timer->callback;
		timer_arg = timer->context;

		/* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,
		 * 则再重设定时器
		 */
		if (timer->delay > 0 && timer->keep) {
			timer->ncount++;
			eventp->timer_request(eventp, timer->callback,
				timer->context, timer->delay, timer->keep);
		} else {
			acl_ring_detach(&timer->ring); /* first this */
			timer->nrefer--;
			if (timer->nrefer != 0)
				acl_msg_fatal("%s(%d): nrefer(%d) != 0",
					myname, __LINE__, timer->nrefer);
			acl_myfree(timer);
		}
		timer_fn(ACL_EVENT_TIME, eventp, timer_arg);
	}

	/* 处理准备好的描述字事件 */

	if (eventp->ready_cnt > 0)
		event_fire(eventp);

	eventp->nested--;
}
Exemple #4
0
static void event_loop(ACL_EVENT *eventp)
{
	const char *myname = "event_loop";
	EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp;
	ACL_EVENT_NOTIFY_TIME timer_fn;
	void    *timer_arg;
	ACL_SOCKET sockfd;
	ACL_EVENT_TIMER *timer;
	int   select_delay, nready, i;
	ACL_EVENT_FDTABLE *fdp;
	ACL_RING timer_ring, *entry_ptr;
	struct timeval tv, *tvp;
	fd_set rmask;  /* enabled read events */
	fd_set wmask;  /* enabled write events */
	fd_set xmask;  /* for bad news mostly */

	acl_ring_init(&timer_ring);

	SET_TIME(eventp->present);
	THREAD_LOCK(&event_thr->event.tm_mutex);

	/*
	 * Find out when the next timer would go off. Timer requests are sorted.
	 * If any timer is scheduled, adjust the delay appropriately.
	 */
	if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		select_delay = (int) ((timer->when - eventp->present + 1000000 - 1)
			/ 1000000);
		if (select_delay < 0)
			select_delay = 0;
		else if (eventp->delay_sec >= 0 && select_delay > eventp->delay_sec)
			select_delay = eventp->delay_sec;
	} else
		select_delay = eventp->delay_sec;

	THREAD_UNLOCK(&event_thr->event.tm_mutex);

	THREAD_LOCK(&event_thr->event.tb_mutex);

	eventp->ready_cnt = 0;

	if (event_thr_prepare(eventp) == 0) {
		THREAD_UNLOCK(&event_thr->event.tb_mutex);

		if (eventp->ready_cnt == 0) {
			select_delay /= 1000000;
			if (select_delay <= 0)
				select_delay = 1;
			sleep((int) select_delay);
		}

		nready = 0;
		goto TAG_DONE;
	}

	if (eventp->ready_cnt > 0) {
		tv.tv_sec  = 0;
		tv.tv_usec = 0;
		tvp = &tv;
	} else if (select_delay < 0) {
		tvp = NULL;
	} else {
		tv.tv_sec  = select_delay;
		tv.tv_usec = eventp->delay_usec;
		tvp = &tv;
	}

	rmask = event_thr->rmask;
	wmask = event_thr->wmask;
	xmask = event_thr->xmask;

	THREAD_UNLOCK(&event_thr->event.tb_mutex);

	event_thr->event.blocked = 1;
	nready = select((int) eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp);
	event_thr->event.blocked = 0;

	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR)
			acl_msg_fatal("%s(%d), %s: event_loop: select: %s",
				__FILE__, __LINE__, myname, acl_last_serror());
		goto TAG_DONE;
	} else if (nready == 0)
		goto TAG_DONE;

	THREAD_LOCK(&event_thr->event.tb_mutex);

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = eventp->fdtabs[i];

		/* if fdp has been set in eventp->ready ? */
		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;

		sockfd = ACL_VSTREAM_SOCK(fdp->stream);

		if (FD_ISSET(sockfd, &xmask)) {
			fdp->event_type |= ACL_EVENT_XCPT;
			fdp->fdidx_ready = eventp->ready_cnt;
			eventp->ready[eventp->ready_cnt++] = fdp;
			continue;
		}

		if (FD_ISSET(sockfd, &rmask)) {
			/* has been set in ready ? */
			if ((fdp->event_type & ACL_EVENT_READ) == 0) {
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->ready_cnt;
				eventp->ready[eventp->ready_cnt++] = fdp;
			}

			if (fdp->listener)
				fdp->event_type |= ACL_EVENT_ACCEPT;
			else
				fdp->stream->read_ready = 1;
		} else if (fdp->w_callback && FD_ISSET(sockfd, &wmask)) {
			fdp->event_type |= ACL_EVENT_WRITE;
			fdp->fdidx_ready = eventp->ready_cnt;
			eventp->ready[eventp->ready_cnt++] = fdp;
		}
	}

	THREAD_UNLOCK(&event_thr->event.tb_mutex);

TAG_DONE:

	/*
	 * Deliver timer events. Requests are sorted: we can stop when we reach
	 * the future or the list end. Allow the application to update the timer
	 * queue while it is being called back. To this end, we repeatedly pop
	 * the first request off the timer queue before delivering the event to
	 * the application.
	 */

	SET_TIME(eventp->present);

	THREAD_LOCK(&event_thr->event.tm_mutex);

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->present)
			break;

		acl_ring_detach(&timer->ring);          /* first this */
		acl_ring_prepend(&timer_ring, &timer->ring);
	}

	THREAD_UNLOCK(&event_thr->event.tm_mutex);

	while (1) {
		entry_ptr = acl_ring_pop_head(&timer_ring);
		if (entry_ptr == NULL)
			break;

		timer     = ACL_RING_TO_TIMER(entry_ptr);
		timer_fn  = timer->callback;
		timer_arg = timer->context;

		timer_fn(ACL_EVENT_TIME, eventp, timer_arg);

		acl_myfree(timer);
	}

	if (eventp->ready_cnt > 0)
		event_thr_fire(eventp);
}