service: service listing was broken

I think it was quite possible for two services on the same multiplex not
to share the same tuner. Also I wasn't convinced about how it kicked running
services.
This commit is contained in:
Adam Sutton 2013-09-26 23:12:04 +01:00
parent 3fec2653ff
commit fe9bd60192
5 changed files with 68 additions and 45 deletions

View file

@ -156,7 +156,7 @@ mpegts_service_config_save(service_t *t)
static void static void
mpegts_service_enlist(service_t *t, struct service_instance_list *sil) mpegts_service_enlist(service_t *t, struct service_instance_list *sil)
{ {
int p = 0, w; // TODO: priority int p = 0, w;
mpegts_service_t *s = (mpegts_service_t*)t; mpegts_service_t *s = (mpegts_service_t*)t;
mpegts_mux_t *m = s->s_dvb_mux; mpegts_mux_t *m = s->s_dvb_mux;
mpegts_mux_instance_t *mmi; mpegts_mux_instance_t *mmi;
@ -173,11 +173,15 @@ mpegts_service_enlist(service_t *t, struct service_instance_list *sil)
if (!mmi->mmi_input->mi_is_enabled(mmi->mmi_input)) continue; if (!mmi->mmi_input->mi_is_enabled(mmi->mmi_input)) continue;
/* Set weight to 0 for already active mux */ /* Set weight to -1 (forced) for already active mux */
if (mmi->mmi_mux->mm_active == mmi) if (mmi->mmi_mux->mm_active == mmi) {
w = 0; w = -1;
else p = -1;
} else {
w = mmi->mmi_input->mi_current_weight(mmi->mmi_input); w = mmi->mmi_input->mi_current_weight(mmi->mmi_input);
p = 0;//mmi->mmi_input->mi_priority(mmi->mmi_input);
}
service_instance_add(sil, t, mmi->mmi_input->mi_instance, p, w); service_instance_add(sil, t, mmi->mmi_input->mi_instance, p, w);
} }
} }

View file

@ -377,7 +377,8 @@ service_start(service_t *t, int instance)
* Main entry point for starting a service based on a channel * Main entry point for starting a service based on a channel
*/ */
service_instance_t * service_instance_t *
service_find_instance(service_t *s, channel_t *ch, struct service_instance_list *sil, service_find_instance
(service_t *s, channel_t *ch, service_instance_list_t *sil,
int *error, int weight) int *error, int weight)
{ {
channel_service_mapping_t *csm; channel_service_mapping_t *csm;
@ -385,50 +386,59 @@ service_find_instance(service_t *s, channel_t *ch, struct service_instance_list
lock_assert(&global_lock); lock_assert(&global_lock);
// First, update list of candidates /* Build list */
TAILQ_FOREACH(si, sil, si_link)
LIST_FOREACH(si, sil, si_link)
si->si_mark = 1; si->si_mark = 1;
if (ch) { if (ch) {
LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) { LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) {
s = csm->csm_svc; s = csm->csm_svc;
if (!s->s_is_enabled(s)) continue; if (s->s_is_enabled(s))
s->s_enlist(s, sil); s->s_enlist(s, sil);
} }
} else { } else {
s->s_enlist(s, sil); s->s_enlist(s, sil);
} }
for(si = LIST_FIRST(sil); si != NULL; si = next) { /* Clean */
next = LIST_NEXT(si, si_link); for(si = TAILQ_FIRST(sil); si != NULL; si = next) {
next = TAILQ_NEXT(si, si_link);
if(si->si_mark) if(si->si_mark)
service_instance_destroy(si); service_instance_destroy(sil, si);
} }
// Check if any service is already running, if so, use that /* Debug */
LIST_FOREACH(si, sil, si_link) TAILQ_FOREACH(si, sil, si_link) {
const char *name = ch ? ch->ch_name : NULL;
if (!name && s) name = s->s_nicename;
tvhdebug("service", "%s si %p weight %d prio %d error %d\n",
name, si, si->si_weight, si->si_prio, si->si_error);
}
/* Already running? */
TAILQ_FOREACH(si, sil, si_link)
if(si->si_s->s_status == SERVICE_RUNNING && si->si_error == 0) if(si->si_s->s_status == SERVICE_RUNNING && si->si_error == 0)
return si; return si;
// Check if any is idle /* Forced or Idle */
LIST_FOREACH(si, sil, si_link) TAILQ_FOREACH(si, sil, si_link)
if(si->si_weight == 0 && si->si_error == 0) if(si->si_weight <= 0 && si->si_error == 0)
break; break;
// Check if to kick someone out /* Bump someone */
if(si == NULL) { if (!si) {
LIST_FOREACH(si, sil, si_link) { TAILQ_FOREACH_REVERSE(si, sil, service_instance_list, si_link)
if(si->si_weight < weight && si->si_error == 0) if (weight > si->si_weight && si->si_error == 0)
break; break;
} }
}
/* Failed */
if(si == NULL) { if(si == NULL) {
*error = SM_CODE_NO_FREE_ADAPTER; *error = SM_CODE_NO_FREE_ADAPTER;
return NULL; return NULL;
} }
/* Start */
service_start(si->si_s, si->si_instance); service_start(si->si_s, si->si_instance);
return si; return si;
} }
@ -1097,24 +1107,30 @@ service_refresh_channel(service_t *t)
/** /**
* * Weight then prio?
*/ */
static int static int
si_cmp(const service_instance_t *a, const service_instance_t *b) si_cmp(const service_instance_t *a, const service_instance_t *b)
{ {
return a->si_prio - b->si_prio; int r;
r = a->si_weight - b->si_weight;
if (!r)
r = a->si_prio - b->si_prio;
return r;
} }
/** /**
* *
*/ */
service_instance_t * service_instance_t *
service_instance_add(struct service_instance_list *sil, service_instance_add(service_instance_list_t *sil,
struct service *s, int instance, int prio, struct service *s, int instance, int prio,
int weight) int weight)
{ {
service_instance_t *si; service_instance_t *si;
LIST_FOREACH(si, sil, si_link)
/* Existing */
TAILQ_FOREACH(si, sil, si_link)
if(si->si_s == s && si->si_instance == instance) if(si->si_s == s && si->si_instance == instance)
break; break;
@ -1128,11 +1144,11 @@ service_instance_add(struct service_instance_list *sil,
si->si_mark = 0; si->si_mark = 0;
if(si->si_prio == prio && si->si_weight == weight) if(si->si_prio == prio && si->si_weight == weight)
return si; return si;
LIST_REMOVE(si, si_link); TAILQ_REMOVE(sil, si, si_link);
} }
si->si_weight = weight; si->si_weight = weight;
si->si_prio = prio; si->si_prio = prio;
LIST_INSERT_SORTED(sil, si, si_link, si_cmp); TAILQ_INSERT_SORTED(sil, si, si_link, si_cmp);
return si; return si;
} }
@ -1141,9 +1157,10 @@ service_instance_add(struct service_instance_list *sil,
* *
*/ */
void void
service_instance_destroy(service_instance_t *si) service_instance_destroy
(service_instance_list_t *sil, service_instance_t *si)
{ {
LIST_REMOVE(si, si_link); TAILQ_REMOVE(sil, si, si_link);
service_unref(si->si_s); service_unref(si->si_s);
free(si); free(si);
} }
@ -1153,13 +1170,13 @@ service_instance_destroy(service_instance_t *si)
* *
*/ */
void void
service_instance_list_clear(struct service_instance_list *sil) service_instance_list_clear(service_instance_list_t *sil)
{ {
lock_assert(&global_lock); lock_assert(&global_lock);
service_instance_t *si; service_instance_t *si;
while((si = LIST_FIRST(sil)) != NULL) while((si = TAILQ_FIRST(sil)) != NULL)
service_instance_destroy(si); service_instance_destroy(sil, si);
} }

View file

@ -128,14 +128,14 @@ typedef struct elementary_stream {
} elementary_stream_t; } elementary_stream_t;
LIST_HEAD(service_instance_list, service_instance); typedef TAILQ_HEAD(service_instance_list, service_instance) service_instance_list_t;
/** /**
* *
*/ */
typedef struct service_instance { typedef struct service_instance {
LIST_ENTRY(service_instance) si_link; TAILQ_ENTRY(service_instance) si_link;
int si_prio; int si_prio;
@ -162,15 +162,16 @@ typedef struct service_instance {
/** /**
* *
*/ */
service_instance_t *service_instance_add(struct service_instance_list *sil, service_instance_t *service_instance_add(service_instance_list_t *sil,
struct service *s, struct service *s,
int instance, int instance,
int prio, int prio,
int weight); int weight);
void service_instance_destroy(service_instance_t *si); void service_instance_destroy
(service_instance_list_t *sil, service_instance_t *si);
void service_instance_list_clear(struct service_instance_list *sil); void service_instance_list_clear(service_instance_list_t *sil);
/** /**
* *
@ -268,7 +269,7 @@ typedef struct service {
int (*s_is_enabled)(struct service *t); int (*s_is_enabled)(struct service *t);
void (*s_enlist)(struct service *s, struct service_instance_list *sil); void (*s_enlist)(struct service *s, service_instance_list_t *sil);
int (*s_start_feed)(struct service *s, int instance); int (*s_start_feed)(struct service *s, int instance);
@ -442,7 +443,7 @@ service_t *service_find(const char *identifier);
service_instance_t *service_find_instance(struct service *s, service_instance_t *service_find_instance(struct service *s,
struct channel *ch, struct channel *ch,
struct service_instance_list *sil, service_instance_list_t *sil,
int *error, int *error,
int weight); int weight);

View file

@ -422,6 +422,7 @@ subscription_create
th_subscription_t *s = calloc(1, sizeof(th_subscription_t)); th_subscription_t *s = calloc(1, sizeof(th_subscription_t));
int reject = 0; int reject = 0;
static int tally; static int tally;
TAILQ_INIT(&s->ths_instances);
if(flags & SUBSCRIPTION_NONE) if(flags & SUBSCRIPTION_NONE)
reject |= (SMT_TO_MASK(SMT_PACKET) | SMT_TO_MASK(SMT_MPEGTS)); reject |= (SMT_TO_MASK(SMT_PACKET) | SMT_TO_MASK(SMT_MPEGTS));

View file

@ -74,7 +74,7 @@ typedef struct th_subscription {
/** /**
* This is the list of service candidates we have * This is the list of service candidates we have
*/ */
struct service_instance_list ths_instances; service_instance_list_t ths_instances;
struct service_instance *ths_current_instance; struct service_instance *ths_current_instance;
#if ENABLE_MPEGTS #if ENABLE_MPEGTS