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
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_mux_t *m = s->s_dvb_mux;
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;
/* Set weight to 0 for already active mux */
if (mmi->mmi_mux->mm_active == mmi)
w = 0;
else
/* Set weight to -1 (forced) for already active mux */
if (mmi->mmi_mux->mm_active == mmi) {
w = -1;
p = -1;
} else {
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);
}
}

View file

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

View file

@ -128,14 +128,14 @@ typedef struct elementary_stream {
} 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 {
LIST_ENTRY(service_instance) si_link;
TAILQ_ENTRY(service_instance) si_link;
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,
int instance,
int prio,
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);
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);
@ -442,7 +443,7 @@ service_t *service_find(const char *identifier);
service_instance_t *service_find_instance(struct service *s,
struct channel *ch,
struct service_instance_list *sil,
service_instance_list_t *sil,
int *error,
int weight);

View file

@ -422,6 +422,7 @@ subscription_create
th_subscription_t *s = calloc(1, sizeof(th_subscription_t));
int reject = 0;
static int tally;
TAILQ_INIT(&s->ths_instances);
if(flags & SUBSCRIPTION_NONE)
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
*/
struct service_instance_list ths_instances;
service_instance_list_t ths_instances;
struct service_instance *ths_current_instance;
#if ENABLE_MPEGTS