mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-20 08:56:56 -05:00
impl-metadata: avoid infinite loop in cleat_items
When we need to remove all items, copy the storage to a temporary array and clear the storage. When one of the callbacks would add a new item to the storage it would operate on the new empty storage and the loop to iteratively clear subjects would be able to complete. Fixes #1622
This commit is contained in:
parent
afb37dd7fc
commit
49a0250ecd
1 changed files with 18 additions and 10 deletions
|
|
@ -121,31 +121,31 @@ static int impl_add_listener(void *object,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct item *find_item(struct metadata *this, uint32_t subject, const char *key)
|
static struct item *find_item(struct pw_array *storage, uint32_t subject, const char *key)
|
||||||
{
|
{
|
||||||
struct item *item;
|
struct item *item;
|
||||||
|
|
||||||
pw_array_for_each(item, &this->storage) {
|
pw_array_for_each(item, storage) {
|
||||||
if (item->subject == subject && (key == NULL || spa_streq(item->key, key)))
|
if (item->subject == subject && (key == NULL || spa_streq(item->key, key)))
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clear_subjects(struct metadata *this, uint32_t subject)
|
static int clear_subjects(struct metadata *this, struct pw_array *storage, uint32_t subject)
|
||||||
{
|
{
|
||||||
struct item *item;
|
struct item *item;
|
||||||
uint32_t removed = 0;
|
uint32_t removed = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
item = find_item(this, subject, NULL);
|
item = find_item(storage, subject, NULL);
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pw_log_debug(NAME" %p: remove id:%d key:%s", this, subject, item->key);
|
pw_log_debug(NAME" %p: remove id:%d key:%s", this, subject, item->key);
|
||||||
|
|
||||||
clear_item(item);
|
clear_item(item);
|
||||||
pw_array_remove(&this->storage, item);
|
pw_array_remove(storage, item);
|
||||||
removed++;
|
removed++;
|
||||||
}
|
}
|
||||||
if (removed > 0)
|
if (removed > 0)
|
||||||
|
|
@ -157,9 +157,17 @@ static int clear_subjects(struct metadata *this, uint32_t subject)
|
||||||
static void clear_items(struct metadata *this)
|
static void clear_items(struct metadata *this)
|
||||||
{
|
{
|
||||||
struct item *item;
|
struct item *item;
|
||||||
pw_array_consume(item, &this->storage)
|
struct pw_array tmp;
|
||||||
clear_subjects(this, item->subject);
|
|
||||||
pw_array_reset(&this->storage);
|
/* copy to tmp and reinitialize the storage so that the callbacks
|
||||||
|
* will operate on the new empty metadata. Otherwise, if a callbacks
|
||||||
|
* adds new metadata we just keep on emptying the metadata forever. */
|
||||||
|
tmp = this->storage;
|
||||||
|
pw_array_init(&this->storage, 4096);
|
||||||
|
|
||||||
|
pw_array_consume(item, &tmp)
|
||||||
|
clear_subjects(this, &tmp, item->subject);
|
||||||
|
pw_array_clear(&tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int impl_set_property(void *object,
|
static int impl_set_property(void *object,
|
||||||
|
|
@ -175,9 +183,9 @@ static int impl_set_property(void *object,
|
||||||
pw_log_debug(NAME" %p: id:%d key:%s type:%s value:%s", this, subject, key, type, value);
|
pw_log_debug(NAME" %p: id:%d key:%s type:%s value:%s", this, subject, key, type, value);
|
||||||
|
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
return clear_subjects(this, subject);
|
return clear_subjects(this, &this->storage, subject);
|
||||||
|
|
||||||
item = find_item(this, subject, key);
|
item = find_item(&this->storage, subject, key);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
if (item != NULL) {
|
if (item != NULL) {
|
||||||
clear_item(item);
|
clear_item(item);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue