assert(idc);
l = htsmsg_create_list();
- if ((is = idnode_find_all(idc))) {
+ if ((is = idnode_find_all(idc, NULL))) {
for (i = 0; i < is->is_count; i++) {
in = is->is_array[i];
/* Multiple */
if (uuids) {
+ const idnodes_rb_t *domain = NULL;
l = htsmsg_create_list();
HTSMSG_FOREACH(f, uuids) {
if (!(uuid = htsmsg_field_get_str(f))) continue;
- if (!(in = idnode_find(uuid, NULL))) continue;
+ if (!(in = idnode_find(uuid, NULL, domain))) continue;
+ domain = in->in_domain;
if (idnode_perm(in, perm, NULL)) {
err = EPERM;
continue;
/* Single */
} else {
- if (!(in = idnode_find(uuid, NULL)))
+ if (!(in = idnode_find(uuid, NULL, NULL)))
err = ENOENT;
else {
if (idnode_perm(in, perm, NULL)) {
if (!msg->hm_islist) {
if (!(uuid = htsmsg_get_str(msg, "uuid")))
goto exit;
- if (!(in = idnode_find(uuid, NULL)))
+ if (!(in = idnode_find(uuid, NULL, NULL)))
goto exit;
if (idnode_perm(in, perm, msg)) {
err = EPERM;
/* Multiple */
} else {
+ const idnodes_rb_t *domain = NULL;
HTSMSG_FOREACH(f, msg) {
if (!(conf = htsmsg_field_get_map(f)))
continue;
if (!(uuid = htsmsg_get_str(conf, "uuid")))
continue;
- if (!(in = idnode_find(uuid, NULL)))
+ if (!(in = idnode_find(uuid, NULL, domain)))
continue;
+ domain = in->in_domain;
if (idnode_perm(in, perm, conf)) {
err = EPERM;
continue;
pthread_mutex_lock(&global_lock);
if (!isroot || root) {
- if (!(node = idnode_find(isroot ? root : uuid, NULL))) {
+ if (!(node = idnode_find(isroot ? root : uuid, NULL, NULL))) {
pthread_mutex_unlock(&global_lock);
return EINVAL;
}
/* Multiple */
if (uuids) {
+ const idnodes_rb_t *domain = NULL;
HTSMSG_FOREACH(f, uuids) {
if (!(uuid = htsmsg_field_get_string(f))) continue;
- if (!(in = idnode_find(uuid, NULL))) continue;
+ if (!(in = idnode_find(uuid, NULL, domain))) continue;
+ domain = in->in_domain;
handler(perm, in);
}
/* Single */
} else {
uuid = htsmsg_field_get_string(f);
- if (!(in = idnode_find(uuid, NULL)))
+ if (!(in = idnode_find(uuid, NULL, NULL)))
err = ENOENT;
else
handler(perm, in);
channel_t *channel_find_by_name(const char *name);
#define channel_find_by_uuid(u)\
- (channel_t*)idnode_find(u, &channel_class)
+ (channel_t*)idnode_find(u, &channel_class, NULL)
channel_t *channel_find_by_id(uint32_t id);
channel_tag_t *channel_tag_find_by_identifier(uint32_t id);
static inline channel_tag_t *channel_tag_find_by_uuid(const char *uuid)
- { return (channel_tag_t*)idnode_find(uuid, &channel_tag_class); }
+ { return (channel_tag_t*)idnode_find(uuid, &channel_tag_class, NULL); }
void channel_tag_save(channel_tag_t *ct);
int i, n;
extern const idclass_t linuxdvb_adapter_class;
linuxdvb_adapter_t *la;
- idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class);
+ idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class, NULL);
for (i = 0; i < is->is_count; i++) {
la = (linuxdvb_adapter_t*)is->is_array[i];
if (!la || !la->la_is_enabled(la)) continue;
dvr_config_t *dvr_config_create(const char *name, const char *uuid, htsmsg_t *conf);
static inline dvr_config_t *dvr_config_find_by_uuid(const char *uuid)
- { return (dvr_config_t*)idnode_find(uuid, &dvr_config_class); }
+ { return (dvr_config_t*)idnode_find(uuid, &dvr_config_class, NULL); }
void dvr_config_delete(const char *name);
dvr_entry_t *dvr_entry_find_by_id(int id);
static inline dvr_entry_t *dvr_entry_find_by_uuid(const char *uuid)
- { return (dvr_entry_t*)idnode_find(uuid, &dvr_entry_class); }
+ { return (dvr_entry_t*)idnode_find(uuid, &dvr_entry_class, NULL); }
dvr_entry_t *dvr_entry_find_by_event(epg_broadcast_t *e);
static inline dvr_autorec_entry_t *
dvr_autorec_find_by_uuid(const char *uuid)
- { return (dvr_autorec_entry_t*)idnode_find(uuid, &dvr_autorec_entry_class); }
+ { return (dvr_autorec_entry_t*)idnode_find(uuid, &dvr_autorec_entry_class, NULL); }
htsmsg_t * dvr_autorec_entry_class_time_list(void *o, const char *null);
static inline dvr_timerec_entry_t *
dvr_timerec_find_by_uuid(const char *uuid)
- { return (dvr_timerec_entry_t*)idnode_find(uuid, &dvr_timerec_entry_class); }
+ { return (dvr_timerec_entry_t*)idnode_find(uuid, &dvr_timerec_entry_class, NULL); }
void dvr_timerec_save(dvr_timerec_entry_t *dae);
#include "settings.h"
#include "uuid.h"
+static const idnodes_rb_t * idnode_domain ( const idclass_t *idc );
+static void idclass_root_register ( idnode_t *in );
+
typedef struct idclass_link
{
- const idclass_t *idc;
+ const idclass_t *idc;
+ idnodes_rb_t nodes;
RB_ENTRY(idclass_link) link;
} idclass_link_t;
-static RB_HEAD(,idnode) idnodes;
+static idnodes_rb_t idnodes;
static RB_HEAD(,idclass_link) idclasses;
+static RB_HEAD(,idclass_link) idrootclasses;
static pthread_cond_t idnode_cond;
static pthread_mutex_t idnode_mutex;
static htsmsg_t *idnode_queue;
return memcmp(a->in_uuid, b->in_uuid, sizeof(a->in_uuid));
}
+static int
+ic_cmp ( const idclass_link_t *a, const idclass_link_t *b )
+{
+ assert(a->idc->ic_class);
+ assert(b->idc->ic_class);
+ return strcmp(a->idc->ic_class, b->idc->ic_class);
+}
+
/* **************************************************************************
* Registration
* *************************************************************************/
idnode_init(void)
{
idnode_queue = NULL;
+ RB_INIT(&idnodes);
+ RB_INIT(&idclasses);
+ RB_INIT(&idrootclasses);
pthread_mutex_init(&idnode_mutex, NULL);
pthread_cond_init(&idnode_cond, NULL);
tvhthread_create(&idnode_tid, NULL, idnode_thread, NULL);
RB_REMOVE(&idclasses, il, link);
free(il);
}
+ while ((il = RB_FIRST(&idrootclasses)) != NULL) {
+ RB_REMOVE(&idrootclasses, il, link);
+ free(il);
+ }
SKEL_FREE(idclasses_skel);
}
static const idclass_t *
-idnode_root_class(idnode_t *in)
+idnode_root_class(const idclass_t *idc)
{
- const idclass_t *idc;
-
- idc = in->in_class;
while (idc && idc->ic_super)
idc = idc->ic_super;
return idc;
idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class, int flags)
{
idnode_t *c;
- lock_assert(&global_lock);
tvh_uuid_t u;
int retries = 5;
uint32_t u32;
const idclass_t *idc;;
+ lock_assert(&global_lock);
+
in->in_class = class;
do {
c = NULL;
if (flags & IDNODE_SHORT_UUID) {
u32 = idnode_get_short_uuid(in);
- idc = idnode_root_class(in);
+ idc = idnode_root_class(in->in_class);
RB_FOREACH(c, &idnodes, in_link) {
- if (idc != idnode_root_class(c))
+ if (idc != idnode_root_class(c->in_class))
continue;
if (idnode_get_short_uuid(c) == u32)
break;
/* Register the class */
idclass_register(class); // Note: we never actually unregister
+ idclass_root_register(in);
+ assert(in->in_domain);
+ c = RB_INSERT_SORTED(in->in_domain, in, in_domain_link, in_cmp);
+ assert(c == NULL);
/* Fire event */
idnode_notify_simple(in);
{
lock_assert(&global_lock);
RB_REMOVE(&idnodes, in, in_link);
+ RB_REMOVE(in->in_domain, in, in_domain_link);
tvhtrace("idnode", "unlink node %s", idnode_uuid_as_str(in));
idnode_notify_simple(in);
}
/**
*
*/
+static const idnodes_rb_t *
+idnode_domain(const idclass_t *idc)
+{
+ if (idc) {
+ idclass_link_t lskel, *l;
+ const idclass_t *root = idnode_root_class(idc);
+ lskel.idc = root;
+ l = RB_FIND(&idrootclasses, &lskel, link, ic_cmp);
+ if (l == NULL)
+ return NULL;
+ return &l->nodes;
+ } else {
+ return NULL;
+ }
+}
+
void *
-idnode_find(const char *uuid, const idclass_t *idc)
+idnode_find ( const char *uuid, const idclass_t *idc, const idnodes_rb_t *domain )
{
idnode_t skel, *r;
return NULL;
if(hex2bin(skel.in_uuid, sizeof(skel.in_uuid), uuid))
return NULL;
- r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
+ if (domain == NULL)
+ domain = idnode_domain(idc);
+ if (domain == NULL)
+ r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
+ else
+ r = RB_FIND(domain, &skel, in_domain_link, in_cmp);
if(r != NULL && idc != NULL) {
const idclass_t *c = r->in_class;
for(;c != NULL; c = c->ic_super) {
}
idnode_set_t *
-idnode_find_all ( const idclass_t *idc )
+idnode_find_all ( const idclass_t *idc, const idnodes_rb_t *domain )
{
idnode_t *in;
const idclass_t *ic;
tvhtrace("idnode", "find class %s", idc->ic_class);
idnode_set_t *is = calloc(1, sizeof(idnode_set_t));
- RB_FOREACH(in, &idnodes, in_link) {
- ic = in->in_class;
- while (ic) {
- if (ic == idc) {
- tvhtrace("idnode", " add node %s", idnode_uuid_as_str(in));
- idnode_set_add(is, in, NULL);
- break;
+ if (domain == NULL)
+ domain = idnode_domain(idc);
+ if (domain == NULL) {
+ RB_FOREACH(in, &idnodes, in_link) {
+ ic = in->in_class;
+ while (ic) {
+ if (ic == idc) {
+ tvhtrace("idnode", " add node %s", idnode_uuid_as_str(in));
+ idnode_set_add(is, in, NULL);
+ break;
+ }
+ ic = ic->ic_super;
+ }
+ }
+ } else {
+ RB_FOREACH(in, domain, in_domain_link) {
+ ic = in->in_class;
+ while (ic) {
+ if (ic == idc) {
+ tvhtrace("idnode", " add node %s", idnode_uuid_as_str(in));
+ idnode_set_add(is, in, NULL);
+ break;
+ }
+ ic = ic->ic_super;
}
- ic = ic->ic_super;
}
}
return is;
return NULL;
}
-static int
-ic_cmp ( const idclass_link_t *a, const idclass_link_t *b )
-{
- assert(a->idc->ic_class);
- assert(b->idc->ic_class);
- return strcmp(a->idc->ic_class, b->idc->ic_class);
-}
-
void
idclass_register(const idclass_t *idc)
{
idclasses_skel->idc = idc;
if (RB_INSERT_SORTED(&idclasses, idclasses_skel, link, ic_cmp))
break;
+ RB_INIT(&idclasses_skel->nodes); /* not used, but for sure */
SKEL_USED(idclasses_skel);
tvhtrace("idnode", "register class %s", idc->ic_class);
idc = idc->ic_super;
}
}
+static void
+idclass_root_register(idnode_t *in)
+{
+ const idclass_t *idc = in->in_class;
+ idclass_link_t *r;
+ idc = idnode_root_class(idc);
+ SKEL_ALLOC(idclasses_skel);
+ idclasses_skel->idc = idc;
+ r = RB_INSERT_SORTED(&idrootclasses, idclasses_skel, link, ic_cmp);
+ if (r) {
+ in->in_domain = &r->nodes;
+ return;
+ }
+ RB_INIT(&idclasses_skel->nodes);
+ r = idclasses_skel;
+ SKEL_USED(idclasses_skel);
+ tvhtrace("idnode", "register root class %s", idc->ic_class);
+ in->in_domain = &r->nodes;
+}
+
const idclass_t *
idclass_find ( const char *class )
{
pthread_mutex_lock(&global_lock);
HTSMSG_FOREACH(f, q) {
- node = idnode_find(f->hmf_name, NULL);
+ node = idnode_find(f->hmf_name, NULL, NULL);
event = htsmsg_field_get_str(f);
m = htsmsg_create_map();
htsmsg_add_str(m, "uuid", f->hmf_name);
int (*ic_perm) (idnode_t *self, struct access *a, htsmsg_t *msg_to_write);
};
+
+typedef RB_HEAD(, idnode) idnodes_rb_t;
+
/*
* Node definition
*/
struct idnode {
uint8_t in_uuid[UUID_BIN_SIZE]; ///< Unique ID
RB_ENTRY(idnode) in_link; ///< Global hash
+ RB_ENTRY(idnode) in_domain_link; ///< Root class link (domain)
+ idnodes_rb_t *in_domain; ///< Domain nodes
const idclass_t *in_class; ///< Class definition
};
void idnode_changed (idnode_t *in);
-void *idnode_find (const char *uuid, const idclass_t *idc);
-idnode_set_t *idnode_find_all(const idclass_t *idc);
+void *idnode_find (const char *uuid, const idclass_t *idc, const idnodes_rb_t *nodes);
+idnode_set_t *idnode_find_all(const idclass_t *idc, const idnodes_rb_t *nodes);
void idnode_notify (idnode_t *in, int event);
void mpegts_input_delete ( mpegts_input_t *mi, int delconf );
-#define mpegts_input_find(u) idnode_find(u, &mpegts_input_class);
+static inline mpegts_input_t *mpegts_input_find(const char *uuid)
+ { return idnode_find(uuid, &mpegts_input_class, NULL); }
int mpegts_input_set_networks ( mpegts_input_t *mi, htsmsg_t *msg );
extern const idclass_t mpegts_network_class;
-#define mpegts_network_find(u)\
- idnode_find(u, &mpegts_network_class)
+static inline mpegts_network_t *mpegts_network_find(const char *uuid)
+ { return idnode_find(uuid, &mpegts_network_class, NULL); }
mpegts_mux_t *mpegts_network_find_mux
(mpegts_network_t *mn, uint16_t onid, uint16_t tsid);
mpegts_mux_create0(calloc(1, sizeof(mpegts_mux_t)), &mpegts_mux_class, uuid,\
mn, onid, tsid, conf)
-#define mpegts_mux_find(u)\
- idnode_find(u, &mpegts_mux_class)
+static inline mpegts_mux_t *mpegts_mux_find(const char *uuid)
+ { return idnode_find(uuid, &mpegts_mux_class, NULL); }
#define mpegts_mux_delete_by_uuid(u, delconf)\
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm, delconf); }
mpegts_service_t *mpegts_service_find
( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, int create, int *save );
-#define mpegts_service_find_by_uuid(u)\
- idnode_find(u, &mpegts_service_class)
+static inline mpegts_service_t *mpegts_service_find_by_uuid(const char *uuid)
+ { return idnode_find(uuid, &mpegts_service_class, NULL); }
void mpegts_service_delete ( service_t *s, int delconf );
else
return NULL;
- return idnode_find_all(idc);
+ return idnode_find_all(idc, NULL);
}
/* **************************************************************************
dvb_network_t*
dvb_network_find_by_uuid(const char *uuid)
{
- idnode_t *in = idnode_find(uuid, &dvb_network_class);
- return (dvb_network_t*)in;
+ return idnode_find(uuid, &dvb_network_class, NULL);
}
int dvb_network_get_orbital_pos
else
return NULL;
- return idnode_find_all(idc);
+ return idnode_find_all(idc, NULL);
}
/* **************************************************************************
tvhftrace("main", avahi_done);
tvhftrace("main", bonjour_done);
tvhftrace("main", imagecache_done);
- tvhftrace("main", idnode_done);
tvhftrace("main", lang_code_done);
tvhftrace("main", api_done);
tvhftrace("main", config_done);
tvhftrace("main", esfilter_done);
tvhftrace("main", intlconv_done);
tvhftrace("main", urlparse_done);
+ tvhftrace("main", idnode_done);
tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
tvhlog_end();
return t;
}
-/**
- * Find a service based on the given identifier
- */
-service_t *
-service_find(const char *identifier)
-{
- return idnode_find(identifier, &service_class);
-}
-
-
/**
*
*/
void service_ref(service_t *t);
-service_t *service_find(const char *identifier);
+static inline service_t *service_find(const char *identifier)
+ { return idnode_find(identifier, &service_class, NULL); }
#define service_find_by_identifier service_find
service_instance_t *service_find_instance(struct service *s,