/* * This function temporarily disables listening so that another new instance * can start listening. It is designed to be called upon reception of a * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop * the proxy, or a SIGTTIN can be sent to listen again. */ void pause_proxies(void) { int err; struct proxy *p; err = 0; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->cap & PR_CAP_FE && p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) { Warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); pause_proxy(p); if (p->state != PR_STPAUSED) { err |= 1; Warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); } } p = p->next; } if (err) { Warning("Some proxies refused to pause, performing soft stop now.\n"); send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n"); soft_stop(); } }
/* * This function reactivates listening. This can be used after a call to * sig_pause(), for example when a new instance has failed starting up. * It is designed to be called upon reception of a SIGTTIN. */ void resume_proxies(void) { int err; struct proxy *p; struct peers *prs; err = 0; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { err |= !resume_proxy(p); p = p->next; } prs = peers; while (prs) { p = prs->peers_fe; err |= !resume_proxy(p); prs = prs->next; } if (err) { Warning("Some proxies refused to resume, a restart is probably needed to resume safe operations.\n"); send_log(p, LOG_WARNING, "Some proxies refused to resume, a restart is probably needed to resume safe operations.\n"); } }
/* * This function temporarily disables listening so that another new instance * can start listening. It is designed to be called upon reception of a * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop * the proxy, or a SIGTTIN can be sent to listen again. */ void pause_proxies(void) { int err; struct proxy *p; struct peers *prs; err = 0; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { err |= !pause_proxy(p); p = p->next; } prs = peers; while (prs) { p = prs->peers_fe; err |= !pause_proxy(p); prs = prs->next; } if (err) { Warning("Some proxies refused to pause, performing soft stop now.\n"); send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n"); soft_stop(); } }
/* * this function disables health-check servers so that the process will quickly be ignored * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace * time will not be used since it would already not listen anymore to the socket. */ void soft_stop(void) { struct proxy *p; struct peers *prs; stopping = 1; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->state != PR_STSTOPPED) { Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); p->stop_time = tick_add(now_ms, p->grace); } if (p->table.size && p->table.sync_task) task_wakeup(p->table.sync_task, TASK_WOKEN_MSG); /* wake every proxy task up so that they can handle the stopping */ task_wakeup(p->task, TASK_WOKEN_MSG); p = p->next; } prs = peers; while (prs) { stop_proxy((struct proxy *)prs->peers_fe); prs = prs->next; } /* signal zero is used to broadcast the "stopping" event */ signal_handler(0); }
/* * This function reactivates listening. This can be used after a call to * sig_pause(), for example when a new instance has failed starting up. * It is designed to be called upon reception of a SIGTTIN. */ void listen_proxies(void) { struct proxy *p; struct listener *l; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->state == PR_STPAUSED) { Warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); for (l = p->listen; l != NULL; l = l->next) { if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) { if (actconn < global.maxconn && p->feconn < p->maxconn) { EV_FD_SET(l->fd, DIR_RD); p->state = PR_STRUN; } else p->state = PR_STIDLE; } else { int port; if (l->addr.ss_family == AF_INET6) { port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port); Warning("Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); } else if (l->addr.ss_family == AF_INET) { port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port); Warning("Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); } else { Warning("Bind on socket %d busy while trying to enable %s %s.\n", l->luid, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Bind on socket %d busy while trying to enable %s %s.\n", l->luid, proxy_cap_str(p->cap), p->id); } /* Another port might have been enabled. Let's stop everything. */ pause_proxy(p); break; } } } p = p->next; } }
/* * this function disables health-check servers so that the process will quickly be ignored * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace * time will not be used since it would already not listen anymore to the socket. */ void soft_stop(void) { struct proxy *p; stopping = 1; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->state != PR_STSTOPPED) { Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); p->stop_time = tick_add(now_ms, p->grace); } p = p->next; } }
REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) { int i; int wait_time; struct timespec timeout_ts; unsigned int nevlist; int fd, old_fd; int status; /* * Scan the list of file descriptors with an updated status: */ for (i = 0; i < fd_nbupdt; i++) { fd = fd_updt[i]; _HA_ATOMIC_AND(&fdtab[fd].update_mask, ~tid_bit); if (fdtab[fd].owner == NULL) { activity[tid].poll_drop++; continue; } _update_fd(fd); } fd_nbupdt = 0; /* Scan the global update list */ for (old_fd = fd = update_list.first; fd != -1; fd = fdtab[fd].update.next) { if (fd == -2) { fd = old_fd; continue; } else if (fd <= -3) fd = -fd -4; if (fd == -1) break; if (fdtab[fd].update_mask & tid_bit) done_update_polling(fd); else continue; if (!fdtab[fd].owner) continue; _update_fd(fd); } thread_harmless_now(); /* * Determine how long to wait for events to materialise on the port. */ wait_time = wake ? 0 : compute_poll_timeout(exp); tv_entering_poll(); activity_count_runtime(); do { int timeout = (global.tune.options & GTUNE_BUSY_POLLING) ? 0 : wait_time; int interrupted = 0; nevlist = 1; /* desired number of events to be retrieved */ timeout_ts.tv_sec = (timeout / 1000); timeout_ts.tv_nsec = (timeout % 1000) * 1000000; status = port_getn(evports_fd[tid], evports_evlist, evports_evlist_max, &nevlist, /* updated to the number of events retrieved */ &timeout_ts); if (status != 0) { int e = errno; switch (e) { case ETIME: /* * Though the manual page has not historically made it * clear, port_getn() can return -1 with an errno of * ETIME and still have returned some number of events. */ /* nevlist >= 0 */ break; default: nevlist = 0; interrupted = 1; break; } } tv_update_date(timeout, nevlist); if (nevlist || interrupted) break; if (timeout || !wait_time) break; if (signal_queue_len || wake) break; if (tick_isset(exp) && tick_is_expired(exp, now_ms)) break; } while(1); tv_leaving_poll(wait_time, nevlist); thread_harmless_end(); for (i = 0; i < nevlist; i++) { unsigned int n = 0; int events, rebind_events; fd = evports_evlist[i].portev_object; events = evports_evlist[i].portev_events; if (fdtab[fd].owner == NULL) { activity[tid].poll_dead++; continue; } if (!(fdtab[fd].thread_mask & tid_bit)) { activity[tid].poll_skip++; continue; } /* * By virtue of receiving an event for this file descriptor, it * is no longer associated with the port in question. Store * the previous event mask so that we may reassociate after * processing is complete. */ rebind_events = evports_state_to_events(fdtab[fd].state); /* rebind_events != 0 */ /* * Set bits based on the events we received from the port: */ if (events & POLLIN) n |= FD_POLL_IN; if (events & POLLOUT) n |= FD_POLL_OUT; if (events & POLLERR) n |= FD_POLL_ERR; if (events & POLLHUP) n |= FD_POLL_HUP; /* * Call connection processing callbacks. Note that it's * possible for this processing to alter the required event * port assocation; i.e., the "state" member of the "fdtab" * entry. If it changes, the fd will be placed on the updated * list for processing the next time we are called. */ fd_update_events(fd, n); /* * This file descriptor was closed during the processing of * polled events. No need to reassociate. */ if (fdtab[fd].owner == NULL) continue; /* * Reassociate with the port, using the same event mask as * before. This call will not result in a dissociation as we * asserted that _some_ events needed to be rebound above. * * Reassociating with the same mask allows us to mimic the * level-triggered behaviour of poll(2). In the event that we * are interested in the same events on the next turn of the * loop, this represents no extra work. * * If this additional port_associate(3C) call becomes a * performance problem, we would need to verify that we can * correctly interact with the file descriptor cache and update * list (see "src/fd.c") to avoid reassociating here, or to use * a different events mask. */ evports_resync_fd(fd, rebind_events); } }
void * fio_count(void *data) { int i; uint64_t my_rxcount = 0, my_txcount = 0, unuse_count = 0, prev_rx = 0, prev_tx = 0; struct timeval tic, toc; int report_interval = 1*1000; /* report interval */ char dump_buf_rx[2000] = {0}; char dump_buf_tx[2000] = {0}; char dump_buf[1000] = {0}; g_logfac = syslog_get_facility(g_str_logfac); g_log_host_name = sysconfig.src_ip.name; int bucfd = buc_open(sysconfig.dst_ip[0].name, sysconfig.src_port); if (bucfd == -1) return NULL; gettimeofday(&toc, NULL); while (sysconfig.working) { struct timeval delta; uint64_t pps_rx, pps_tx; int done = 0; dump_buf_rx[0] = '\0'; dump_buf_tx[0] = '\0'; delta.tv_sec = report_interval/1000; delta.tv_usec = (report_interval%1000)*1000; //计时== select(0, NULL, NULL, NULL, &delta); tv_update_date(); timersub(&fio_now, &toc, &toc); my_rxcount = 0; my_txcount = 0; unuse_count = 0; for (i = 0; i < sysconfig.nthreads; i++) { my_rxcount += g_contexts[i].nics[0].rxcount; my_rxcount += g_contexts[i].nics[1].rxcount; my_txcount += g_contexts[i].nics[0].txcount; my_txcount += g_contexts[i].nics[1].txcount; unuse_count += g_contexts[i].nics[0].unuse_count; unuse_count += g_contexts[i].nics[1].unuse_count; sprintf(dump_buf, "%"LU64" ", g_contexts[i].nics[0].rxcount + g_contexts[i].nics[1].rxcount); strcat(dump_buf_rx, dump_buf); sprintf(dump_buf, "%"LU64" ", g_contexts[i].nics[0].txcount + g_contexts[i].nics[1].txcount); strcat(dump_buf_tx, dump_buf); if (g_contexts[i].used == 0) done++; } pps_tx = pps_rx = toc.tv_sec* 1000000 + toc.tv_usec; if (pps_rx < 10000) continue; pps_rx = (my_rxcount - prev_rx)*1000000 / pps_rx; OD( "rx %"LU64" ppsrx %s", pps_rx, dump_buf_rx); pps_tx = (my_txcount - prev_tx)*1000000 / pps_tx; OD( "tx %"LU64" ppstx %s", pps_tx, dump_buf_tx); OD( "rx useless pkt %"LU64"\n", unuse_count); syslog_format(bucfd, "rx %"LU64" ppsrx %s\ntx %"LU64" ppstx %s\nrx useless pkt %"LU64, pps_rx, dump_buf_rx, pps_tx, dump_buf_tx, unuse_count); prev_rx = my_rxcount; prev_tx = my_txcount; toc = fio_now; fio_gnow++; if (done == sysconfig.nthreads) break; } timerclear(&tic); timerclear(&toc); OD( "I'll shutdown"); return NULL; }
/* * Linux epoll() poller */ REGPRM2 static void _do_poll(struct poller *p, int exp) { int status; int fd; int count; int updt_idx; int wait_time; int old_fd; /* first, scan the update list to find polling changes */ for (updt_idx = 0; updt_idx < fd_nbupdt; updt_idx++) { fd = fd_updt[updt_idx]; HA_ATOMIC_AND(&fdtab[fd].update_mask, ~tid_bit); if (!fdtab[fd].owner) { activity[tid].poll_drop++; continue; } _update_fd(fd); } fd_nbupdt = 0; /* Scan the global update list */ for (old_fd = fd = update_list.first; fd != -1; fd = fdtab[fd].update.next) { if (fd == -2) { fd = old_fd; continue; } else if (fd <= -3) fd = -fd -4; if (fd == -1) break; if (fdtab[fd].update_mask & tid_bit) done_update_polling(fd); else continue; if (!fdtab[fd].owner) continue; _update_fd(fd); } thread_harmless_now(); /* compute the epoll_wait() timeout */ if (!exp) wait_time = MAX_DELAY_MS; else if (tick_is_expired(exp, now_ms)) { activity[tid].poll_exp++; wait_time = 0; } else { wait_time = TICKS_TO_MS(tick_remain(now_ms, exp)) + 1; if (wait_time > MAX_DELAY_MS) wait_time = MAX_DELAY_MS; } /* now let's wait for polled events */ gettimeofday(&before_poll, NULL); status = epoll_wait(epoll_fd[tid], epoll_events, global.tune.maxpollevents, wait_time); tv_update_date(wait_time, status); measure_idle(); thread_harmless_end(); /* process polled events */ for (count = 0; count < status; count++) { unsigned int n; unsigned int e = epoll_events[count].events; fd = epoll_events[count].data.fd; if (!fdtab[fd].owner) { activity[tid].poll_dead++; continue; } if (!(fdtab[fd].thread_mask & tid_bit)) { /* FD has been migrated */ activity[tid].poll_skip++; epoll_ctl(epoll_fd[tid], EPOLL_CTL_DEL, fd, &ev); HA_ATOMIC_AND(&polled_mask[fd], ~tid_bit); continue; } /* it looks complicated but gcc can optimize it away when constants * have same values... In fact it depends on gcc :-( */ if (EPOLLIN == FD_POLL_IN && EPOLLOUT == FD_POLL_OUT && EPOLLPRI == FD_POLL_PRI && EPOLLERR == FD_POLL_ERR && EPOLLHUP == FD_POLL_HUP) { n = e & (EPOLLIN|EPOLLOUT|EPOLLPRI|EPOLLERR|EPOLLHUP); } else { n = ((e & EPOLLIN ) ? FD_POLL_IN : 0) | ((e & EPOLLPRI) ? FD_POLL_PRI : 0) | ((e & EPOLLOUT) ? FD_POLL_OUT : 0) | ((e & EPOLLERR) ? FD_POLL_ERR : 0) | ((e & EPOLLHUP) ? FD_POLL_HUP : 0); } /* always remap RDHUP to HUP as they're used similarly */ if (e & EPOLLRDHUP) { HA_ATOMIC_OR(&cur_poller.flags, HAP_POLL_F_RDHUP); n |= FD_POLL_HUP; } fd_update_events(fd, n); } /* the caller will take care of cached events */ }