Introduce a new set of utility functions that can be used to create
pthread-based helpers. Helper threads created in this way will ensure
thread safety for errno while sharing the same memory space.

Signed-off-by: Tiwei Bie <tiwei....@antgroup.com>
---
 arch/um/include/shared/os.h |  5 +++
 arch/um/os-Linux/helper.c   | 63 +++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index bc02767f0639..d0ae42911cb5 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -224,6 +224,11 @@ extern int run_helper_thread(int (*proc)(void *), void 
*arg,
                             unsigned int flags, unsigned long *stack_out);
 extern int helper_wait(int pid);
 
+struct os_helper_thread;
+int os_run_helper_thread(struct os_helper_thread **td_out,
+                        void *(*routine)(void *), void *arg);
+void os_kill_helper_thread(struct os_helper_thread *td);
+void os_fix_helper_thread_signals(void);
 
 /* umid.c */
 extern int umid_file_name(char *name, char *buf, int len);
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index 3cb8ac63be6e..df22cba24d82 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sched.h>
+#include <pthread.h>
 #include <linux/limits.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
@@ -167,3 +168,65 @@ int helper_wait(int pid)
        } else
                return 0;
 }
+
+struct os_helper_thread {
+       pthread_t handle;
+};
+
+int os_run_helper_thread(struct os_helper_thread **td_out,
+                        void *(*routine)(void *), void *arg)
+{
+       struct os_helper_thread *td;
+       sigset_t sigset, oset;
+       int err, flags;
+
+       flags = __uml_cant_sleep() ? UM_GFP_ATOMIC : UM_GFP_KERNEL;
+       td = uml_kmalloc(sizeof(*td), flags);
+       if (!td)
+               return -ENOMEM;
+
+       sigfillset(&sigset);
+       if (sigprocmask(SIG_SETMASK, &sigset, &oset) < 0) {
+               err = -errno;
+               kfree(td);
+               return err;
+       }
+
+       err = pthread_create(&td->handle, NULL, routine, arg);
+
+       if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0)
+               panic("Failed to restore the signal mask: %d", errno);
+
+       if (err != 0)
+               kfree(td);
+       else
+               *td_out = td;
+
+       return -err;
+}
+
+void os_kill_helper_thread(struct os_helper_thread *td)
+{
+       pthread_cancel(td->handle);
+       pthread_join(td->handle, NULL);
+       kfree(td);
+}
+
+void os_fix_helper_thread_signals(void)
+{
+       sigset_t sigset;
+
+       sigemptyset(&sigset);
+
+       sigaddset(&sigset, SIGWINCH);
+       sigaddset(&sigset, SIGPIPE);
+       sigaddset(&sigset, SIGPROF);
+       sigaddset(&sigset, SIGINT);
+       sigaddset(&sigset, SIGTERM);
+       sigaddset(&sigset, SIGCHLD);
+       sigaddset(&sigset, SIGALRM);
+       sigaddset(&sigset, SIGIO);
+       sigaddset(&sigset, SIGUSR1);
+
+       pthread_sigmask(SIG_SETMASK, &sigset, NULL);
+}
-- 
2.34.1


Reply via email to