Пример #1
0
int acl_fiber_sem_wait(ACL_FIBER_SEM *sem)
{
	ACL_FIBER *curr;

	if (sem->tid != acl_pthread_self())
		return -1;

	if (sem->num > 0) {
		sem->num--;
		return sem->num;
	}

	curr = acl_fiber_running();
	if (curr == NULL)
		return -1;

	acl_ring_prepend(&sem->waiting, &curr->me);
	acl_fiber_switch();

	/* if switch to me because other killed me, I should detach myself;
	 * else if because other unlock, I'll be detached twice which is
	 * hamless because ACL_RING can deal with it.
	 */
	acl_ring_detach(&curr->me);

	return sem->num;
}
Пример #2
0
void acl_fiber_ready(ACL_FIBER *fiber)
{
	if (fiber->status != FIBER_STATUS_EXITING) {
		fiber->status = FIBER_STATUS_READY;
		acl_ring_prepend(&__thread_fiber->ready, &fiber->me);
	}
}
Пример #3
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);
}
Пример #4
0
static int __lock(ACL_FIBER_MUTEX *lk, int block)
{
	ACL_FIBER *curr = acl_fiber_running();

	if (lk->owner == NULL) {
		lk->owner = acl_fiber_running();
		acl_ring_prepend(&curr->holding, &lk->me);
		return 0;
	}

	// xxx: no support recursion lock
	assert(lk->owner != curr);

	if (!block)
		return -1;

	acl_ring_prepend(&lk->waiting, &curr->me);
	curr->waiting = lk;

	acl_fiber_switch();

	/* if switch to me because other killed me, I should detach myself;
	 * else if because other unlock, I'll be detached twice which is
	 * hamless because ACL_RING can deal with it.
	 */
	acl_ring_detach(&curr->me);

	if (lk->owner == curr)
		return 0;

	if (acl_fiber_killed(curr))
		acl_msg_info("%s(%d), %s: lock fiber-%u was killed",
			__FILE__, __LINE__, __FUNCTION__, acl_fiber_id(curr));
	else
		acl_msg_warn("%s(%d), %s: qlock: owner=%p self=%p oops",
			__FILE__, __LINE__, __FUNCTION__, lk->owner, curr);

	return 0;
}
Пример #5
0
static void __create_ring(int flag, int size)
{
	MY_TYPE *my_type;
	int   i;

	for (i = 0; i < size; i++) {
		my_type = acl_mycalloc(1, sizeof(MY_TYPE));
		snprintf(my_type->name, sizeof(my_type->name), "name:%d", i);
		snprintf(my_type->value, sizeof(my_type->value), "value:%d", i);
		my_type->i = i;
		if (flag)
			acl_ring_prepend(&__ring_header, &my_type->ring_entry);
		else
			acl_ring_append(&__ring_header, &my_type->ring_entry);
	}
}
Пример #6
0
static void fiber_swap(ACL_FIBER *from, ACL_FIBER *to)
{
	if (from->status == FIBER_STATUS_EXITING) {
		size_t slot = from->slot;
		int n = acl_ring_size(&__thread_fiber->dead);

		/* if the cached dead fibers reached the limit,
		 * some will be freed
		 */
		if (n > MAX_CACHE) {
			n -= MAX_CACHE;
			fiber_kick(n);
		}

		if (!from->sys)
			__thread_fiber->count--;

		__thread_fiber->fibers[slot] =
			__thread_fiber->fibers[--__thread_fiber->slot];
		__thread_fiber->fibers[slot]->slot = slot;

		acl_ring_prepend(&__thread_fiber->dead, &from->me);
	}

#ifdef	USE_JMP
	/* use setcontext() for the initial jump, as it allows us to set up
	 * a stack, but continue with longjmp() as it's much faster.
	 */
	if (SETJMP(from->env) == 0) {
		/* context just be used once for set up a stack, which will
		 * be freed in fiber_start. The context in __thread_fiber
		 * was set NULL.
		 */
		if (to->context != NULL)
			setcontext(to->context);
		else
			LONGJMP(to->env);
	}
#else
	if (swapcontext(from->context, to->context) < 0)
		acl_msg_fatal("%s(%d), %s: swapcontext error %s",
			__FILE__, __LINE__, __FUNCTION__, acl_last_serror());
#endif
}
Пример #7
0
static int __wlock(ACL_FIBER_RWLOCK *lk, int block)
{
	ACL_FIBER *curr;

	if (lk->writer == NULL && lk->readers == 0) {
		lk->writer = acl_fiber_running();
		return 1;
	}

	if (!block)
		return 0;

	curr = acl_fiber_running();
	acl_ring_prepend(&lk->wwaiting, &curr->me);
	acl_fiber_switch();

	/* if switch to me because other killed me, I should detach myself */
	acl_ring_detach(&curr->me);

	return 1;
}
Пример #8
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);
}
Пример #9
0
void acl_xml_node_add_child(ACL_XML_NODE *parent, ACL_XML_NODE *child)
{
    acl_ring_prepend(&parent->children, &child->node);
    child->parent = parent;
}
Пример #10
0
/* 查询DNS信息,采用外挂模块的方式 */
static void thrpool_nslookup(SERVICE *service, CLIENT_ENTRY *entry,
	const char *domain, int port)
{
	const char *myname = "thrpool_nslookup";
	DNS_CTX dns_ctx;
	DNS_RING *list;
	char *ptr;

	entry->tm.stamp = time(NULL);

	memset(&dns_ctx, 0, sizeof(dns_ctx));
	dns_ctx.begin = entry->tm.stamp;
	STRNCPY(dns_ctx.domain_key, domain, sizeof(dns_ctx.domain_key));
	ptr = strchr(dns_ctx.domain_key, ':');
	/* 仅留下域名部分 */
	if (ptr)
		*ptr = 0;

	entry->server_port = port;
	if (entry->server_port <= 0)
		entry->server_port = 80;
	
	/* 将域名字符串都转换成小写,以便于进行哈希查询 */
	acl_lowercase(dns_ctx.domain_key);

	dns_ctx.context = service;
	dns_ctx.callback = thrpool_nslookup_complete;

	STRNCPY(entry->domain_key, dns_ctx.domain_key, sizeof(entry->domain_key));

	/* 先查询DNS查询表中是否已经包含本次需要被查询的域名 */
	list = (DNS_RING *) acl_htable_find(service->dns_table, dns_ctx.domain_key);
	if (list) {
		/* 将本次对同一域名的查询添加进同一个查询链中 */
		acl_ring_prepend(&list->ring, &entry->dns_entry);
		/* 将查询链对象的引用计数加1 */
		list->nrefer++;
		/* 如果该查询链已经存在,说明有查询任务等待返回,其返回后会一同将
		 * 本次任务进行触发,如果此处触发新任务,则会造成内存访问冲突,因为
		 * 查询DNS的过程是由一组线程池进行查询的。
		 * (void) dns_server_lookup(proxy_entry->aio_proxy->dns_server, &dns_ctx);
		 */
		return;
	}

	/* 创建一个新的查询链对象,并将本次查询任务加入该查询链中及将该查询链加入查询表中 */

	list = (DNS_RING *) acl_mycalloc(1, sizeof(DNS_RING));
	acl_ring_init(&list->ring);
	STRNCPY(list->domain_key, dns_ctx.domain_key, sizeof(list->domain_key));

	/* 将本次查询任务加入新的查询链中且将查询链的引用计数加1 */
	acl_ring_prepend(&list->ring, &entry->dns_entry);
	list->nrefer++;

	/* 将新的查询链加入查询表中 */
	if (acl_htable_enter(service->dns_table, list->domain_key, (char *) list) == NULL)
		acl_msg_fatal("%s: add domain(%s) to table error", myname, list->domain_key);

	/* 开始启动DNS查询过程 */
	(void) dns_server_lookup(service->dns_server, &dns_ctx);
}