Пример #1
0
void acl_fiber_schedule(void)
{
	ACL_FIBER *fiber;
	ACL_RING *head;

	acl_fiber_hook_api(1);

	for (;;) {
		head = acl_ring_pop_head(&__thread_fiber->ready);
		if (head == NULL) {
			acl_msg_info("------- NO ACL_FIBER NOW --------");
			break;
		}

		fiber = ACL_RING_TO_APPL(head, ACL_FIBER, me);
		fiber->status = FIBER_STATUS_READY;

		__thread_fiber->running = fiber;
		__thread_fiber->switched++;

		fiber_swap(&__thread_fiber->original, fiber);
		__thread_fiber->running = NULL;
	}

	/* release dead fiber */
	while ((head = acl_ring_pop_head(&__thread_fiber->dead)) != NULL) {
		fiber = ACL_RING_TO_APPL(head, ACL_FIBER, me);
		fiber_free(fiber);
	}

	acl_fiber_hook_api(0);
}
Пример #2
0
static void test(void)
{
	ACL_RING ring;

	acl_ring_init(&ring);
	for (int i = 0; i < 10; i++)
	{
		A* a = new A;
		a->m = i;
		acl_ring_prepend(&ring, &a->entry);
		printf("put %d\r\n", i);
	}

	printf("-------------------------------------------------------\r\n");

	while (true)
	{
		ACL_RING* head = acl_ring_pop_head(&ring);
		if (head == NULL)
			break;
		A* a = ACL_RING_TO_APPL(head, A, entry);
		printf("pop %d\r\n", a->m);
		delete a;
	}

	exit (0);
}
Пример #3
0
static void event_set_all(ACL_EVENT *eventp)
{
	EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp;
	ACL_EVENT_FDTABLE *fdp;
	int   i;

	/* 优先处理添加读/写监控任务, 这样可以把中间的 ADD 状态转换成正式状态 */

	eventp->fdcnt_ready = 0;

	if (eventp->present - eventp->last_check >= eventp->check_inter) {
		eventp->last_check = eventp->present;
		event_check_fds(eventp);
	}

	/* 处理任务项 */

	while (1) {
		ACL_RING *r = acl_ring_pop_head(&ev->fdp_delay_list);
		if (r == NULL)
			break;
		fdp = acl_ring_to_appl(r, ACL_EVENT_FDTABLE, delay_entry);

		if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) {
			enable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) {
			enable_write(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) {
			disable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) {
			disable_write(ev, fdp);
		}

		fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER;
	}

	for (i = 0; i < eventp->fdcnt; i++) {
		fdp = eventp->fdtabs[i];
		if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT)))
			continue;
		if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)
			&& (fdp->event_read == NULL || fdp->event_read->type == 0))
		{
			enable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)
			&& (fdp->event_write == NULL || fdp->event_write->type == 0))
		{
			enable_write(ev, fdp);
		}
	}
}
Пример #4
0
static void fiber_kick(int max)
{
	ACL_RING *head;
	ACL_FIBER *fiber;

	while (max > 0) {
		head = acl_ring_pop_head(&__thread_fiber->dead);
		if (head == NULL)
			break;
		fiber = ACL_RING_TO_APPL(head, ACL_FIBER,me);
		fiber_free(fiber);
		max--;
	}
}
Пример #5
0
static void event_set_all(ACL_EVENT *eventp)
{
	EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp;
	ACL_EVENT_FDTABLE *fdp;

	/* 优先处理添加读/写监控任务, 这样可以把 ADD 中间态转换成正式状态 */

	eventp->ready_cnt = 0;

	if (eventp->present - eventp->last_check >= eventp->check_inter
		|| eventp->read_ready > 0)
	{
		eventp->read_ready = 0;
		eventp->last_check = eventp->present;
		event_check_fds(eventp);
	}

	/* 处理任务项 */

	while (1) {
		ACL_RING *r = acl_ring_pop_head(&ev->fdp_delay_list);
		if (r == NULL)
			break;
		fdp = acl_ring_to_appl(r, ACL_EVENT_FDTABLE, delay_entry);

		if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) {
			enable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) {
			enable_write(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) {
			disable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) {
			disable_write(ev, fdp);
		}

		fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER;
	}
}
Пример #6
0
void acl_fiber_switch(void)
{
	ACL_FIBER *fiber, *current = __thread_fiber->running;
	ACL_RING *head;

#ifdef _DEBUG
	acl_assert(current);
#endif

	head = acl_ring_pop_head(&__thread_fiber->ready);

	if (head == NULL) {
		fiber_swap(current, &__thread_fiber->original);
		return;
	}

	fiber = ACL_RING_TO_APPL(head, ACL_FIBER, me);
	//fiber->status = FIBER_STATUS_READY;

	__thread_fiber->running = fiber;
	__thread_fiber->switched++;
	fiber_swap(current, __thread_fiber->running);
}
Пример #7
0
int acl_xml_node_delete(ACL_XML_NODE *node)
{
    ACL_RING *next;
    ACL_XML_NODE *node_next;
    int   n = 1;

    while ((next = acl_ring_pop_head(&node->children)) != NULL) {
        node_next = acl_ring_to_appl(next, ACL_XML_NODE, node);
        n += acl_xml_node_delete(node_next);
    }

    node->xml->node_cnt--;
    if (node->id != NULL)
        acl_htable_delete(node->xml->id_table, STR(node->id), NULL);
    if (node->xml->node_cache &&
            acl_array_size(node->xml->node_cache) < node->xml->max_cache)
    {
        node->xml->node_cache->push_back(node->xml->node_cache, node);
        acl_ring_detach(&node->node);
    } else
        acl_xml_node_free(node);
    return (n);
}
Пример #8
0
void acl_xml_reset(ACL_XML *xml)
{
    const char *myname = "acl_xml_reset";
    ACL_RING *next;
    ACL_XML_NODE *node;

    while ((next = acl_ring_pop_head(&xml->root->children)) != NULL) {
        node = acl_ring_to_appl(next, ACL_XML_NODE, node);
        (void) acl_xml_node_delete(node);
    }

    /* 因为根结点是一个虚结点,所以不需要释放,其会在调用
     * acl_xml_free 时被释放
     */
    acl_ring_detach(&xml->root->node);
    acl_xml_node_reset(xml->root);

    if (xml->node_cnt != 1)
        acl_msg_fatal("%s(%d): node_cnt(%d) invalid",
                      myname, __LINE__, xml->node_cnt);

    acl_htable_reset(xml->id_table, NULL);
    xml->curr_node = NULL;
}
Пример #9
0
int acl_xml_free(ACL_XML *xml)
{
    ACL_RING *next;
    ACL_XML_NODE *node;
    int   n = 1;

    while ((next = acl_ring_pop_head(&xml->root->children)) != NULL) {
        node = acl_ring_to_appl(next, ACL_XML_NODE, node);
        n += acl_xml_node_delete(node);
    }

    acl_xml_node_free(xml->root);
    xml->node_cnt--;
    acl_assert(xml->node_cnt == 0);
    acl_htable_free(xml->id_table, NULL);
    if (xml->node_cache != NULL)
        acl_array_free(xml->node_cache,
                       (void (*)(void*)) acl_xml_node_free);
    if (xml->slice)
        acl_slice_pool_free(__FILE__, __LINE__, xml);
    else
        acl_myfree(xml);
    return (n);
}
Пример #10
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_FN worker_fn;
	void    *worker_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->event_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->event_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);

	if (event_thr_prepare(eventp) == 0) {
		if (eventp->fdcnt_ready == 0) {
			if (select_delay <= 0)
				select_delay = 1;
			sleep(select_delay);
		}

		THREAD_UNLOCK(&event_thr->event.tb_mutex);
		goto TAG_DONE;
	}

	if (eventp->fdcnt_ready > 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(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp);
	event_thr->event.blocked = 0;

	if (nready < 0) {
		if (acl_last_error() != ACL_EINTR) {
			char  ebuf[256];
			acl_msg_fatal("%s(%d), %s: event_loop: select: %s",
				__FILE__, __LINE__, myname,
				acl_last_strerror(ebuf, sizeof(ebuf)));
		}
		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->fdtabs_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->fdcnt_ready;
			eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			continue;
		}

		if (FD_ISSET(sockfd, &rmask)) {
			fdp->stream->sys_read_ready = 1;
			/* has been set in fdtabs_ready ? */
			if ((fdp->event_type & ACL_EVENT_READ) == 0) {
				fdp->event_type |= ACL_EVENT_READ;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			}
		} else if (fdp->w_callback && FD_ISSET(sockfd, &wmask)) {
			fdp->event_type |= ACL_EVENT_WRITE;
			fdp->fdidx_ready = eventp->fdcnt_ready;
			eventp->fdtabs_ready[eventp->fdcnt_ready++] = 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->event_present);

	THREAD_LOCK(&event_thr->event.tm_mutex);

	while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) {
		if (timer->when > eventp->event_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);
		worker_fn     = timer->callback;
		worker_arg    = timer->context;

		worker_fn(ACL_EVENT_TIME, worker_arg);

		acl_myfree(timer);
	}

	event_thr_fire(eventp);
}
Пример #11
0
static ACL_FIBER *fiber_alloc(void (*fn)(ACL_FIBER *, void *),
	void *arg, size_t size)
{
	ACL_FIBER *fiber;
	sigset_t zero;
	union cc_arg carg;
	ACL_RING *head;

	fiber_check();

#define	APPL	ACL_RING_TO_APPL

	/* try to reuse the fiber memory in dead queue */
	head = acl_ring_pop_head(&__thread_fiber->dead);
	if (head == NULL) {
		fiber = (ACL_FIBER *) acl_mycalloc(1, sizeof(ACL_FIBER));
		fiber->buff = (char *) acl_mymalloc(size);
	} else if ((fiber = APPL(head, ACL_FIBER, me))->size < size)
		fiber->buff = (char *) acl_myrealloc(fiber->buff, size);
	else
		size = fiber->size;

	fiber->errnum = 0;
	fiber->fn     = fn;
	fiber->arg    = arg;
	fiber->size   = size;
	fiber->id     = ++__thread_fiber->idgen;
	fiber->flag   = 0;
	fiber->status = FIBER_STATUS_READY;

	carg.p = fiber;

	if (fiber->context == NULL)
		fiber->context = (ucontext_t *) acl_mymalloc(sizeof(ucontext_t));
	sigemptyset(&zero);
	sigprocmask(SIG_BLOCK, &zero, &fiber->context->uc_sigmask);

	if (getcontext(fiber->context) < 0)
		acl_msg_fatal("%s(%d), %s: getcontext error: %s",
			__FILE__, __LINE__, __FUNCTION__, acl_last_serror());

	fiber->context->uc_stack.ss_sp   = fiber->buff + 8;
	fiber->context->uc_stack.ss_size = fiber->size - 64;

#ifdef	USE_JMP
	fiber->context->uc_link = NULL;
#else
	fiber->context->uc_link = __thread_fiber->original.context;
#endif

#ifdef USE_VALGRIND
	/* avoding the valgrind's warning */
	fiber->vid = VALGRIND_STACK_REGISTER(fiber->context->uc_stack.ss_sp,
			fiber->context->uc_stack.ss_sp
			+ fiber->context->uc_stack.ss_size);
#endif
	makecontext(fiber->context, (void(*)(void)) fiber_start,
		2, carg.i[0], carg.i[1]);

	return fiber;
}
Пример #12
0
static void event_set_all(ACL_EVENT *eventp)
{
	EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp;
	ACL_EVENT_FDTABLE *fdp;
	int   i;

	/* 优先处理添加读/写监控任务, 这样可以把中间的 ADD 状态转换成正式状态 */

	eventp->fdcnt_ready = 0;

	if (eventp->event_present - ev->last_check >= 1000000) {
		ev->last_check = eventp->event_present;
		for (i = 0; i < eventp->fdcnt; i++) {
			fdp = eventp->fdtabs[i];
			if ((fdp->stream->flag & ACL_VSTREAM_FLAG_BAD) != 0) {
				fdp->stream->flag &= ~ACL_VSTREAM_FLAG_BAD;
				fdp->event_type |= ACL_EVENT_XCPT;
				fdp->fdidx_ready = eventp->fdcnt_ready;
				eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
			} else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) {
				if (ACL_VSTREAM_BFRD_CNT(fdp->stream) > 0) {
					fdp->stream->sys_read_ready = 0;
					fdp->event_type |= ACL_EVENT_READ;
					fdp->fdidx_ready = eventp->fdcnt_ready;
					eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
				} else if (fdp->r_ttl > 0 &&  eventp->event_present > fdp->r_ttl) {
					fdp->event_type |= ACL_EVENT_RW_TIMEOUT;
					fdp->fdidx_ready = eventp->fdcnt_ready;
					eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
				}
			} else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) {
				if (fdp->w_ttl > 0 && eventp->event_present > fdp->w_ttl) {
					fdp->event_type |= ACL_EVENT_RW_TIMEOUT;
					fdp->fdidx_ready = eventp->fdcnt_ready;
					eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp;
				}
			}
		}
	}

	/* 处理任务项 */

	while (1) {
		ACL_RING *r = acl_ring_pop_head(&ev->fdp_delay_list);
		if (r == NULL)
			break;
		fdp = acl_ring_to_appl(r, ACL_EVENT_FDTABLE, delay_entry);

		if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) {
			enable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) {
			enable_write(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) {
			disable_read(ev, fdp);
		}
		if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) {
			disable_write(ev, fdp);
		}

		fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER;
	}
}
Пример #13
0
/* DNS查询结果之后的回调函数 */
static void thrpool_nslookup_complete(const DNS_CTX *dns_ctx)
{
	const char *myname = "thrpool_nslookup_complte";
	SERVICE *service = (SERVICE *) dns_ctx->context;
	DNS_RING *list;
	ACL_RING *ring_ptr;
	CLIENT_ENTRY *entry;
	time_t inter, now;

	list = (DNS_RING *) acl_htable_find(service->dns_table,
				dns_ctx->domain_key);
	if (list == NULL) {
		acl_msg_warn(NULL, "%s: domain(%s) not found maybe handled",
			myname, dns_ctx->domain_key);
		return;
	}

	time(&now);
	inter = now - dns_ctx->begin;

	/* 如果查询时间过长,则给出警告信息 */
	if (inter >= 5)
		acl_msg_warn("%s(%d): dns search time=%d, domain(%s)",
			myname, __LINE__, time(NULL) - dns_ctx->begin,
			dns_ctx->domain_key);

	while (1) {
		ring_ptr = acl_ring_pop_head(&list->ring);
		if (ring_ptr == NULL)
			break;

		list->nrefer--;

		entry = ACL_RING_TO_APPL(ring_ptr, CLIENT_ENTRY, dns_entry);

		entry->tm.dns_lookup = now - entry->tm.stamp;
		entry->tm.stamp = now;

		if (dns_ctx->ip_cnt <= 0) {
			acl_msg_error("%s(%d): dns not found domain(%s)",
				myname, __LINE__, dns_ctx->domain_key);
			if (entry->client == NULL)
				acl_msg_fatal("%s(%d): client null",
					__FILE__, __LINE__);

			if (entry->dns_errmsg) {
				/* XXX: 因为此处可能会有两处关闭 client 流的地方:
				 * acl_aio_writen 及 forward_complete,为防止重复
				 * 关闭造成的内存访问非法,需要 * 在第一个可能关闭
				 * 的函数(acl_aio_writen)调用前提升 client 流的
				 * 引用值,并且在该函数返回后再恢复引用值
				 */

				acl_aio_refer(entry->client);
				acl_aio_writen(entry->client, entry->dns_errmsg,
					(int) strlen(entry->dns_errmsg));
				/* 恢复refer值 */
				acl_aio_unrefer(entry->client);
			}

			entry->nslookup_notify_fn(entry, NSLOOKUP_ERR);

			continue;
		}

		if (acl_do_debug(20, 2)) {
			int   i;

			for (i = 0; i < dns_ctx->ip_cnt; i++)
				acl_msg_info("%s(%d): domain(%s), ip%d(%s)",
					myname, __LINE__, dns_ctx->domain_key,
					i, dns_ctx->ip[i]);
		}
		
		/* 将查得的所有DNS结果都拷贝至请求对象中 */
		memcpy(&entry->dns_ctx, dns_ctx, sizeof(entry->dns_ctx));

		/* 下面注释部分被打开,便可以测试连接重试功能:)-- zsx, 2008.2.28
		 * strcpy(proxy_entry->dns_ctx.ip[1], proxy_entry->dns_ctx.ip[0]);
		 * strcpy(proxy_entry->dns_ctx.ip[0], "127.0.0.1");
		 * if (proxy_entry->dns_ctx.ip_cnt < 2)
		 *	proxy_entry->dns_ctx.ip_cnt = 2;
		 */
		entry->ip_idx = 0;
		entry->nslookup_notify_fn(entry, NSLOOKUP_OK);
	}

	acl_htable_delete(service->dns_table, dns_ctx->domain_key, NULL);
	if (list->nrefer <= 0)
		acl_myfree(list);
	else
		acl_msg_fatal("%s(%d): list's nrefer=%d",
			myname, __LINE__, list->nrefer);
}