summaryrefslogtreecommitdiffstats
path: root/input/ipc-unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'input/ipc-unix.c')
-rw-r--r--input/ipc-unix.c151
1 files changed, 79 insertions, 72 deletions
diff --git a/input/ipc-unix.c b/input/ipc-unix.c
index bfd035298c..a416b54e1e 100644
--- a/input/ipc-unix.c
+++ b/input/ipc-unix.c
@@ -15,10 +15,9 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <pthread.h>
#include <errno.h>
#include <unistd.h>
-
+#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
@@ -26,8 +25,6 @@
#include <sys/stat.h>
#include <sys/un.h>
-#include "config.h"
-
#include "osdep/io.h"
#include "osdep/threads.h"
@@ -50,7 +47,7 @@ struct mp_ipc_ctx {
struct mp_client_api *client_api;
const char *path;
- pthread_t thread;
+ mp_thread thread;
int death_pipe[2];
};
@@ -58,9 +55,10 @@ struct client_arg {
struct mp_log *log;
struct mpv_handle *client;
- char *client_name;
+ const char *client_name;
int client_fd;
bool close_client_fd;
+ bool quit_on_close;
bool writable;
};
@@ -92,10 +90,8 @@ static int ipc_write_str(struct client_arg *client, const char *buf)
return 0;
}
-static void *client_thread(void *p)
+static MP_THREAD_VOID client_thread(void *p)
{
- pthread_detach(pthread_self());
-
// We don't use MSG_NOSIGNAL because the moldy fruit OS doesn't support it.
struct sigaction sa = { .sa_handler = SIG_IGN, .sa_flags = SA_RESTART };
sigfillset(&sa.sa_mask);
@@ -106,7 +102,9 @@ static void *client_thread(void *p)
struct client_arg *arg = p;
bstr client_msg = { talloc_strdup(NULL, ""), 0 };
- mpthread_set_name(arg->client_name);
+ char *tname = talloc_asprintf(NULL, "ipc/%s", arg->client_name);
+ mp_thread_set_name(tname);
+ talloc_free(tname);
int pipe_fd = mpv_get_wakeup_pipe(arg->client);
if (pipe_fd < 0) {
@@ -162,7 +160,7 @@ static void *client_thread(void *p)
}
}
- if (fds[1].revents & (POLLIN | POLLHUP)) {
+ if (fds[1].revents & (POLLIN | POLLHUP | POLLNVAL)) {
while (1) {
char buf[128];
bstr append = { buf, 0 };
@@ -210,92 +208,92 @@ done:
talloc_free(client_msg.start);
if (arg->close_client_fd)
close(arg->client_fd);
- mpv_destroy(arg->client);
+ struct mpv_handle *h = arg->client;
+ bool quit = arg->quit_on_close;
talloc_free(arg);
- return NULL;
+ if (quit) {
+ mpv_terminate_destroy(h);
+ } else {
+ mpv_destroy(h);
+ }
+ MP_THREAD_RETURN();
}
-static void ipc_start_client(struct mp_ipc_ctx *ctx, struct client_arg *client)
+static bool ipc_start_client(struct mp_ipc_ctx *ctx, struct client_arg *client,
+ bool free_on_init_fail)
{
- client->client = mp_new_client(ctx->client_api, client->client_name);
+ if (!client->client)
+ client->client = mp_new_client(ctx->client_api, client->client_name);
if (!client->client)
goto err;
client->log = mp_client_get_log(client->client);
- pthread_t client_thr;
- if (pthread_create(&client_thr, NULL, client_thread, client))
+ mp_thread client_thr;
+ if (mp_thread_create(&client_thr, client_thread, client))
goto err;
+ mp_thread_detach(client_thr);
- return;
+ return true;
err:
- if (client->client)
- mpv_destroy(client->client);
+ if (free_on_init_fail) {
+ if (client->client)
+ mpv_destroy(client->client);
- if (client->close_client_fd)
- close(client->client_fd);
+ if (client->close_client_fd)
+ close(client->client_fd);
+ }
talloc_free(client);
+ return false;
}
static void ipc_start_client_json(struct mp_ipc_ctx *ctx, int id, int fd)
{
struct client_arg *client = talloc_ptrtype(NULL, client);
*client = (struct client_arg){
- .client_name = talloc_asprintf(client, "ipc-%d", id),
- .client_fd = fd,
- .close_client_fd = true,
-
+ .client_name =
+ id >= 0 ? talloc_asprintf(client, "ipc-%d", id) : "ipc",
+ .client_fd = fd,
+ .close_client_fd = id >= 0,
+ .quit_on_close = id < 0,
.writable = true,
};
- ipc_start_client(ctx, client);
+ ipc_start_client(ctx, client, true);
}
-static void ipc_start_client_text(struct mp_ipc_ctx *ctx, const char *path)
+bool mp_ipc_start_anon_client(struct mp_ipc_ctx *ctx, struct mpv_handle *h,
+ int out_fd[2])
{
- int mode = O_RDONLY;
- int client_fd = -1;
- bool close_client_fd = true;
- bool writable = false;
-
- if (strcmp(path, "/dev/stdin") == 0) { // for symmetry with Linux
- client_fd = STDIN_FILENO;
- close_client_fd = false;
- } else if (strncmp(path, "fd://", 5) == 0) {
- char *end = NULL;
- client_fd = strtol(path + 5, &end, 0);
- if (!end || end == path + 5 || end[0]) {
- MP_ERR(ctx, "Invalid FD: %s\n", path);
- return;
- }
- close_client_fd = false;
- writable = true; // maybe
- } else {
- // Use RDWR for FIFOs to ensure they stay open over multiple accesses.
- struct stat st;
- if (stat(path, &st) == 0 && S_ISFIFO(st.st_mode))
- mode = O_RDWR;
- client_fd = open(path, mode);
- }
- if (client_fd < 0) {
- MP_ERR(ctx, "Could not open '%s'\n", path);
- return;
- }
+ int pair[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair))
+ return false;
+ mp_set_cloexec(pair[0]);
+ mp_set_cloexec(pair[1]);
struct client_arg *client = talloc_ptrtype(NULL, client);
*client = (struct client_arg){
- .client_name = "input-file",
- .client_fd = client_fd,
- .close_client_fd = close_client_fd,
- .writable = writable,
+ .client = h,
+ .client_name = mpv_client_name(h),
+ .client_fd = pair[1],
+ .close_client_fd = true,
+ .writable = true,
};
- ipc_start_client(ctx, client);
+ if (!ipc_start_client(ctx, client, false)) {
+ close(pair[0]);
+ close(pair[1]);
+ return false;
+ }
+
+ out_fd[0] = pair[0];
+ out_fd[1] = -1;
+ return true;
}
-static void *ipc_thread(void *p)
+static MP_THREAD_VOID ipc_thread(void *p)
{
int rc;
@@ -304,7 +302,7 @@ static void *ipc_thread(void *p)
struct mp_ipc_ctx *arg = p;
- mpthread_set_name("ipc socket listener");
+ mp_thread_set_name("ipc/socket");
MP_VERBOSE(arg, "Starting IPC master\n");
@@ -314,9 +312,7 @@ static void *ipc_thread(void *p)
goto done;
}
-#if HAVE_FCHMOD
fchmod(ipc_fd, 0600);
-#endif
size_t path_len = strlen(arg->path);
if (path_len >= sizeof(ipc_un.sun_path) - 1) {
@@ -381,7 +377,7 @@ done:
if (ipc_fd >= 0)
close(ipc_fd);
- return NULL;
+ MP_THREAD_RETURN();
}
struct mp_ipc_ctx *mp_init_ipc(struct mp_client_api *client_api,
@@ -396,12 +392,23 @@ struct mp_ipc_ctx *mp_init_ipc(struct mp_client_api *client_api,
.path = mp_get_user_path(arg, global, opts->ipc_path),
.death_pipe = {-1, -1},
};
- char *input_file = mp_get_user_path(arg, global, opts->input_file);
- talloc_free(opts);
+ if (opts->ipc_client && opts->ipc_client[0]) {
+ int fd = -1;
+ if (strncmp(opts->ipc_client, "fd://", 5) == 0) {
+ char *end;
+ unsigned long l = strtoul(opts->ipc_client + 5, &end, 0);
+ if (!end[0] && l <= INT_MAX)
+ fd = l;
+ }
+ if (fd < 0) {
+ MP_ERR(arg, "Invalid IPC client argument: '%s'\n", opts->ipc_client);
+ } else {
+ ipc_start_client_json(arg, -1, fd);
+ }
+ }
- if (input_file && *input_file)
- ipc_start_client_text(arg, input_file);
+ talloc_free(opts);
if (!arg->path || !arg->path[0])
goto out;
@@ -409,7 +416,7 @@ struct mp_ipc_ctx *mp_init_ipc(struct mp_client_api *client_api,
if (mp_make_wakeup_pipe(arg->death_pipe) < 0)
goto out;
- if (pthread_create(&arg->thread, NULL, ipc_thread, arg))
+ if (mp_thread_create(&arg->thread, ipc_thread, arg))
goto out;
return arg;
@@ -429,7 +436,7 @@ void mp_uninit_ipc(struct mp_ipc_ctx *arg)
return;
(void)write(arg->death_pipe[1], &(char){0}, 1);
- pthread_join(arg->thread, NULL);
+ mp_thread_join(arg->thread);
close(arg->death_pipe[0]);
close(arg->death_pipe[1]);