Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tiwei Bie and committed by
Johannes Berg
4f087eaf 16a0ca5e

+68
+5
arch/um/include/shared/os.h
··· 224 224 unsigned int flags, unsigned long *stack_out); 225 225 extern int helper_wait(int pid); 226 226 227 + struct os_helper_thread; 228 + int os_run_helper_thread(struct os_helper_thread **td_out, 229 + void *(*routine)(void *), void *arg); 230 + void os_kill_helper_thread(struct os_helper_thread *td); 231 + void os_fix_helper_thread_signals(void); 227 232 228 233 /* umid.c */ 229 234 extern int umid_file_name(char *name, char *buf, int len);
+63
arch/um/os-Linux/helper.c
··· 8 8 #include <unistd.h> 9 9 #include <errno.h> 10 10 #include <sched.h> 11 + #include <pthread.h> 11 12 #include <linux/limits.h> 12 13 #include <sys/socket.h> 13 14 #include <sys/wait.h> ··· 167 166 return -ECHILD; 168 167 } else 169 168 return 0; 169 + } 170 + 171 + struct os_helper_thread { 172 + pthread_t handle; 173 + }; 174 + 175 + int os_run_helper_thread(struct os_helper_thread **td_out, 176 + void *(*routine)(void *), void *arg) 177 + { 178 + struct os_helper_thread *td; 179 + sigset_t sigset, oset; 180 + int err, flags; 181 + 182 + flags = __uml_cant_sleep() ? UM_GFP_ATOMIC : UM_GFP_KERNEL; 183 + td = uml_kmalloc(sizeof(*td), flags); 184 + if (!td) 185 + return -ENOMEM; 186 + 187 + sigfillset(&sigset); 188 + if (sigprocmask(SIG_SETMASK, &sigset, &oset) < 0) { 189 + err = -errno; 190 + kfree(td); 191 + return err; 192 + } 193 + 194 + err = pthread_create(&td->handle, NULL, routine, arg); 195 + 196 + if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) 197 + panic("Failed to restore the signal mask: %d", errno); 198 + 199 + if (err != 0) 200 + kfree(td); 201 + else 202 + *td_out = td; 203 + 204 + return -err; 205 + } 206 + 207 + void os_kill_helper_thread(struct os_helper_thread *td) 208 + { 209 + pthread_cancel(td->handle); 210 + pthread_join(td->handle, NULL); 211 + kfree(td); 212 + } 213 + 214 + void os_fix_helper_thread_signals(void) 215 + { 216 + sigset_t sigset; 217 + 218 + sigemptyset(&sigset); 219 + 220 + sigaddset(&sigset, SIGWINCH); 221 + sigaddset(&sigset, SIGPIPE); 222 + sigaddset(&sigset, SIGPROF); 223 + sigaddset(&sigset, SIGINT); 224 + sigaddset(&sigset, SIGTERM); 225 + sigaddset(&sigset, SIGCHLD); 226 + sigaddset(&sigset, SIGALRM); 227 + sigaddset(&sigset, SIGIO); 228 + sigaddset(&sigset, SIGUSR1); 229 + 230 + pthread_sigmask(SIG_SETMASK, &sigset, NULL); 170 231 }