pulse-server: implement temporary data attached to manager objects

Add functions for setting timer-based lifetimes for object data.

Having the timers in the object data themselves simplifies life cycle
management, as client/manager disconnects are handled without further
work.
This commit is contained in:
Pauli Virtanen 2022-05-14 16:01:14 +03:00 committed by Wim Taymans
parent 36ad886388
commit 83be5d866f
2 changed files with 74 additions and 6 deletions

View file

@ -41,12 +41,15 @@
#define manager_emit_removed(m,o) spa_hook_list_call(&m->hooks, struct pw_manager_events, removed, 0, o)
#define manager_emit_metadata(m,o,s,k,t,v) spa_hook_list_call(&m->hooks, struct pw_manager_events, metadata,0,o,s,k,t,v)
#define manager_emit_disconnect(m) spa_hook_list_call(&m->hooks, struct pw_manager_events, disconnect, 0)
#define manager_emit_object_data_timeout(m,o,k) spa_hook_list_call(&m->hooks, struct pw_manager_events, object_data_timeout,0,o,k)
struct object;
struct manager {
struct pw_manager this;
struct pw_loop *loop;
struct spa_hook core_listener;
struct spa_hook registry_listener;
int sync_seq;
@ -64,8 +67,10 @@ struct object_info {
struct object_data {
struct spa_list link;
struct object *object;
const char *key;
size_t size;
struct spa_source *timer;
};
struct object {
@ -188,6 +193,16 @@ static void object_update_params(struct object *o)
}
}
static void object_data_free(struct object_data *d)
{
spa_list_remove(&d->link);
if (d->timer) {
pw_loop_destroy_source(d->object->manager->loop, d->timer);
d->timer = NULL;
}
free(d);
}
static void object_destroy(struct object *o)
{
struct manager *m = o->manager;
@ -201,10 +216,8 @@ static void object_destroy(struct object *o)
free(o->this.message_object_path);
clear_params(&o->this.param_list, SPA_ID_INVALID);
clear_params(&o->pending_list, SPA_ID_INVALID);
spa_list_consume(d, &o->data_list, link) {
spa_list_remove(&d->link);
free(d);
}
spa_list_consume(d, &o->data_list, link)
object_data_free(d);
free(o);
}
@ -716,6 +729,7 @@ static const struct pw_core_events core_events = {
struct pw_manager *pw_manager_new(struct pw_core *core)
{
struct manager *m;
struct pw_context *context;
m = calloc(1, sizeof(*m));
if (m == NULL)
@ -729,6 +743,9 @@ struct pw_manager *pw_manager_new(struct pw_core *core)
return NULL;
}
context = pw_core_get_context(core);
m->loop = pw_context_get_main_loop(context);
spa_hook_list_init(&m->hooks);
spa_list_init(&m->this.object_list);
@ -847,11 +864,14 @@ void *pw_manager_object_add_data(struct pw_manager_object *obj, const char *key,
if (d != NULL) {
if (d->size == size)
goto done;
spa_list_remove(&d->link);
free(d);
object_data_free(d);
}
d = calloc(1, sizeof(struct object_data) + size);
if (d == NULL)
return NULL;
d->object = o;
d->key = key;
d->size = size;
@ -861,6 +881,49 @@ done:
return SPA_PTROFF(d, sizeof(struct object_data), void);
}
static void object_data_timeout(void *data, uint64_t count)
{
struct object_data *d = data;
struct object *o = d->object;
struct manager *m = o->manager;
pw_log_debug("manager:%p object id:%d data '%s' lifetime ends",
m, o->this.id, d->key);
if (d->timer) {
pw_loop_destroy_source(m->loop, d->timer);
d->timer = NULL;
}
manager_emit_object_data_timeout(m, &o->this, d->key);
}
void *pw_manager_object_add_temporary_data(struct pw_manager_object *obj, const char *key,
size_t size, uint64_t lifetime_nsec)
{
struct object *o = SPA_CONTAINER_OF(obj, struct object, this);
struct object_data *d;
void *data;
struct timespec timeout = {0}, interval = {0};
data = pw_manager_object_add_data(obj, key, size);
if (data == NULL)
return NULL;
d = SPA_PTROFF(data, -sizeof(struct object_data), void);
if (d->timer == NULL)
d->timer = pw_loop_add_timer(o->manager->loop, object_data_timeout, d);
if (d->timer == NULL)
return NULL;
timeout.tv_sec = lifetime_nsec / SPA_NSEC_PER_SEC;
timeout.tv_nsec = lifetime_nsec % SPA_NSEC_PER_SEC;
pw_loop_update_timer(o->manager->loop, d->timer, &timeout, &interval, false);
return data;
}
void *pw_manager_object_get_data(struct pw_manager_object *obj, const char *id)
{
struct object *o = SPA_CONTAINER_OF(obj, struct object, this);

View file

@ -55,6 +55,9 @@ struct pw_manager_events {
const char *type, const char *value);
void (*disconnect) (void *data);
void (*object_data_timeout) (void *data, struct pw_manager_object *object,
const char *key);
};
struct pw_manager {
@ -115,6 +118,8 @@ int pw_manager_for_each_object(struct pw_manager *manager,
void *pw_manager_object_add_data(struct pw_manager_object *o, const char *key, size_t size);
void *pw_manager_object_get_data(struct pw_manager_object *obj, const char *key);
void *pw_manager_object_add_temporary_data(struct pw_manager_object *o, const char *key,
size_t size, uint64_t lifetime_nsec);
bool pw_manager_object_is_client(struct pw_manager_object *o);
bool pw_manager_object_is_module(struct pw_manager_object *o);