global: avoid using existing global id

Add the global immediately after creating it. Make sure we only
enumerate registered globals. This way, we can already check for
duplicate ids before the global is registered.

When allocating a global id, avoid using an existing id. Move some
code around to make it easier to implement a more efficient algorithm
for collision detection.

Move the object id counter to the context.
This commit is contained in:
Wim Taymans 2022-01-13 16:10:35 +01:00
parent 3a49168f26
commit 5baab24848
3 changed files with 34 additions and 6 deletions

View file

@ -570,6 +570,8 @@ int pw_context_for_each_global(struct pw_context *context,
int res;
spa_list_for_each_safe(g, t, &context->global_list, link) {
if (!g->registered)
continue;
if (!global_can_read(context, g))
continue;
if ((res = callback(data, g)) != 0)
@ -588,12 +590,36 @@ static struct pw_global *find_global(struct pw_context *context, uint32_t id)
return NULL;
}
static uint32_t next_global_id(struct pw_context *context)
{
uint32_t id, retry = 0;
while (true) {
id = context->serial++ & 0xffffff;
if (find_global(context, id) == NULL)
return id;
if (retry++ > 4096)
break;
}
return SPA_ID_INVALID;
}
uint32_t pw_context_add_global(struct pw_context *context, struct pw_global *global)
{
global->id = next_global_id(context);
spa_list_append(&context->global_list, &global->link);
}
void pw_context_remove_global(struct pw_context *context, struct pw_global *global)
{
spa_list_remove(&global->link);
}
SPA_EXPORT
struct pw_global *pw_context_find_global(struct pw_context *context, uint32_t id)
{
struct pw_global *global;
global = find_global(context, id);
if (global == NULL || !global->registered) {
errno = ENOENT;

View file

@ -36,8 +36,6 @@
PW_LOG_TOPIC_EXTERN(log_global);
#define PW_LOG_TOPIC_DEFAULT log_global
static uint32_t serial = 0;
/** \cond */
struct impl {
struct pw_global this;
@ -96,11 +94,12 @@ pw_global_new(struct pw_context *context,
this->func = func;
this->object = object;
this->properties = properties;
this->id = serial++ & 0xffffff;
spa_list_init(&this->resource_list);
spa_hook_list_init(&this->listener_list);
pw_context_add_global(context, this);
pw_log_debug("%p: new %s %d", this, this->type, this->id);
return this;
@ -126,7 +125,6 @@ int pw_global_register(struct pw_global *global)
if (global->registered)
return -EEXIST;
spa_list_append(&context->global_list, &global->link);
global->registered = true;
spa_list_for_each(registry, &context->registry_resource_list, link) {
@ -163,7 +161,6 @@ static int global_unregister(struct pw_global *global)
pw_registry_resource_global_remove(resource, global->id);
}
spa_list_remove(&global->link);
global->registered = false;
pw_log_debug("%p: unregistered %u", global, global->id);
@ -368,6 +365,7 @@ void pw_global_destroy(struct pw_global *global)
struct pw_resource *resource;
global->destroyed = true;
pw_context_remove_global(global->context, global);
pw_log_debug("%p: destroy %u", global, global->id);
pw_global_emit_destroy(global);

View file

@ -450,6 +450,7 @@ struct pw_context {
uint32_t n_support; /**< number of support items */
struct pw_array factory_lib; /**< mapping of factory_name regexp to library */
uint32_t serial;
struct pw_array objects; /**< objects */
struct pw_impl_client *current_client; /**< client currently executing code in mainloop */
@ -1115,6 +1116,9 @@ struct pw_control {
void *user_data;
};
uint32_t pw_context_add_global(struct pw_context *context, struct pw_global *global);
void pw_context_remove_global(struct pw_context *context, struct pw_global *global);
/** Find a good format between 2 ports */
int pw_context_find_format(struct pw_context *context,
struct pw_impl_port *output,