mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-08 13:30:08 -05:00
context: implement faster id collision check
Keep a sorted circular list of the globals by id. Keep all globals smaller than the current serial at the tail and the globals bigger in the front. When we wrap around we will eventually have a collision with the head global, we can then skip that id, move the global to the tail and try the next id. In the normal case, this is O(1) collision check and O(1) removal. In the case of a collisions, it needs to skip the cluster of used ids. See !1108
This commit is contained in:
parent
e241febe62
commit
8ca037683e
3 changed files with 33 additions and 15 deletions
|
|
@ -220,6 +220,7 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop,
|
|||
spa_list_init(&this->core_list);
|
||||
spa_list_init(&this->registry_resource_list);
|
||||
spa_list_init(&this->global_list);
|
||||
spa_list_init(&this->sorted_globals);
|
||||
spa_list_init(&this->module_list);
|
||||
spa_list_init(&this->device_list);
|
||||
spa_list_init(&this->client_list);
|
||||
|
|
@ -590,23 +591,34 @@ 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, start = context->serial;
|
||||
while (true) {
|
||||
id = context->serial;
|
||||
context->serial = (context->serial+1) & 0xffffff;
|
||||
if (find_global(context, id) == NULL)
|
||||
return id;
|
||||
if (context->serial == start)
|
||||
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);
|
||||
uint32_t count = 0;
|
||||
|
||||
while (true) {
|
||||
struct pw_global *g;
|
||||
|
||||
if (spa_list_is_empty(&context->sorted_globals))
|
||||
break;
|
||||
|
||||
g = spa_list_first(&context->sorted_globals, struct pw_global, sorted_link);
|
||||
if (g->id != context->serial)
|
||||
break;
|
||||
context->serial = (context->serial+1) & PW_ID_MASK;
|
||||
|
||||
/* we have found a global with the next serial, move it to the back
|
||||
* of the sorted list */
|
||||
spa_list_remove(&g->sorted_link);
|
||||
spa_list_append(&context->sorted_globals, &g->sorted_link);
|
||||
|
||||
/* if we tried PW_ID_MASK times, we're out of ids */
|
||||
if (++count == PW_ID_MASK)
|
||||
return SPA_ID_INVALID;
|
||||
}
|
||||
global->id = context->serial;
|
||||
context->serial = (context->serial+1) & PW_ID_MASK;
|
||||
|
||||
spa_list_append(&context->sorted_globals, &global->sorted_link);
|
||||
spa_list_append(&context->global_list, &global->link);
|
||||
return global->id;
|
||||
}
|
||||
|
|
@ -614,6 +626,7 @@ uint32_t pw_context_add_global(struct pw_context *context, struct pw_global *glo
|
|||
void pw_context_remove_global(struct pw_context *context, struct pw_global *global)
|
||||
{
|
||||
spa_list_remove(&global->link);
|
||||
spa_list_remove(&global->sorted_link);
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ struct pw_registry;
|
|||
/* invalid ID that matches any object when used for permissions */
|
||||
#define PW_ID_ANY (uint32_t)(0xffffffff)
|
||||
|
||||
/* ID will only use these bits */
|
||||
#define PW_ID_MASK (uint32_t)(0xffffff)
|
||||
|
||||
/** The core information. Extra information may be added in later versions,
|
||||
* clients must not assume a constant struct size */
|
||||
struct pw_core_info {
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ struct pw_global {
|
|||
struct pw_context *context; /**< the context */
|
||||
|
||||
struct spa_list link; /**< link in context list of globals */
|
||||
struct spa_list sorted_link; /**< link in context list of sorted_globals */
|
||||
uint32_t id; /**< server id of the object */
|
||||
|
||||
struct pw_properties *properties; /**< properties of the global */
|
||||
|
|
@ -451,6 +452,7 @@ struct pw_context {
|
|||
struct pw_array factory_lib; /**< mapping of factory_name regexp to library */
|
||||
|
||||
uint32_t serial;
|
||||
struct spa_list sorted_globals;
|
||||
struct pw_array objects; /**< objects */
|
||||
|
||||
struct pw_impl_client *current_client; /**< client currently executing code in mainloop */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue