From dc9c271aa1349fd866fa055f92714fb81319abc5 Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Thu, 7 Jan 1999 21:23:50 +0000 Subject: [PATCH] Changes to the LINUX_THREADS support to only allocate extra memory for shared signal handling when there is shared signal handling being used. This removes the main objection to making the shared signal handling a standard ability in rfork() and friends and 'unconditionalising' this code. (i.e. the allocation of an extra 328 bytes per process). Signal handling information remains in the U area until such a time as it's reference count would be incremented to > 1. At that point a new struct is malloc'd and maintained in KVM so that it can be shared between the processes (threads) using it. A function to check the reference count and move the struct back to the U area when it drops back to 1 is also supplied. Signal information is therefore now swapable for all processes that are not sharing that information with other processes. THis should addres the concerns raised by Garrett and others. Submitted by: "Richard Seaman, Jr." --- sys/kern/init_main.c | 12 +----------- sys/kern/kern_exit.c | 43 ++++++++++++++++++++++++++----------------- sys/kern/kern_fork.c | 36 ++++++++++++++++++++++++++++-------- sys/sys/proc.h | 25 ++++++++++--------------- sys/sys/signalvar.h | 6 ++++-- sys/sys/unistd.h | 3 +-- sys/sys/user.h | 6 +----- sys/vm/vm_glue.c | 11 ++++++++++- 8 files changed, 81 insertions(+), 61 deletions(-) diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 9269b264f8fd..246684f88362 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -39,7 +39,7 @@ * SUCH DAMAGE. * * @(#)init_main.c 8.9 (Berkeley) 1/21/94 - * $Id: init_main.c,v 1.101 1998/12/19 08:23:31 julian Exp $ + * $Id: init_main.c,v 1.102 1998/12/30 10:38:58 dfr Exp $ */ #include "opt_devfs.h" @@ -469,22 +469,12 @@ proc0_init(dummy) #endif /* INCOMPAT_LITES2*/ #endif -#ifndef COMPAT_LINUX_THREADS /* * We continue to place resource usage info and signal * actions in the user struct so they're pageable. */ p->p_stats = &p->p_addr->u_stats; p->p_sigacts = &p->p_addr->u_sigacts; -#else - /* - * We continue to place resource usage info in the user struct so - * it's pageable. - */ - p->p_stats = &p->p_addr->u_stats; - - p->p_sigacts = &p->p_procsig->ps_sigacts; -#endif /* COMPAT_LINUX_THREADS */ /* * Charge root for one process. diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 7de0c480ebc7..7be01af67fac 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 - * $Id: kern_exit.c,v 1.69 1998/11/11 10:03:54 truckman Exp $ + * $Id: kern_exit.c,v 1.70 1998/12/19 02:55:33 julian Exp $ */ #include "opt_compat.h" @@ -73,6 +73,9 @@ #include #include #include +#ifdef COMPAT_LINUX_THREADS +#include +#endif static MALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status"); @@ -438,14 +441,6 @@ loop: if (uap->pid != WAIT_ANY && p->p_pid != uap->pid && p->p_pgid != -uap->pid) continue; -#ifdef COMPAT_LINUX_THREADS - #if 0 - if ((p->p_sigparent != 0) ^ ((uap->options & WLINUXCLONE) != 0)) { - continue; - } - #endif - -#endif /* COMPAT_LINUX_THREADS */ nfound++; if (p->p_stat == SZOMB) { /* charge childs scheduling cpu usage to parent */ @@ -515,11 +510,11 @@ loop: #ifdef COMPAT_LINUX_THREADS if (--p->p_procsig->ps_refcnt == 0) { - free(p->p_procsig, M_TEMP); + if (p->p_sigacts != &p->p_addr->u_sigacts) + FREE(p->p_sigacts, M_SUBPROC); + FREE(p->p_procsig, M_SUBPROC); p->p_procsig = NULL; - p->p_sigacts = NULL; } - #endif /* COMPAT_LINUX_THREADS */ /* * Give machine-dependent layer a chance @@ -576,11 +571,6 @@ proc_reparent(child, parent) LIST_REMOVE(child, p_sibling); LIST_INSERT_HEAD(&parent->p_children, child, p_sibling); child->p_pptr = parent; -#ifdef COMPAT_LINUX_THREADS - #if 0 - child->p_sigparent = 0; - #endif -#endif /* COMPAT_LINUX_THREADS */ } /* @@ -636,3 +626,22 @@ rm_at_exit(function) } return (count); } + +#ifdef COMPAT_LINUX_THREADS +void check_sigacts (void) +{ + struct proc *p = curproc; + struct sigacts *pss; + int s; + + if (p->p_procsig->ps_refcnt == 1 && + p->p_sigacts != &p->p_addr->u_sigacts) { + pss = p->p_sigacts; + s = splhigh(); + p->p_addr->u_sigacts = *pss; + p->p_sigacts = &p->p_addr->u_sigacts; + splx(s); + FREE(pss, M_SUBPROC); + } +} +#endif diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index ef38e011908e..732712b32fd8 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)kern_fork.c 8.6 (Berkeley) 4/8/94 - * $Id: kern_fork.c,v 1.52 1998/11/09 15:07:41 truckman Exp $ + * $Id: kern_fork.c,v 1.53 1998/12/19 02:55:33 julian Exp $ */ #include "opt_ktrace.h" @@ -64,7 +64,7 @@ #ifdef COMPAT_LINUX_THREADS #include - +#include #endif /* COMPAT_LINUX_THREADS */ #ifdef SMP static int fast_vfork = 0; /* Doesn't work on SMP yet. */ @@ -331,21 +331,41 @@ again: #ifdef COMPAT_LINUX_THREADS if (flags & RFSIGSHARE) { + p2->p_procsig = p1->p_procsig; p2->p_procsig->ps_refcnt++; + if (p1->p_sigacts == &p1->p_addr->u_sigacts) { + struct sigacts *newsigacts; + int s; + + if (p2->p_procsig->ps_refcnt != 2) + printf ("PID:%d Creating shared sigacts with procsig->ps_refcnt %d\n", + p2->p_pid, p2->p_procsig->ps_refcnt); + /* Create the shared sigacts structure */ + MALLOC (newsigacts, struct sigacts *, sizeof (struct sigacts), + M_SUBPROC, M_WAITOK); + s = splhigh(); + /* Set p_sigacts to the new shared structure. Note that this + * is updating p1->p_sigacts at the same time, since p_sigacts + * is just a pointer to the shared p_procsig->ps_sigacts. + */ + p2->p_sigacts = newsigacts; + /* Copy in the values from the u area */ + *p2->p_sigacts = p1->p_addr->u_sigacts; + splx (s); + } } else { - p2->p_procsig = malloc(sizeof(struct procsig), M_TEMP, M_WAITOK); - p2->p_procsig->ps_refcnt = 1; - p2->p_procsig->ps_posix = 0; + MALLOC (p2->p_procsig, struct procsig *, sizeof(struct procsig), + M_SUBPROC, M_WAITOK); bcopy(&p1->p_procsig->ps_begincopy, &p2->p_procsig->ps_begincopy, (unsigned)&p1->p_procsig->ps_endcopy - (unsigned)&p1->p_procsig->ps_begincopy); + p2->p_procsig->ps_refcnt = 1; + /* Note that we fill in the values of sigacts in vm_fork */ + p2->p_sigacts = NULL; } if (flags & RFLINUXTHPN) { p2->p_sigparent = SIGUSR1; } - p2->p_sigacts = &p2->p_procsig->ps_sigacts; - if((flags & RFTHREAD) != 0 && (flags & RFPOSIXSIG) != 0) - p2->p_procsig->ps_posix = 1; #endif /* COMPAT_LINUX_THREADS */ /* bump references to the text vnode (for procfs) */ p2->p_textvp = p1->p_textvp; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index d590b426bdba..1b7d5ad15710 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)proc.h 8.15 (Berkeley) 5/19/95 - * $Id: proc.h,v 1.64 1998/12/21 07:41:50 dillon Exp $ + * $Id: proc.h,v 1.65 1998/12/31 13:23:16 bde Exp $ */ #ifndef _SYS_PROC_H_ @@ -86,13 +86,11 @@ struct procsig { #define ps_begincopy ps_sigignore sigset_t ps_sigignore; /* Signals being ignored. */ sigset_t ps_sigcatch; /* Signals being caught by user. */ - int ps_flag; - struct sigacts ps_sigacts; + int ps_flag; + struct sigacts *ps_sigacts; #define ps_endcopy ps_refcnt int ps_refcnt; - int ps_posix; }; - #endif /* COMPAT_LINUX_THREADS */ /* @@ -125,7 +123,14 @@ struct proc { struct pstats *p_stats; /* Accounting/statistics (PROC ONLY). */ struct plimit *p_limit; /* Process limits. */ struct vm_object *p_upages_obj;/* Upages object */ +#ifndef COMPAT_LINUX_THREADS struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */ +#else + struct procsig *p_procsig; +#define p_sigacts p_procsig->ps_sigacts +#define p_sigignore p_procsig->ps_sigignore +#define p_sigcatch p_procsig->ps_sigcatch +#endif #define p_ucred p_cred->pc_ucred #define p_rlimit p_limit->pl_rlimit @@ -201,22 +206,12 @@ struct proc { #define p_endzero p_startcopy /* The following fields are all copied upon creation in fork. */ -#ifndef COMPAT_LINUX_THREADS #define p_startcopy p_sigmask -#else -#define p_startcopy p_procsig -#endif /* COMPAT_LINUX_THREADS */ -#ifdef COMPAT_LINUX_THREADS - struct procsig *p_procsig; -#define p_sigignore p_procsig->ps_sigignore -#define p_sigcatch p_procsig->ps_sigcatch -#endif /* COMPAT_LINUX_THREADS */ sigset_t p_sigmask; /* Current signal mask. */ #ifndef COMPAT_LINUX_THREADS sigset_t p_sigignore; /* Signals being ignored. */ sigset_t p_sigcatch; /* Signals being caught by user. */ - #endif /* COMPAT_LINUX_THREADS */ u_char p_priority; /* Process priority. */ u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index a97f950b5477..658c6cb29c78 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)signalvar.h 8.6 (Berkeley) 2/19/95 - * $Id: signalvar.h,v 1.20 1998/11/11 10:04:13 truckman Exp $ + * $Id: signalvar.h,v 1.21 1998/12/19 02:55:34 julian Exp $ */ #ifndef _SYS_SIGNALVAR_H_ /* tmp for user.h */ @@ -175,7 +175,9 @@ void psignal __P((struct proc *p, int sig)); void sigexit __P((struct proc *p, int signum)); void siginit __P((struct proc *p)); void trapsignal __P((struct proc *p, int sig, u_long code)); - +#ifdef COMPAT_LINUX_THREADS +void check_sigacts (void); +#endif /* * Machine-dependent functions: */ diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h index 17b2028a99a4..d6216039f6b9 100644 --- a/sys/sys/unistd.h +++ b/sys/sys/unistd.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)unistd.h 8.2 (Berkeley) 1/7/94 - * $Id: unistd.h,v 1.17 1998/03/28 11:51:01 dufault Exp $ + * $Id: unistd.h,v 1.18 1998/12/19 02:55:34 julian Exp $ */ #ifndef _SYS_UNISTD_H_ @@ -187,7 +187,6 @@ #define RFCFDG (1<<12) /* zero fd table */ #define RFTHREAD (1<<13) /* enable kernel thread support */ #define RFSIGSHARE (1<<14) /* share signal handlers */ -#define RFPOSIXSIG (1<<15) /* UNIMPL posix thread signal delivery */ #define RFLINUXTHPN (1<<16) /* do linux clone exit parent notification */ #define RFPPWAIT (1<<31) /* parent sleeps until child exits (vfork) */ diff --git a/sys/sys/user.h b/sys/sys/user.h index f97891cbfb2a..df6715461183 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)user.h 8.2 (Berkeley) 9/23/93 - * $Id: user.h,v 1.16 1998/07/15 20:18:00 dfr Exp $ + * $Id: user.h,v 1.17 1998/12/19 02:55:34 julian Exp $ */ #ifndef _SYS_USER_H_ @@ -101,12 +101,8 @@ void fill_eproc __P((struct proc *, struct eproc *)); struct user { struct pcb u_pcb; - -#ifndef COMPAT_LINUX_THREADS struct sigacts u_sigacts; /* p_sigacts points here (use it!) */ -#endif /* COMPAT_LINUX_THREADS */ struct pstats u_stats; /* p_stats points here (use it!) */ - /* * Remaining fields only for core dump and/or ptrace-- * not valid at other times! diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index ce4786f8e834..ec844dbba246 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -59,7 +59,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_glue.c,v 1.78 1998/12/19 02:55:34 julian Exp $ + * $Id: vm_glue.c,v 1.79 1998/12/19 08:23:31 julian Exp $ */ #include "opt_rlimit.h" @@ -243,8 +243,17 @@ vm_fork(p1, p2, flags) * p_stats currently points at fields in the user struct * but not at &u, instead at p_addr. Copy parts of * p_stats; zero the rest of p_stats (statistics). + * + * If procsig->ps_refcnt is 1 and p2->p_sigacts is NULL we dont' need + * to share sigacts, so we use the up->u_sigacts. */ p2->p_stats = &up->u_stats; + if (p2->p_sigacts == NULL) { + if (p2->p_procsig->ps_refcnt != 1) + printf ("PID:%d NULL sigacts with refcnt not 1!\n",p2->p_pid); + p2->p_sigacts = &up->u_sigacts; + up->u_sigacts = *p1->p_sigacts; + } #endif /* COMPAT_LINUX_THREADS */ bzero(&up->u_stats.pstat_startzero, (unsigned) ((caddr_t) &up->u_stats.pstat_endzero -