static void acl_xml_node_reset(ACL_XML_NODE *node) { ACL_VSTRING_RESET(node->ltag); ACL_VSTRING_RESET(node->rtag); ACL_VSTRING_RESET(node->text); ACL_VSTRING_TERMINATE(node->ltag); ACL_VSTRING_TERMINATE(node->rtag); ACL_VSTRING_TERMINATE(node->text); node->id = NULL; if (node->attr_list) acl_array_clean(node->attr_list, (void (*)(void*)) acl_xml_attr_free); node->parent = NULL; acl_ring_init(&node->children); node->depth = 0; acl_ring_init(&node->node); node->curr_attr = NULL; node->quote = 0; node->last_ch = 0; node->nlt = 0; node->meta[0] = 0; node->flag = 0; node->status = ACL_XML_S_NXT; }
static void fiber_check(void) { if (__thread_fiber != NULL) return; acl_assert(acl_pthread_once(&__once_control, thread_init) == 0); __thread_fiber = (FIBER_TLS *) acl_mycalloc(1, sizeof(FIBER_TLS)); #ifdef USE_JMP /* set context NULL when using setjmp that setcontext will not be * called in fiber_swap. */ __thread_fiber->original.context = NULL; #else __thread_fiber->original.context = (ucontext_t *) acl_mycalloc(1, sizeof(ucontext_t)); #endif __thread_fiber->fibers = NULL; __thread_fiber->size = 0; __thread_fiber->slot = 0; __thread_fiber->idgen = 0; __thread_fiber->count = 0; acl_ring_init(&__thread_fiber->ready); acl_ring_init(&__thread_fiber->dead); if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { __main_fiber = __thread_fiber; atexit(fiber_schedule_main_free); } else if (acl_pthread_setspecific(__fiber_key, __thread_fiber) != 0) acl_msg_fatal("acl_pthread_setspecific error!"); }
ACL_FIBER_MUTEX *acl_fiber_mutex_create(void) { ACL_FIBER_MUTEX *lk = (ACL_FIBER_MUTEX *) acl_mymalloc(sizeof(ACL_FIBER_MUTEX)); lk->owner = NULL; acl_ring_init(&lk->me); acl_ring_init(&lk->waiting); return lk; }
ACL_FIBER_RWLOCK *acl_fiber_rwlock_create(void) { ACL_FIBER_RWLOCK *lk = (ACL_FIBER_RWLOCK *) acl_mymalloc(sizeof(ACL_FIBER_RWLOCK)); lk->readers = 0; lk->writer = NULL; acl_ring_init(&lk->rwaiting); acl_ring_init(&lk->wwaiting); return lk; }
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); }
static void event_init(ACL_EVENT *eventp, int fdsize, int delay_sec, int delay_usec) { eventp->fdsize = fdsize; /* eventp->fdtab_free_cnt = 0; */ eventp->fdcnt = 0; eventp->fdcnt_ready = 0; eventp->fdtabs = (ACL_EVENT_FDTABLE **) acl_mycalloc(fdsize,sizeof(ACL_EVENT_FDTABLE *)); eventp->fdtabs_ready = (ACL_EVENT_FDTABLE **) acl_mycalloc(fdsize, sizeof(ACL_EVENT_FDTABLE *)); eventp->maxfd = 0; eventp->nested = 0; eventp->delay_sec = delay_sec + delay_usec / 1000000; eventp->delay_usec = delay_usec % 1000000; acl_ring_init(&eventp->timer_head); eventp->timer_keep = 0; SET_TIME(eventp->present); SET_TIME(eventp->last_debug); eventp->check_inter = 100000; /* default: 100 ms */ if (eventp->init_fn) eventp->init_fn(eventp); }
void fiber_io_check(void) { if (__thread_fiber != NULL) return; acl_assert(acl_pthread_once(&__once_control, thread_init) == 0); __maxfd = acl_open_limit(0); if (__maxfd <= 0) __maxfd = MAXFD; __thread_fiber = (FIBER_TLS *) acl_mymalloc(sizeof(FIBER_TLS)); __thread_fiber->event = event_create(__maxfd); __thread_fiber->io_fibers = (ACL_FIBER **) acl_mycalloc(__maxfd, sizeof(ACL_FIBER *)); __thread_fiber->ev_fiber = acl_fiber_create(fiber_io_loop, __thread_fiber->event, STACK_SIZE); __thread_fiber->io_count = 0; __thread_fiber->nsleeping = 0; __thread_fiber->io_stop = 0; acl_ring_init(&__thread_fiber->ev_timer); if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { __main_fiber = __thread_fiber; atexit(fiber_io_main_free); } else if (acl_pthread_setspecific(__fiber_key, __thread_fiber) != 0) acl_msg_fatal("acl_pthread_setspecific error!"); }
ICMP_CHAT *icmp_chat_create(ACL_AIO* aio, int check_tid) { ICMP_CHAT *chat; chat = (ICMP_CHAT*) acl_mycalloc(1, sizeof(ICMP_CHAT)); chat->aio = aio; acl_ring_init(&chat->host_head); chat->is = icmp_stream_open(aio); chat->seq_no = 0; chat->count = 0; #ifdef ACL_UNIX chat->pid = getpid(); #elif defined(ACL_WINDOWS) chat->pid = _getpid(); #endif chat->tid = (unsigned long) acl_pthread_self(); chat->check_tid = check_tid; if (aio != NULL) icmp_chat_aio_init(chat, aio); else icmp_chat_sio_init(chat); return (chat); }
ACL_FIBER_SEM *acl_fiber_sem_create(int num) { ACL_FIBER_SEM *sem = (ACL_FIBER_SEM *) acl_mymalloc(sizeof(ACL_FIBER_SEM)); sem->num = num; acl_ring_init(&sem->waiting); sem->tid = acl_pthread_self(); return sem; }
ACL_XML_NODE *acl_xml_node_alloc(ACL_XML *xml) { ACL_XML_NODE *node; if (xml->node_cache) { node = (ACL_XML_NODE*) xml->node_cache->pop_back(xml->node_cache); if (node) { acl_xml_node_reset(node); node->xml = xml; xml->node_cnt++; return (node); } } if (xml->slice) node = (ACL_XML_NODE*) acl_slice_pool_calloc(__FILE__, __LINE__, xml->slice, 1, sizeof(ACL_XML_NODE)); else node = (ACL_XML_NODE*) acl_mycalloc(1, sizeof(ACL_XML_NODE)); acl_ring_init(&node->children); acl_ring_init(&node->node); node->xml = xml; node->status = ACL_XML_S_NXT; node->ltag = acl_vstring_slice_alloc(xml->slice, 16); node->rtag = acl_vstring_slice_alloc(xml->slice, 16); node->text = acl_vstring_slice_alloc(xml->slice, 16); node->attr_list = acl_array_create(5); xml->node_cnt++; node->iter_head = node_iter_head; node->iter_next = node_iter_next; node->iter_tail = node_iter_tail; node->iter_prev = node_iter_prev; return (node); }
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); }
/* 查询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); }