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); }
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_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); } } }
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--; } }
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; } }
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); }
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); }
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; }
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); }
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); }
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; }
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; } }
/* 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); }