static void rtpp_mif_run(void *argp) { struct rtpp_module_if_priv *pvt; struct rtpp_wi *wi; int signum; const char *aname; struct rtpp_acct *rap; pvt = (struct rtpp_module_if_priv *)argp; for (;;) { wi = rtpp_queue_get_item(pvt->req_q, 0); if (rtpp_wi_get_type(wi) == RTPP_WI_TYPE_SGNL) { signum = rtpp_wi_sgnl_get_signum(wi); rtpp_wi_free(wi); if (signum == SIGTERM) { break; } continue; } aname = rtpp_wi_apis_getnamearg(wi, (void **)&rap, sizeof(rap)); if (aname == do_acct_aname) { pvt->mip->on_session_end.func(pvt->mpvt, rap); } CALL_METHOD(rap->rcnt, decref); rtpp_wi_free(wi); } }
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; }
static void rtpp_notify_queue_run(void *arg) { struct rtpp_wi *wi; struct rtpp_notify_wi *wi_data; struct rtpp_notify_priv *pvt; pvt = (struct rtpp_notify_priv *)arg; for (;;) { wi = rtpp_queue_get_item(pvt->nqueue, 0); if (rtpp_wi_get_type(wi) == RTPP_WI_TYPE_SGNL) { rtpp_wi_free(wi); break; } wi_data = rtpp_wi_data_get_ptr(wi, sizeof(struct rtpp_notify_wi), 0); /* main work here */ do_timeout_notification(wi_data, 3, wi->log); /* deallocate wi */ rtpp_wi_free(wi); } }
struct rtpp_notify * rtpp_notify_ctor(struct rtpp_log *glog) { struct rtpp_notify_priv *pvt; pvt = rtpp_zmalloc(sizeof(struct rtpp_notify_priv)); if (pvt == NULL) { goto e0; } pvt->nqueue = rtpp_queue_init(1, "rtpp_notify"); if (pvt->nqueue == NULL) { goto e1; } /* Pre-allocate sigterm, so that we don't have any malloc() in dtor() */ pvt->sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0); if (pvt->sigterm == NULL) { goto e2; } if (pthread_create(&pvt->thread_id, NULL, (void *(*)(void *))&rtpp_notify_queue_run, pvt) != 0) { goto e3; } CALL_METHOD(glog->rcnt, incref); pvt->glog = glog; pvt->pub.schedule = &rtpp_notify_schedule; pvt->pub.dtor = &rtpp_notify_dtor; return (&pvt->pub); e3: rtpp_wi_free(pvt->sigterm); e2: rtpp_queue_destroy(pvt->nqueue); e1: free(pvt); e0: return (NULL); }
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 } }
struct rtpp_module_if * rtpp_module_if_ctor(struct rtpp_cfg_stable *cfsp, struct rtpp_log *log, const char *mpath) { struct rtpp_refcnt *rcnt; struct rtpp_module_if_priv *pvt; const char *derr; pvt = rtpp_rzmalloc(sizeof(struct rtpp_module_if_priv), &rcnt); if (pvt == NULL) { goto e0; } pvt->pub.rcnt = rcnt; pvt->dmp = dlopen(mpath, RTLD_NOW); if (pvt->dmp == NULL) { derr = dlerror(); if (strstr(derr, mpath) == NULL) { RTPP_LOG(log, RTPP_LOG_ERR, "can't dlopen(%s): %s", mpath, derr); } else { RTPP_LOG(log, RTPP_LOG_ERR, "can't dlopen() module: %s", derr); } goto e1; } pvt->mip = dlsym(pvt->dmp, "rtpp_module"); if (pvt->mip == NULL) { derr = dlerror(); if (strstr(derr, mpath) == NULL) { RTPP_LOG(log, RTPP_LOG_ERR, "can't find 'rtpp_module' symbol in the %s" ": %s", mpath, derr); } else { RTPP_LOG(log, RTPP_LOG_ERR, "can't find 'rtpp_module' symbol: %s", derr); } goto e2; } if (!MI_VER_CHCK(pvt->mip)) { RTPP_LOG(log, RTPP_LOG_ERR, "incompatible API version in the %s, " "consider recompiling the module", mpath); goto e2; } #if RTPP_CHECK_LEAKS pvt->mip->_malloc = &rtpp_memdeb_malloc; pvt->mip->_zmalloc = &rtpp_zmalloc_memdeb; pvt->mip->_free = &rtpp_memdeb_free; pvt->mip->_realloc = &rtpp_memdeb_realloc; pvt->mip->_strdup = &rtpp_memdeb_strdup; pvt->mip->_asprintf = &rtpp_memdeb_asprintf; pvt->mip->_vasprintf = &rtpp_memdeb_vasprintf; pvt->memdeb_p = rtpp_memdeb_init(); rtpp_memdeb_setlog(pvt->memdeb_p, log); #else pvt->mip->_malloc = (rtpp_module_malloc_t)&malloc; pvt->mip->_zmalloc = (rtpp_module_zmalloc_t)&rtpp_zmalloc; pvt->mip->_free = (rtpp_module_free_t)&free; pvt->mip->_realloc = (rtpp_module_realloc_t)&realloc; pvt->mip->_strdup = (rtpp_module_strdup_t)&strdup; pvt->mip->_asprintf = rtpp_module_asprintf; pvt->mip->_vasprintf = rtpp_module_vasprintf; #endif if (pvt->memdeb_p == NULL) { goto e2; } /* We make a copy, so that the module cannot screw us up */ pvt->mip->memdeb_p = pvt->memdeb_p; pvt->sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0); if (pvt->sigterm == NULL) { goto e3; } pvt->req_q = rtpp_queue_init(1, "rtpp_module_if(%s)", pvt->mip->name); if (pvt->req_q == NULL) { goto e4; } if (pvt->mip->ctor != NULL) { pvt->mpvt = pvt->mip->ctor(cfsp); if (pvt->mpvt == NULL) { RTPP_LOG(log, RTPP_LOG_ERR, "module '%s' failed to initialize", pvt->mip->name); goto e5; } } if (pvt->mip->on_session_end.argsize != rtpp_acct_OSIZE()) { RTPP_LOG(log, RTPP_LOG_ERR, "incompatible API version in the %s, " "consider recompiling the module", mpath); goto e6; } if (pthread_create(&pvt->thread_id, NULL, (void *(*)(void *))&rtpp_mif_run, pvt) != 0) { goto e6; } CALL_METHOD(log->rcnt, incref); pvt->log = log; pvt->pub.do_acct = &rtpp_mif_do_acct; CALL_METHOD(pvt->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_mif_dtor, pvt); return ((&pvt->pub)); e6: if (pvt->mip->dtor != NULL) { pvt->mip->dtor(pvt->mpvt); } e5: rtpp_queue_destroy(pvt->req_q); #if RTPP_CHECK_LEAKS if (rtpp_memdeb_dumpstats(pvt->memdeb_p, 1) != 0) { RTPP_LOG(log, RTPP_LOG_ERR, "module '%s' leaked memory in the failed " "constructor", pvt->mip->name); } #endif e4: rtpp_wi_free(pvt->sigterm); e3: #if RTPP_CHECK_LEAKS rtpp_memdeb_dtor(pvt->memdeb_p); #endif e2: dlclose(pvt->dmp); e1: CALL_METHOD(rcnt, decref); free(pvt); e0: return (NULL); }
struct rtpp_anetio_cf * rtpp_netio_async_init(struct cfg *cf, int qlen) { struct rtpp_anetio_cf *netio_cf; int i, ri; netio_cf = rtpp_zmalloc(sizeof(*netio_cf)); if (netio_cf == NULL) return (NULL); for (i = 0; i < SEND_THREADS; i++) { netio_cf->args[i].out_q = rtpp_queue_init(qlen, "RTPP->NET%.2d", i); if (netio_cf->args[i].out_q == NULL) { for (ri = i - 1; ri >= 0; ri--) { rtpp_queue_destroy(netio_cf->args[ri].out_q); } goto e0; } netio_cf->args[i].glog = cf->stable->glog; netio_cf->args[i].dmode = cf->stable->dmode; #ifdef RTPP_DEBUG recfilter_init(&netio_cf->args[i].average_load, 0.9, 0.0, 0); #endif } for (i = 0; i < SEND_THREADS; i++) { netio_cf->args[i].sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0); if (netio_cf->args[i].sigterm == NULL) { for (ri = i - 1; ri >= 0; ri--) { rtpp_wi_free(netio_cf->args[ri].sigterm); } goto e1; } } cf->stable->rtpp_netio_cf = netio_cf; for (i = 0; i < SEND_THREADS; i++) { if (pthread_create(&(netio_cf->thread_id[i]), NULL, (void *(*)(void *))&rtpp_anetio_sthread, &netio_cf->args[i]) != 0) { for (ri = i - 1; ri >= 0; ri--) { rtpp_queue_put_item(netio_cf->args[ri].sigterm, netio_cf->args[ri].out_q); pthread_join(netio_cf->thread_id[ri], NULL); } for (ri = i; ri < SEND_THREADS; ri++) { rtpp_wi_free(netio_cf->args[ri].sigterm); } goto e1; } } return (netio_cf); #if 0 e2: for (i = 0; i < SEND_THREADS; i++) { rtpp_wi_free(netio_cf->args[i].sigterm); } #endif e1: for (i = 0; i < SEND_THREADS; i++) { rtpp_queue_destroy(netio_cf->args[i].out_q); } e0: free(netio_cf); return (NULL); }
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; }