static void * mtimer_thread(void *aux) { mtimer_t *mti; mti_callback_t *cb; int64_t now, next; const char *id; pthread_mutex_lock(&global_lock); while (tvheadend_is_running() && atomic_get(&tvheadend_mainloop) == 0) tvh_cond_wait(&mtimer_cond, &global_lock); pthread_mutex_unlock(&global_lock); while (tvheadend_is_running()) { now = mdispatch_clock_update(); /* Global monoclock timers */ pthread_mutex_lock(&global_lock); next = now + sec2mono(3600); while((mti = LIST_FIRST(&mtimers)) != NULL) { if (mti->mti_expire > now) { next = mti->mti_expire; break; } #if ENABLE_GTIMER_CHECK id = mti->mti_id; #else id = NULL; #endif tprofile_start(&mtimer_profile, id); cb = mti->mti_callback; LIST_REMOVE(mti, mti_link); mti->mti_callback = NULL; cb(mti->mti_opaque); tprofile_finish(&mtimer_profile); } /* Periodic updates */ if (next > mtimer_periodic) next = mtimer_periodic; /* Wait */ tvh_cond_timedwait(&mtimer_cond, &global_lock, next); pthread_mutex_unlock(&global_lock); } return NULL; }
static void * mtimer_thread(void *aux) { mtimer_t *mti; mti_callback_t *cb; int64_t now, next; #if ENABLE_GTIMER_CHECK int64_t mtm; const char *id; const char *fcn; #endif while (tvheadend_is_running()) { now = mdispatch_clock_update(); /* Global monoclock timers */ pthread_mutex_lock(&global_lock); next = now + sec2mono(3600); while((mti = LIST_FIRST(&mtimers)) != NULL) { if (mti->mti_expire > now) { next = mti->mti_expire; break; } #if ENABLE_GTIMER_CHECK mtm = getmonoclock(); id = mti->mti_id; fcn = mti->mti_fcn; #endif cb = mti->mti_callback; LIST_REMOVE(mti, mti_link); mti->mti_callback = NULL; cb(mti->mti_opaque); #if ENABLE_GTIMER_CHECK mtm = getmonoclock() - mtm; if (mtm > 10000) tvhtrace("mtimer", "%s:%s duration %"PRId64"us", id, fcn, mtm); #endif } /* Periodic updates */ if (next > mtimer_periodic) next = mtimer_periodic; /* Wait */ tvh_cond_timedwait(&mtimer_cond, &global_lock, next); pthread_mutex_unlock(&global_lock); } return NULL; }
static void * mtimer_tick_thread(void *aux) { while (tvheadend_is_running()) { /* update clocks each 10x in one second */ atomic_set_s64(&__mdispatch_clock, getmonoclock()); tvh_safe_usleep(100000); } return NULL; }
static void mainloop(void) { gtimer_t *gti; gti_callback_t *cb; time_t now; struct timespec ts; const char *id; while (tvheadend_is_running()) { now = gdispatch_clock_update(); ts.tv_sec = now + 3600; ts.tv_nsec = 0; /* Global timers */ pthread_mutex_lock(&global_lock); // TODO: there is a risk that if timers re-insert themselves to // the top of the list with a 0 offset we could loop indefinitely #if 0 tvhdebug(LS_GTIMER, "now %"PRItime_t, ts.tv_sec); LIST_FOREACH(gti, >imers, gti_link) tvhdebug(LS_GTIMER, " gti %p expire %"PRItimet, gti, gti->gti_expire.tv_sec); #endif while((gti = LIST_FIRST(>imers)) != NULL) { if (gti->gti_expire > now) { ts.tv_sec = gti->gti_expire; break; } #if ENABLE_GTIMER_CHECK id = gti->gti_id; #else id = NULL; #endif tprofile_start(>imer_profile, id); cb = gti->gti_callback; LIST_REMOVE(gti, gti_link); gti->gti_callback = NULL; cb(gti->gti_opaque); tprofile_finish(>imer_profile); } /* Wait */ pthread_cond_timedwait(>imer_cond, &global_lock, &ts); pthread_mutex_unlock(&global_lock); } }
static void * tasklet_thread ( void *aux ) { tasklet_t *tsk; tsk_callback_t *tsk_cb; void *opaque; tvhthread_renice(20); pthread_mutex_lock(&tasklet_lock); while (tvheadend_is_running()) { tsk = TAILQ_FIRST(&tasklets); if (tsk == NULL) { tvh_cond_wait(&tasklet_cond, &tasklet_lock); continue; } /* the callback might re-initialize tasklet, save everything */ TAILQ_REMOVE(&tasklets, tsk, tsk_link); tsk_cb = tsk->tsk_callback; opaque = tsk->tsk_opaque; tsk->tsk_callback = NULL; if (tsk->tsk_free) { memoryinfo_free(&tasklet_memoryinfo, sizeof(*tsk)); tsk->tsk_free(tsk); } /* now, the callback can be safely called */ if (tsk_cb) { pthread_mutex_unlock(&tasklet_lock); tsk_cb(opaque, 0); pthread_mutex_lock(&tasklet_lock); } } pthread_mutex_unlock(&tasklet_lock); return NULL; }
static void * tvhdhomerun_device_discovery_thread( void *aux ) { struct hdhomerun_discover_device_t result_list[MAX_HDHOMERUN_DEVICES]; int numDevices, brk; while (tvheadend_is_running()) { numDevices = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, MAX_HDHOMERUN_DEVICES); if (numDevices > 0) { while (numDevices > 0 ) { numDevices--; struct hdhomerun_discover_device_t* cDev = &result_list[numDevices]; if ( cDev->device_type == HDHOMERUN_DEVICE_TYPE_TUNER ) { pthread_mutex_lock(&global_lock); tvhdhomerun_device_t *existing = tvhdhomerun_device_find(cDev->device_id); if ( tvheadend_is_running() ) { if ( !existing ) { tvhinfo(LS_TVHDHOMERUN,"Found HDHomerun device %08x with %d tuners", cDev->device_id, cDev->tuner_count); tvhdhomerun_device_create(cDev); } else if ( ((struct sockaddr_in *)&existing->hd_info.ip_address)->sin_addr.s_addr != htonl(cDev->ip_addr) ) { struct sockaddr_storage detected_dev_addr; memset(&detected_dev_addr, 0, sizeof(detected_dev_addr)); detected_dev_addr.ss_family = AF_INET; ((struct sockaddr_in *)&detected_dev_addr)->sin_addr.s_addr = htonl(cDev->ip_addr); char existing_ip[64]; tcp_get_str_from_ip(&existing->hd_info.ip_address, existing_ip, sizeof(existing_ip)); char detected_ip[64]; tcp_get_str_from_ip(&detected_dev_addr, detected_ip, sizeof(detected_ip)); tvhinfo(LS_TVHDHOMERUN,"HDHomerun device %08x switched IPs from %s to %s, updating", cDev->device_id, existing_ip, detected_ip); tvhdhomerun_device_destroy(existing); tvhdhomerun_device_create(cDev); } } pthread_mutex_unlock(&global_lock); } } } pthread_mutex_lock(&tvhdhomerun_discovery_lock); brk = 0; if (tvheadend_is_running()) { brk = tvh_cond_timedwait(&tvhdhomerun_discovery_cond, &tvhdhomerun_discovery_lock, mclk() + sec2mono(15)); brk = !ERRNO_AGAIN(brk) && brk != ETIMEDOUT; } pthread_mutex_unlock(&tvhdhomerun_discovery_lock); if (brk) break; } return NULL; }
static void mainloop(void) { gtimer_t *gti; gti_callback_t *cb; time_t now; struct timespec ts; #if ENABLE_GTIMER_CHECK int64_t mtm; const char *id; const char *fcn; #endif while (tvheadend_is_running()) { now = gdispatch_clock_update(); ts.tv_sec = now + 3600; ts.tv_nsec = 0; /* Global timers */ pthread_mutex_lock(&global_lock); // TODO: there is a risk that if timers re-insert themselves to // the top of the list with a 0 offset we could loop indefinitely #if 0 tvhdebug("gtimer", "now %"PRItime_t, ts.tv_sec); LIST_FOREACH(gti, >imers, gti_link) tvhdebug("gtimer", " gti %p expire %"PRItimet, gti, gti->gti_expire.tv_sec); #endif while((gti = LIST_FIRST(>imers)) != NULL) { if (gti->gti_expire > now) { ts.tv_sec = gti->gti_expire; break; } #if ENABLE_GTIMER_CHECK mtm = getmonoclock(); id = gti->gti_id; fcn = gti->gti_fcn; #endif cb = gti->gti_callback; LIST_REMOVE(gti, gti_link); gti->gti_callback = NULL; cb(gti->gti_opaque); #if ENABLE_GTIMER_CHECK mtm = getmonoclock() - mtm; if (mtm > 10000) tvhtrace("gtimer", "%s:%s duration %"PRId64"us", id, fcn, mtm); #endif } /* Wait */ pthread_cond_timedwait(>imer_cond, &global_lock, &ts); pthread_mutex_unlock(&global_lock); } }
static void * linuxdvb_ca_en50221_thread ( void *aux ) { linuxdvb_ca_t *lca = aux; int slot_id, lasterror = 0; lca->lca_tl = en50221_tl_create(5, 32); if (!lca->lca_tl) { tvherror(LS_EN50221, "failed to create transport layer"); return NULL; } slot_id = en50221_tl_register_slot(lca->lca_tl, lca->lca_ca_fd, 0, 1000, 100); if (slot_id < 0) { tvherror(LS_EN50221, "slot registration failed"); return NULL; } lca->lca_sl = en50221_sl_create(lca->lca_tl, 256); if (lca->lca_sl == NULL) { tvherror(LS_EN50221, "failed to create session layer"); return NULL; } // create the sendfuncs lca->lca_sf.arg = lca->lca_sl; lca->lca_sf.send_data = (en50221_send_data) en50221_sl_send_data; lca->lca_sf.send_datav = (en50221_send_datav) en50221_sl_send_datav; /* create app resources and assign callbacks */ lca->lca_rm_resource = en50221_app_rm_create(&lca->lca_sf); en50221_app_rm_register_enq_callback(lca->lca_rm_resource, linuxdvb_ca_rm_enq_cb, lca); en50221_app_rm_register_reply_callback(lca->lca_rm_resource, linuxdvb_ca_rm_reply_cb, lca); en50221_app_rm_register_changed_callback(lca->lca_rm_resource, linuxdvb_ca_rm_changed_cb, lca); lca->lca_dt_resource = en50221_app_datetime_create(&lca->lca_sf); en50221_app_datetime_register_enquiry_callback(lca->lca_dt_resource, linuxdvb_ca_dt_enquiry_cb, lca); lca->lca_ai_resource = en50221_app_ai_create(&lca->lca_sf); en50221_app_ai_register_callback(lca->lca_ai_resource, linuxdvb_ca_ai_callback, lca); lca->lca_ca_resource = en50221_app_ca_create(&lca->lca_sf); en50221_app_ca_register_info_callback(lca->lca_ca_resource, linuxdvb_ca_ca_info_callback, lca); en50221_app_ca_register_pmt_reply_callback(lca->lca_ca_resource, linuxdvb_ca_ca_pmt_reply_cb, lca); lca->lca_mmi_resource = en50221_app_mmi_create(&lca->lca_sf); en50221_app_mmi_register_close_callback(lca->lca_mmi_resource, linuxdvb_ca_mmi_close_cb, lca); en50221_app_mmi_register_display_control_callback(lca->lca_mmi_resource, linuxdvb_ca_mmi_display_ctl_cb, lca); en50221_app_mmi_register_enq_callback(lca->lca_mmi_resource, linuxdvb_ca_mmi_enq_cb, lca); en50221_app_mmi_register_menu_callback(lca->lca_mmi_resource, linuxdvb_ca_mmi_menu_cb, lca); en50221_app_mmi_register_list_callback(lca->lca_mmi_resource, linuxdvb_ca_app_mmi_list_cb, lca); en50221_sl_register_lookup_callback(lca->lca_sl, linuxdvb_ca_lookup_cb, lca); en50221_sl_register_session_callback(lca->lca_sl, linuxdvb_ca_session_cb, lca); lca->lca_tc = en50221_tl_new_tc(lca->lca_tl, slot_id); while (tvheadend_is_running() && lca->lca_en50221_thread_running) { int error; if ((error = en50221_tl_poll(lca->lca_tl)) != 0) { if (error != lasterror) { tvherror(LS_EN50221, "poll error on slot %d [error:%i]", en50221_tl_get_error_slot(lca->lca_tl), en50221_tl_get_error(lca->lca_tl)); } lasterror = error; } } dvbcam_unregister_cam(lca, 0); en50221_tl_destroy_slot(lca->lca_tl, slot_id); en50221_sl_destroy(lca->lca_sl); en50221_tl_destroy(lca->lca_tl); return 0; }