static void rtpp_mif_dtor(struct rtpp_module_if_priv *pvt) { rtpp_module_if_fin(&(pvt->pub)); /* First, stop the worker thread and wait for it to terminate */ rtpp_queue_put_item(pvt->sigterm, pvt->req_q); pthread_join(pvt->thread_id, NULL); rtpp_queue_destroy(pvt->req_q); /* Then run module destructor (if any) */ if (pvt->mip->dtor != NULL) { pvt->mip->dtor(pvt->mpvt); } #if RTPP_CHECK_LEAKS /* Check if module leaked any mem */ if (rtpp_memdeb_dumpstats(pvt->memdeb_p, 1) != 0) { RTPP_LOG(pvt->log, RTPP_LOG_ERR, "module '%s' leaked memory after " "destruction", pvt->mip->name); } rtpp_memdeb_dtor(pvt->memdeb_p); #endif /* Unload and free everything */ dlclose(pvt->dmp); CALL_METHOD(pvt->log->rcnt, decref); free(pvt); }
int rtpp_sbuf_selftest(void) { struct rtpp_sbuf *sbp; int rval; const char *longtest = "INFO:GLOBAL:rtpp_proc_async_run: ncycles=2600 load=0.068641"; RTPP_MEMDEB_APP_INIT(); sbp = rtpp_sbuf_ctor(6); assert(sbp != NULL); assert(sbp->alen == 6); assert(sbp->cp == sbp->bp); assert(RS_ULEN(sbp) == 0); rval = rtpp_sbuf_write(sbp, "%d", 12345); assert(rval == SBW_OK); assert(sbp->cp[0] == '\0'); assert(strcmp(sbp->bp, "12345") == 0); assert(RS_ULEN(sbp) == 5); rval = rtpp_sbuf_write(sbp, "%s", "F"); assert(rval == SBW_SHRT); assert(sbp->cp[0] == '\0'); assert(strcmp(sbp->bp, "12345") == 0); assert(RS_ULEN(sbp) == 5); assert(rtpp_sbuf_extend(sbp, 7) == 0); assert(RS_ULEN(sbp) == 5); assert(strcmp(sbp->bp, "12345") == 0); rval = rtpp_sbuf_write(sbp, "%s", "F"); assert(rval == SBW_OK); assert(RS_ULEN(sbp) == 6); assert(strcmp(sbp->bp, "12345F") == 0); do { assert(rtpp_sbuf_extend(sbp, sbp->alen + 1) == 0); rval = rtpp_sbuf_write(sbp, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest, longtest); } while (rval == SBW_SHRT); assert(rval == SBW_OK); assert(RS_ULEN(sbp) == 1446); assert(sbp->alen == RS_ULEN(sbp) + 1); assert(strncmp(sbp->bp, "12345F", 6) == 0); rval = RS_ULEN(sbp); rtpp_sbuf_reset(sbp); assert(sbp->cp == sbp->bp); assert(sbp->cp[0] == '\0'); assert(sbp->alen == rval + 1); rtpp_sbuf_dtor(sbp); rval = rtpp_memdeb_dumpstats(MEMDEB_SYM, 0); return (rval); }
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); }
int main(int argc, char **argv) { int i, len; 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)); cf.stable->ctrl_socks = malloc(sizeof(struct rtpp_list)); if (cf.stable->ctrl_socks == NULL) { err(1, "can't allocate memory for the struct rtpp_cfg_stable"); /* NOTREACHED */ } memset(cf.stable->ctrl_socks, '\0', sizeof(struct rtpp_list)); RTPP_LIST_RESET(cf.stable->ctrl_socks); 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); if (rtpp_controlfd_init(&cf) != 0) { err(1, "can't inilialize control socket%s", cf.stable->ctrl_socks->len > 1 ? "s" : ""); } 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(cf.stable->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.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); #ifdef HAVE_SYSTEMD_SD_DAEMON_H sd_notify(0, "READY=1"); #endif #ifdef RTPP_CHECK_LEAKS rtpp_memdeb_setbaseln(); #endif 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); } } #ifdef HAVE_SYSTEMD_SD_DAEMON_H sd_notify(0, "STATUS=Exited"); #endif #ifdef RTPP_CHECK_LEAKS exit(rtpp_memdeb_dumpstats(&cf) == 0 ? 0 : 1); #else exit(0); #endif }