static void rtpp_anetio_sthread(struct sthread_args *args) { int n, nsend, i; struct rtpp_wi *wi, *wis[100]; #ifdef RTPP_DEBUG double tp[3], runtime, sleeptime; long run_n; runtime = sleeptime = 0.0; run_n = 0; tp[0] = getdtime(); #endif for (;;) { nsend = rtpp_queue_get_items(args->out_q, wis, 100, 0); #ifdef RTPP_DEBUG tp[1] = getdtime(); #endif for (i = 0; i < nsend; i++) { wi = wis[i]; if (wi->wi_type == RTPP_WI_TYPE_SGNL) { rtpp_wi_free(wi); goto out; } do { n = sendto(wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, wi->tolen); if (wi->debug != 0) { rtpp_log_write(RTPP_LOG_DBUG, args->glog, "rtpp_anetio_sthread: sendto(%d, %p, %d, %d, %p, %d) = %d", wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, wi->tolen, n); } if (n >= 0) { wi->nsend--; } else if (n == -1 && errno != ENOBUFS) { break; } } while (wi->nsend > 0); rtpp_wi_free(wi); } #ifdef RTPP_DEBUG sleeptime += tp[1] - tp[0]; tp[0] = getdtime(); runtime += tp[0] - tp[1]; if ((run_n % 10000) == 0) { rtpp_log_write(RTPP_LOG_DBUG, args->glog, "rtpp_anetio_sthread(%p): run %ld aload = %f filtered = %f", \ args, run_n, runtime / (runtime + sleeptime), args->average_load.lastval); } if (runtime + sleeptime > 1.0) { recfilter_apply(&args->average_load, runtime / (runtime + sleeptime)); runtime = sleeptime = 0.0; } run_n += 1; #endif } out: return; }
int main(int argc, char **argv) { int i, len, controlfd; double eval, clk; long long ncycles_ref, counter; double eptime; double add_delay; struct cfg cf; char buf[256]; struct recfilter loop_error; struct PFD phase_detector; useconds_t usleep_time; struct sched_param sparam; #if RTPP_DEBUG double sleep_time, filter_lastval; #endif memset(&cf, 0, sizeof(cf)); cf.stable = malloc(sizeof(struct rtpp_cfg_stable)); if (cf.stable == NULL) { err(1, "can't allocate memory for the struct rtpp_cfg_stable"); /* NOTREACHED */ } memset(cf.stable, '\0', sizeof(struct rtpp_cfg_stable)); init_config(&cf, argc, argv); seedrandom(); cf.stable->sessions_ht = rtpp_hash_table_ctor(); if (cf.stable->sessions_ht == NULL) { err(1, "can't allocate memory for the hash table"); /* NOTREACHED */ } cf.stable->rtpp_stats = rtpp_stats_ctor(); if (cf.stable->rtpp_stats == NULL) { err(1, "can't allocate memory for the stats data"); /* NOTREACHED */ } init_port_table(&cf); controlfd = init_controlfd(&cf); if (cf.stable->nodaemon == 0) { if (rtpp_daemon(0, 0) == -1) err(1, "can't switch into daemon mode"); /* NOTREACHED */ } if (rtpp_notify_init() != 0) errx(1, "can't start notification thread"); cf.stable->glog = rtpp_log_open(cf.stable, "rtpproxy", NULL, LF_REOPEN); rtpp_log_setlevel(cf.stable->glog, cf.stable->log_level); _sig_cf = &cf; atexit(ehandler); rtpp_log_write(RTPP_LOG_INFO, cf.stable->glog, "rtpproxy started, pid %d", getpid()); i = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE); if (i >= 0) { len = sprintf(buf, "%u\n", (unsigned int)getpid()); write(i, buf, len); close(i); } else { rtpp_log_ewrite(RTPP_LOG_ERR, cf.stable->glog, "can't open pidfile for writing"); } signal(SIGHUP, sighup); signal(SIGINT, fatsignal); signal(SIGKILL, fatsignal); signal(SIGPIPE, SIG_IGN); signal(SIGTERM, fatsignal); signal(SIGXCPU, fatsignal); signal(SIGXFSZ, fatsignal); signal(SIGVTALRM, fatsignal); signal(SIGPROF, fatsignal); signal(SIGUSR1, fatsignal); signal(SIGUSR2, fatsignal); if (cf.stable->sched_policy != SCHED_OTHER) { sparam.sched_priority = sched_get_priority_max(cf.stable->sched_policy); if (sched_setscheduler(0, cf.stable->sched_policy, &sparam) == -1) { rtpp_log_ewrite(RTPP_LOG_ERR, cf.stable->glog, "sched_setscheduler(SCHED_%s, %d)", (cf.stable->sched_policy == SCHED_FIFO) ? "FIFO" : "RR", sparam.sched_priority); } } if (cf.stable->run_uname != NULL || cf.stable->run_gname != NULL) { if (drop_privileges(&cf) != 0) { rtpp_log_ewrite(RTPP_LOG_ERR, cf.stable->glog, "can't switch to requested user/group"); exit(1); } } set_rlimits(&cf); cf.stable->controlfd = controlfd; cf.sessinfo.sessions[0] = NULL; cf.sessinfo.nsessions = 0; cf.rtp_nsessions = 0; rtpp_command_async_init(&cf); rtpp_proc_async_init(&cf); counter = 0; recfilter_init(&loop_error, 0.96, 0.0, 0); PFD_init(&phase_detector, 2.0); for (;;) { eptime = getdtime(); clk = (eptime + cf.stable->sched_offset) * cf.stable->target_pfreq; ncycles_ref = llrint(clk); eval = PFD_get_error(&phase_detector, clk); #if RTPP_DEBUG filter_lastval = loop_error.lastval; #endif if (eval != 0.0) { recfilter_apply(&loop_error, sigmoid(eval)); } #if RTPP_DEBUG if (counter % (unsigned int)cf.stable->target_pfreq == 0 || counter < 1000) { rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld ncycles %f raw error1 %f, filter lastval %f, filter nextval %f", counter, clk, eval, filter_lastval, loop_error.lastval); } #endif add_delay = freqoff_to_period(cf.stable->target_pfreq, 1.0, loop_error.lastval); usleep_time = add_delay * 1000000.0; #if RTPP_DEBUG if (counter % (unsigned int)cf.stable->target_pfreq == 0 || counter < 1000) { rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld filter lastval %f, filter nextval %f, error %f", counter, filter_lastval, loop_error.lastval, sigmoid(eval)); rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld extra sleeping time %llu", counter, usleep_time); } sleep_time = getdtime(); #endif rtpp_proc_async_wakeup(cf.stable->rtpp_proc_cf, counter, ncycles_ref); usleep(usleep_time); #if RTPP_DEBUG sleep_time = getdtime() - sleep_time; if (counter % (unsigned int)cf.stable->target_pfreq == 0 || counter < 1000 || sleep_time > add_delay * 2.0) { rtpp_log_write(RTPP_LOG_DBUG, cf.stable->glog, "run %lld sleeping time required %llu sleeping time actual %f, CSV: %f,%f,%f", \ counter, usleep_time, sleep_time, (double)counter / cf.stable->target_pfreq, ((double)usleep_time) / 1000.0, sleep_time * 1000.0); } #endif counter += 1; if (cf.stable->slowshutdown != 0) { pthread_mutex_lock(&cf.sessinfo.lock); if (cf.sessinfo.nsessions == 0) { /* The below unlock is not necessary, but does not hurt either */ pthread_mutex_unlock(&cf.sessinfo.lock); rtpp_log_write(RTPP_LOG_INFO, cf.stable->glog, "deorbiting-burn sequence completed, exiting"); break; } pthread_mutex_unlock(&cf.sessinfo.lock); } } exit(0); }
static void rtpp_proc_async_run(void *arg) { struct cfg *cf; double last_tick_time; int alarm_tick, i, ndrain, rtp_only; struct rtpp_proc_async_cf *proc_cf; long long ncycles_ref; #ifdef RTPP_DEBUG int ncycles_ref_pre, last_ctick; #endif struct sign_arg *s_a; struct rtpp_wi *wi, *wis[10]; struct sthread_args *sender; double tp[4]; struct rtpp_proc_rstats *rstats; struct rtpp_stats_obj *stats_cf; cf = (struct cfg *)arg; proc_cf = cf->stable->rtpp_proc_cf; stats_cf = cf->stable->rtpp_stats; rstats = &proc_cf->rstats; last_tick_time = 0; wi = rtpp_queue_get_item(proc_cf->time_q, 0); s_a = (struct sign_arg *)rtpp_wi_sgnl_get_data(wi, NULL); #ifdef RTPP_DEBUG last_ctick = s_a->clock_tick; ncycles_ref_pre = s_a->ncycles_ref; #endif rtpp_wi_free(wi); tp[0] = getdtime(); for (;;) { i = rtpp_queue_get_items(proc_cf->time_q, wis, 10, 0); if (i <= 0) { continue; } i -= 1; s_a = (struct sign_arg *)rtpp_wi_sgnl_get_data(wis[i], NULL); ndrain = (s_a->ncycles_ref - ncycles_ref) / (cf->stable->target_pfreq / MAX_RTP_RATE); #ifdef RTPP_DEBUG last_ctick = s_a->clock_tick; ncycles_ref_pre = ncycles_ref; #endif ncycles_ref = s_a->ncycles_ref; for(; i > -1; i--) { rtpp_wi_free(wis[i]); } tp[1] = getdtime(); #if RTPP_DEBUG if (last_ctick % (unsigned int)cf->stable->target_pfreq == 0 || last_ctick < 1000) { rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld sptime %f, CSV: %f,%f,%f", \ last_ctick, tp[1], (double)last_ctick / cf->stable->target_pfreq, \ ((double)ncycles_ref / cf->stable->target_pfreq) - tp[1], tp[1]); } #endif if (ndrain < 1) { ndrain = 1; } #if RTPP_DEBUG if (ndrain > 1) { rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld " \ "ncycles_ref %lld, ncycles_ref_pre %lld, ndrain %d CSV: %f,%f,%d", \ last_ctick, ncycles_ref, ncycles_ref_pre, ndrain, \ (double)last_ctick / cf->stable->target_pfreq, ndrain); } #endif alarm_tick = 0; if (last_tick_time == 0 || last_tick_time > tp[1]) { last_tick_time = tp[1]; } else if (last_tick_time + (double)TIMETICK < tp[1]) { alarm_tick = 1; last_tick_time = tp[1]; } if (alarm_tick || (ncycles_ref % 7) == 0) { rtp_only = 0; } else { rtp_only = 1; } pthread_mutex_lock(&cf->sessinfo.lock); if (cf->sessinfo.nsessions > 0) { if (rtp_only == 0) { i = poll(cf->sessinfo.pfds_rtcp, cf->sessinfo.nsessions, 0); } i = poll(cf->sessinfo.pfds_rtp, cf->sessinfo.nsessions, 0); pthread_mutex_unlock(&cf->sessinfo.lock); if (i < 0 && errno == EINTR) { rtpp_command_async_wakeup(cf->stable->rtpp_cmd_cf); tp[0] = getdtime(); continue; } } else { pthread_mutex_unlock(&cf->sessinfo.lock); } tp[2] = getdtime(); sender = rtpp_anetio_pick_sender(proc_cf->op); if (rtp_only == 0) { pthread_mutex_lock(&cf->glock); process_rtp(cf, tp[2], alarm_tick, ndrain, sender, rstats); } else { process_rtp_only(cf, tp[2], ndrain, sender, rstats); pthread_mutex_lock(&cf->glock); } if (cf->rtp_nsessions > 0) { process_rtp_servers(cf, tp[2], sender, rstats); } pthread_mutex_unlock(&cf->glock); rtpp_anetio_pump_q(sender); rtpp_command_async_wakeup(cf->stable->rtpp_cmd_cf); tp[3] = getdtime(); flush_rstats(stats_cf, rstats); #if RTPP_DEBUG recfilter_apply(&proc_cf->sleep_time, tp[1] - tp[0]); recfilter_apply(&proc_cf->poll_time, tp[2] - tp[1]); recfilter_apply(&proc_cf->proc_time, tp[3] - tp[2]); #endif tp[0] = tp[3]; #if RTPP_DEBUG if (last_ctick % (unsigned int)cf->stable->target_pfreq == 0 || last_ctick < 1000) { #if 0 rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld eptime %f, CSV: %f,%f,%f", \ last_ctick, tp[3], (double)last_ctick / cf->stable->target_pfreq, tp[3] - tp[1], tp[3]); #endif rtpp_log_write(RTPP_LOG_DBUG, cf->stable->glog, "run %lld eptime %f sleep_time %f poll_time %f proc_time %f CSV: %f,%f,%f,%f", \ last_ctick, tp[3], proc_cf->sleep_time.lastval, proc_cf->poll_time.lastval, proc_cf->proc_time.lastval, \ (double)last_ctick / cf->stable->target_pfreq, proc_cf->sleep_time.lastval, proc_cf->poll_time.lastval, proc_cf->proc_time.lastval); } #endif } }
static void rtpp_cmd_queue_run(void *arg) { struct rtpp_cmd_async_cf *cmd_cf; struct rtpp_cmd_pollset *psp; int i, nready, rval; double sptime; #if 0 double eptime, tused; #endif struct rtpp_command_stats *csp; struct rtpp_stats_obj *rtpp_stats_cf; cmd_cf = (struct rtpp_cmd_async_cf *)arg; rtpp_stats_cf = cmd_cf->cf_save->stable->rtpp_stats; csp = &cmd_cf->cstats; psp = &cmd_cf->pset; for (;;) { sptime = getdtime(); pthread_mutex_lock(&psp->pfds_mutex); if (psp->pfds_used == 0) { pthread_mutex_unlock(&psp->pfds_mutex); if (wait_next_clock(cmd_cf) == TSTATE_CEASE) { break; } continue; } nready = poll(psp->pfds, psp->pfds_used, 2); if (nready == 0) { pthread_mutex_unlock(&psp->pfds_mutex); if (wait_next_clock(cmd_cf) == TSTATE_CEASE) { break; } continue; } if (nready < 0 && errno == EINTR) { pthread_mutex_unlock(&psp->pfds_mutex); continue; } if (nready > 0) { for (i = 0; i < psp->pfds_used; i++) { if ((psp->pfds[i].revents & (POLLERR | POLLHUP)) != 0) { if (RTPP_CTRL_ACCEPTABLE(psp->rccs[i]->csock)) { goto closefd; } if (psp->rccs[i]->csock->type == RTPC_STDIO && (psp->pfds[i].revents & POLLIN) == 0) { goto closefd; } } if ((psp->pfds[i].revents & POLLIN) == 0) { continue; } if (RTPP_CTRL_ISSTREAM(psp->rccs[i]->csock)) { rval = process_commands_stream(cmd_cf->cf_save, psp->rccs[i], sptime, csp, rtpp_stats_cf); } else { rval = process_commands(psp->rccs[i]->csock, cmd_cf->cf_save, psp->pfds[i].fd, sptime, csp, rtpp_stats_cf, cmd_cf->rcache); } /* * Shut down non-datagram sockets that got I/O error * and also all non-continuous UNIX sockets are recycled * after each use. */ if (!RTPP_CTRL_ISDG(psp->rccs[i]->csock) && (rval == -1 || !RTPP_CTRL_ISSTREAM(psp->rccs[i]->csock))) { closefd: if (psp->rccs[i]->csock->type == RTPC_STDIO && psp->rccs[i]->csock->exit_on_close != 0) { cmd_cf->cf_save->stable->slowshutdown = 1; } rtpp_cmd_connection_dtor(psp->rccs[i]); psp->pfds_used--; if (psp->pfds_used > 0 && i < psp->pfds_used) { memcpy(&psp->pfds[i], &psp->pfds[i + 1], (psp->pfds_used - i) * sizeof(struct pollfd)); memcpy(&psp->rccs[i], &psp->rccs[i + 1], (psp->pfds_used - i) * sizeof(struct rtpp_ctrl_connection *)); } } } } pthread_mutex_unlock(&psp->pfds_mutex); if (nready > 0) { rtpp_anetio_pump(cmd_cf->cf_save->stable->rtpp_netio_cf); } #if 0 eptime = getdtime(); pthread_mutex_lock(&cmd_cf->cmd_mutex); recfilter_apply(&cmd_cf->average_load, (eptime - sptime + tused) * cmd_cf->cf_save->stable->target_pfreq); pthread_mutex_unlock(&cmd_cf->cmd_mutex); #endif flush_cstats(rtpp_stats_cf, csp); #if 0 #if RTPP_DEBUG if (last_ctick % (unsigned int)cmd_cf->cf_save->stable->target_pfreq == 0 || last_ctick < 1000) { rtpp_log_write(RTPP_LOG_DBUG, cmd_cf->cf_save->stable->glog, "rtpp_cmd_queue_run %lld sptime %f eptime %f, CSV: %f,%f,%f,%f,%f", \ last_ctick, sptime, eptime, (double)last_ctick / cmd_cf->cf_save->stable->target_pfreq, \ eptime - sptime + tused, eptime, sptime, tused); rtpp_log_write(RTPP_LOG_DBUG, cmd_cf->cf_save->stable->glog, "run %lld average load %f, CSV: %f,%f", last_ctick, \ cmd_cf->average_load.lastval * 100.0, (double)last_ctick / cmd_cf->cf_save->stable->target_pfreq, cmd_cf->average_load.lastval); } #endif #endif } }
static void rtpp_anetio_sthread(struct sthread_args *args) { int n, nsend, i, send_errno, nretry; struct rtpp_wi *wi, *wis[100]; #if RTPP_DEBUG_timers double tp[3], runtime, sleeptime; long run_n; runtime = sleeptime = 0.0; run_n = 0; tp[0] = getdtime(); #endif for (;;) { nsend = rtpp_queue_get_items(args->out_q, wis, 100, 0); #if RTPP_DEBUG_timers tp[1] = getdtime(); #endif for (i = 0; i < nsend; i++) { wi = wis[i]; if (wi->wi_type == RTPP_WI_TYPE_SGNL) { rtpp_wi_free(wi); goto out; } nretry = 0; do { n = sendto(wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, wi->tolen); send_errno = (n < 0) ? errno : 0; #if RTPP_DEBUG_netio >= 1 if (wi->debug != 0) { char daddr[MAX_AP_STRBUF]; addrport2char_r(wi->sendto, daddr, sizeof(daddr), ':'); if (n < 0) { RTPP_ELOG(wi->log, RTPP_LOG_DBUG, "sendto(%d, %p, %lld, %d, %p (%s), %d) = %d", wi->sock, wi->msg, (long long)wi->msg_len, wi->flags, wi->sendto, daddr, wi->tolen, n); } else if (n < wi->msg_len) { RTPP_LOG(wi->log, RTPP_LOG_DBUG, "sendto(%d, %p, %lld, %d, %p (%s), %d) = %d: short write", wi->sock, wi->msg, (long long)wi->msg_len, wi->flags, wi->sendto, daddr, wi->tolen, n); #if RTPP_DEBUG_netio >= 2 } else { RTPP_LOG(wi->log, RTPP_LOG_DBUG, "sendto(%d, %p, %d, %d, %p (%s), %d) = %d", wi->sock, wi->msg, wi->msg_len, wi->flags, wi->sendto, daddr, wi->tolen, n); #endif } } #endif if (n >= 0) { wi->nsend--; } else { /* "EPERM" is Linux thing, yield and retry */ if ((send_errno == EPERM || send_errno == ENOBUFS) && nretry < RTPP_ANETIO_MAX_RETRY) { sched_yield(); nretry++; } else { break; } } } while (wi->nsend > 0); rtpp_wi_free(wi); } #if RTPP_DEBUG_timers sleeptime += tp[1] - tp[0]; tp[0] = getdtime(); runtime += tp[0] - tp[1]; if ((run_n % 10000) == 0) { RTPP_LOG(args->glog, RTPP_LOG_DBUG, "rtpp_anetio_sthread(%p): run %ld aload = %f filtered = %f", \ args, run_n, runtime / (runtime + sleeptime), args->average_load.lastval); } if (runtime + sleeptime > 1.0) { recfilter_apply(&args->average_load, runtime / (runtime + sleeptime)); runtime = sleeptime = 0.0; } run_n += 1; #endif } out: return; }