um: Add pthread-based helper support

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.btw@antgroup.com>
Link: https://patch.msgid.link/20250319135523.97050-2-tiwei.btw@antgroup.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Tiwei Bie 2025-03-19 21:55:20 +08:00 committed by Johannes Berg
parent 16a0ca5e4e
commit 4f087eafdc
2 changed files with 68 additions and 0 deletions

View File

@ -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);

View File

@ -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);
}