mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-16 08:56:45 -05:00
v4l2: reuse fd when opening the same path
When we open the same device multiple times, reuse the file structure and dup the fd.
This commit is contained in:
parent
4cb1c790a4
commit
0f13d5a65e
1 changed files with 58 additions and 20 deletions
|
|
@ -259,6 +259,8 @@ static struct file *make_file(void)
|
||||||
|
|
||||||
static void free_file(struct file *file)
|
static void free_file(struct file *file)
|
||||||
{
|
{
|
||||||
|
pw_log_info("fd:%d", file->fd);
|
||||||
|
|
||||||
if (file->loop)
|
if (file->loop)
|
||||||
pw_thread_loop_stop(file->loop);
|
pw_thread_loop_stop(file->loop);
|
||||||
|
|
||||||
|
|
@ -287,6 +289,7 @@ static void free_file(struct file *file)
|
||||||
|
|
||||||
static void unref_file(struct file *file)
|
static void unref_file(struct file *file)
|
||||||
{
|
{
|
||||||
|
pw_log_debug("fd:%d ref:%d", file->fd, file->ref);
|
||||||
if (ATOMIC_DEC(file->ref) <= 0)
|
if (ATOMIC_DEC(file->ref) <= 0)
|
||||||
free_file(file);
|
free_file(file);
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +303,7 @@ static int add_fd_map(int fd, struct file *file)
|
||||||
map->fd = fd;
|
map->fd = fd;
|
||||||
map->file = file;
|
map->file = file;
|
||||||
ATOMIC_INC(file->ref);
|
ATOMIC_INC(file->ref);
|
||||||
|
pw_log_debug("fd:%d (%d) ref:%d", fd, file->fd, file->ref);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&globals.lock);
|
pthread_mutex_unlock(&globals.lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -331,14 +335,13 @@ static bool add_dev_for_serial(uint32_t dev, uint32_t serial)
|
||||||
static struct fd_map *find_fd_map_unlocked(int fd)
|
static struct fd_map *find_fd_map_unlocked(int fd)
|
||||||
{
|
{
|
||||||
struct fd_map *map;
|
struct fd_map *map;
|
||||||
|
|
||||||
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);
|
||||||
|
pw_log_debug("fd:%d find:%d ref:%d", map->fd, fd, map->file->ref);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,6 +360,30 @@ static struct file *find_file(int fd)
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct file *find_file_by_dev(uint32_t dev)
|
||||||
|
{
|
||||||
|
struct fd_map *map = NULL, *tmp;
|
||||||
|
struct file *file = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&globals.lock);
|
||||||
|
pw_array_for_each(tmp, &globals.fd_maps) {
|
||||||
|
if (tmp->file->dev_id == dev) {
|
||||||
|
if (tmp->file->fd == -1)
|
||||||
|
tmp->file->fd = tmp->fd;
|
||||||
|
ATOMIC_INC(tmp->file->ref);
|
||||||
|
map = tmp;
|
||||||
|
pw_log_debug("dev:%d find:%d ref:%d",
|
||||||
|
tmp->file->dev_id, dev, tmp->file->ref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (map != NULL)
|
||||||
|
file = map->file;
|
||||||
|
pthread_mutex_unlock(&globals.lock);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
static struct file *remove_fd_map(int fd)
|
static struct file *remove_fd_map(int fd)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&globals.lock);
|
pthread_mutex_lock(&globals.lock);
|
||||||
|
|
@ -366,6 +393,7 @@ static struct file *remove_fd_map(int fd)
|
||||||
|
|
||||||
if (map != NULL) {
|
if (map != NULL) {
|
||||||
file = map->file;
|
file = map->file;
|
||||||
|
pw_log_debug("fd:%d find:%d", map->fd, fd);
|
||||||
pw_array_remove(&globals.fd_maps, map);
|
pw_array_remove(&globals.fd_maps, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -701,6 +729,24 @@ static const struct pw_registry_events registry_events = {
|
||||||
.global_remove = registry_event_global_remove,
|
.global_remove = registry_event_global_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int v4l2_dup(int oldfd)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct file *file;
|
||||||
|
|
||||||
|
res = globals.old_fops.dup(oldfd);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if ((file = find_file(oldfd)) != NULL) {
|
||||||
|
add_fd_map(res, file);
|
||||||
|
unref_file(file);
|
||||||
|
pw_log_info("fd:%d -> %d (%s)", oldfd,
|
||||||
|
res, strerror(res < 0 ? errno : 0));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int v4l2_openat(int dirfd, const char *path, int oflag, mode_t mode)
|
static int v4l2_openat(int dirfd, const char *path, int oflag, mode_t mode)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
@ -715,6 +761,12 @@ static int v4l2_openat(int dirfd, const char *path, int oflag, mode_t mode)
|
||||||
if (passthrough)
|
if (passthrough)
|
||||||
return globals.old_fops.openat(dirfd, path, oflag, mode);
|
return globals.old_fops.openat(dirfd, path, oflag, mode);
|
||||||
|
|
||||||
|
if ((file = find_file_by_dev(dev_id)) != NULL) {
|
||||||
|
res = v4l2_dup(file->fd);
|
||||||
|
unref_file(file);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
if ((file = make_file()) == NULL)
|
if ((file = make_file()) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
@ -792,24 +844,6 @@ error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v4l2_dup(int oldfd)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
struct file *file;
|
|
||||||
|
|
||||||
res = globals.old_fops.dup(oldfd);
|
|
||||||
if (res < 0)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
if ((file = find_file(oldfd)) != NULL) {
|
|
||||||
add_fd_map(res, file);
|
|
||||||
unref_file(file);
|
|
||||||
pw_log_info("fd:%d -> %d (%s)", oldfd,
|
|
||||||
res, strerror(res < 0 ? errno : 0));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int v4l2_close(int fd)
|
static int v4l2_close(int fd)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
|
|
@ -817,8 +851,12 @@ static int v4l2_close(int fd)
|
||||||
if ((file = remove_fd_map(fd)) == NULL)
|
if ((file = remove_fd_map(fd)) == NULL)
|
||||||
return globals.old_fops.close(fd);
|
return globals.old_fops.close(fd);
|
||||||
|
|
||||||
|
pw_log_info("fd:%d (%d)", fd, file->fd);
|
||||||
|
|
||||||
if (fd != file->fd)
|
if (fd != file->fd)
|
||||||
spa_system_close(file->l->system, fd);
|
spa_system_close(file->l->system, fd);
|
||||||
|
else
|
||||||
|
file->fd = -1;
|
||||||
|
|
||||||
unref_file(file);
|
unref_file(file);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue