mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-07-24 03:35:36 +00:00
pipewire-v4l2: only access globals.fd_maps
while holding globals.lock
`fd_map` structures are allocated in a `pw_array`. When inserting into a full `pw_array`, it is resized to accomodate the new elements. In that case, all `fd_map` pointers may be invalidated. Hence it is only safe to access `fd_map` structs while holding `globals.lock`, which prevents any modifications to the fd map array, thus keeping the references valid.
This commit is contained in:
parent
e1898812b2
commit
5e1a93d61d
|
@ -299,37 +299,55 @@ static int add_fd_map(int fd, struct file *file)
|
||||||
pthread_mutex_unlock(&globals.lock);
|
pthread_mutex_unlock(&globals.lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static struct fd_map *find_fd_map(int fd)
|
|
||||||
|
/* must be called with `globals.lock` held */
|
||||||
|
static struct fd_map *find_fd_map_unlocked(int fd)
|
||||||
{
|
{
|
||||||
struct fd_map *map, *res = NULL;
|
struct fd_map *map;
|
||||||
pthread_mutex_lock(&globals.lock);
|
|
||||||
pw_array_for_each(map, &globals.fd_maps) {
|
pw_array_for_each(map, &globals.fd_maps) {
|
||||||
if (map->fd == fd) {
|
if (map->fd == fd) {
|
||||||
ATOMIC_INC(map->file->ref);
|
ATOMIC_INC(map->file->ref);
|
||||||
res = map;
|
return map;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&globals.lock);
|
|
||||||
return res;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct file *find_file(int fd)
|
static struct file *find_file(int fd)
|
||||||
{
|
{
|
||||||
struct fd_map *map = find_fd_map(fd);
|
|
||||||
if (map == NULL)
|
|
||||||
return NULL;
|
|
||||||
return map->file;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_fd_map(struct fd_map *map)
|
|
||||||
{
|
|
||||||
struct file *file = map->file;
|
|
||||||
pthread_mutex_lock(&globals.lock);
|
pthread_mutex_lock(&globals.lock);
|
||||||
pw_array_remove(&globals.fd_maps, map);
|
|
||||||
|
struct fd_map *map = find_fd_map_unlocked(fd);
|
||||||
|
struct file *file = NULL;
|
||||||
|
|
||||||
|
if (map != NULL)
|
||||||
|
file = map->file;
|
||||||
|
|
||||||
pthread_mutex_unlock(&globals.lock);
|
pthread_mutex_unlock(&globals.lock);
|
||||||
|
|
||||||
unref_file(file);
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file *remove_fd_map(int fd)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&globals.lock);
|
||||||
|
|
||||||
|
struct fd_map *map = find_fd_map_unlocked(fd);
|
||||||
|
struct file *file = NULL;
|
||||||
|
|
||||||
|
if (map != NULL) {
|
||||||
|
file = map->file;
|
||||||
|
pw_array_remove(&globals.fd_maps, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&globals.lock);
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
|
unref_file(file);
|
||||||
|
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_file_map(void *addr, struct file *file)
|
static int add_file_map(void *addr, struct file *file)
|
||||||
|
@ -711,20 +729,15 @@ static int v4l2_dup(int oldfd)
|
||||||
|
|
||||||
static int v4l2_close(int fd)
|
static int v4l2_close(int fd)
|
||||||
{
|
{
|
||||||
int res = 0;
|
struct file *file = remove_fd_map(fd);
|
||||||
struct file *file;
|
|
||||||
struct fd_map *map;
|
|
||||||
|
|
||||||
if ((map = find_fd_map(fd)) == NULL)
|
if (file == NULL)
|
||||||
return globals.old_fops.close(fd);
|
return globals.old_fops.close(fd);
|
||||||
|
|
||||||
file = map->file;
|
|
||||||
remove_fd_map(map);
|
|
||||||
unref_file(file);
|
unref_file(file);
|
||||||
|
|
||||||
pw_log_info("fd:%d -> %d (%s)", fd,
|
pw_log_info("fd:%d closed", fd);
|
||||||
res, strerror(res < 0 ? errno : 0));
|
return 0;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
|
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
|
||||||
|
|
Loading…
Reference in a new issue