Subject: Re: stopping childs (patch included)
To: matthew green <mrg@eterna.com.au>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 11/05/2002 23:16:59
> i dunno about emmanuel, but for me the fact that the child runs
> for an indeterminate amount of time is not enough. it may run
> to completion even, before the parent gets scheduled again...
> this feature i would like.
I reworked a bit the patch, by splitting the stop on fork and stop on
exec. We now have two short int values that can be changed by sysctl,
one for stopping on fork and one for stopping on exec.
The values are short instead of int to save memory in struct proc. Since
this is a debug feature, no one will load it with big values. I even
wonder is just sticking to a char instead of a short would not be better
(that would leave 2 bytes of padding that could be used for something
else)
Here is the new patch. Comment, opinions, before I commit it?
Oh, yes: I wonder if this feature would not be better integrated into
systrace, than using two sysctl. The interface would be more generic,
but on the other hand, stopping just after the system call is a need
really specific to fork and exec...
Index: sys/sys/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.147
diff -U4 -r1.147 proc.h
--- sys/sys/proc.h 2002/10/23 09:14:59 1.147
+++ sys/sys/proc.h 2002/11/05 22:14:56
@@ -186,8 +186,10 @@
*/
#define p_startzero p_opptr
struct proc *p_opptr; /* Save parent during ptrace. */
+ u_short p_stopfork; /* Stop child on fork */
+ u_short p_stopexec; /* Stop on exec */
int p_dupfd; /* Sideways return value from
filedescopen. XXX */
/* Scheduling */
u_int p_estcpu; /* Time averaged value of
p_cpticks. XXX belongs in p_startcopy section */
Index: sys/sys/sysctl.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/sysctl.h,v
retrieving revision 1.78
diff -U4 -r1.78 sysctl.h
--- sys/sys/sysctl.h 2002/08/26 13:09:39 1.78
+++ sys/sys/sysctl.h 2002/11/05 22:14:58
@@ -75,8 +75,9 @@
#define CTLTYPE_INT 2 /* name describes an integer */
#define CTLTYPE_STRING 3 /* name describes a string */
#define CTLTYPE_QUAD 4 /* name describes a 64-bit
number */
#define CTLTYPE_STRUCT 5 /* name describes a structure */
+#define CTLTYPE_SHORT 6 /* name describes a short
integer */
/*
* Top-level identifiers
*/
@@ -589,14 +590,18 @@
* (rlimit.<type>.{hard,soft}, int).
*/
#define PROC_PID_CORENAME 1
#define PROC_PID_LIMIT 2
-#define PROC_PID_MAXID 3
+#define PROC_PID_STOPFORK 3
+#define PROC_PID_STOPEXEC 4
+#define PROC_PID_MAXID 5
#define PROC_PID_NAMES { \
{ 0, 0 }, \
{ "corename", CTLTYPE_STRING }, \
{ "rlimit", CTLTYPE_NODE }, \
+ { "stopfork", CTLTYPE_SHORT }, \
+ { "stopexec", CTLTYPE_SHORT }, \
}
/* Limit types from <sys/resources.h> */
#define PROC_PID_LIMIT_CPU (RLIMIT_CPU+1)
@@ -682,8 +687,10 @@
*/
typedef int (sysctlfn)
(int *, u_int, void *, size_t *, void *, size_t, struct proc *);
+int sysctl_short(void *, size_t *, void *, size_t, short *);
+int sysctl_rdshort(void *, size_t *, void *, short);
int sysctl_int(void *, size_t *, void *, size_t, int *);
int sysctl_rdint(void *, size_t *, void *, int);
int sysctl_quad(void *, size_t *, void *, size_t, quad_t *);
int sysctl_rdquad(void *, size_t *, void *, quad_t);
Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_sysctl.c,v
retrieving revision 1.114
diff -U4 -r1.114 kern_sysctl.c
--- sys/kern/kern_sysctl.c 2002/11/02 07:25:21 1.114
+++ sys/kern/kern_sysctl.c 2002/11/05 22:15:02
@@ -743,11 +743,28 @@
if (i == p->p_ucred->cr_ngroups)
return EPERM;
}
}
- if (name[1] == PROC_PID_CORENAME) {
+ switch(name[1]) {
+ case PROC_PID_STOPFORK:
if (namelen != 2)
return EINVAL;
+ error = sysctl_short(oldp, oldlenp, newp,
+ newlen, &ptmp->p_stopfork);
+ return error;
+ break;
+
+ case PROC_PID_STOPEXEC:
+ if (namelen != 2)
+ return EINVAL;
+ error = sysctl_short(oldp, oldlenp, newp,
+ newlen, &ptmp->p_stopexec);
+ return error;
+ break;
+
+ case PROC_PID_CORENAME:
+ if (namelen != 2)
+ return EINVAL;
/*
* Can't use sysctl_string() here because we may malloc
a new
* area during the process, so we have to do it by hand.
*/
@@ -813,10 +830,11 @@
cleanup:
if (tmps)
free(tmps, M_TEMP);
return (error);
- }
- if (name[1] == PROC_PID_LIMIT) {
+ break;
+
+ case PROC_PID_LIMIT:
if (namelen != 4 || name[2] >= PROC_PID_LIMIT_MAXID)
return EINVAL;
memcpy(&alim, &ptmp->p_rlimit[name[2] - 1],
sizeof(alim));
if (name[3] == PROC_PID_LIMIT_TYPE_HARD)
@@ -834,9 +852,15 @@
if (newp)
error = dosetrlimit(ptmp, p->p_cred,
name[2] - 1, &alim);
return error;
+ break;
+
+ default:
+ return (EINVAL);
+ break;
}
+ /* NOTREACHED */
return (EINVAL);
}
int
@@ -939,8 +963,42 @@
if (error == 0) \
error = err2; \
} \
}
+
+/*
+ * Validate parameters and get old / set new parameters
+ * for a short integer-valued sysctl function.
+ */
+int
+sysctl_short(void *oldp, size_t *oldlenp, void *newp,
+ size_t newlen, short *valp)
+{
+ int error = 0;
+
+ SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, short)
+ SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, short)
+ SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, short)
+
+ return (error);
+}
+
+
+/*
+ * As above, but read-only.
+ */
+int
+sysctl_rdshort(void *oldp, size_t *oldlenp, void *newp, short val)
+{
+ int error = 0;
+
+ if (newp)
+ return (EPERM);
+
+ SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, short)
+
+ return (error);
+}
/*
* Validate parameters and get old / set new parameters
* for an integer-valued sysctl function.
Index: sys/kern/kern_fork.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_fork.c,v
retrieving revision 1.96
diff -U4 -r1.96 kern_fork.c
--- sys/kern/kern_fork.c 2002/10/23 09:14:17 1.96
+++ sys/kern/kern_fork.c 2002/11/05 22:15:03
@@ -470,15 +470,23 @@
*/
proclist_unlock_write(s);
/*
- * Make child runnable, set start time, and add to run queue.
+ * Make child runnable, set start time, and add to run queue
+ * except if the parent requested the child to start in SSTOP
state.
*/
SCHED_LOCK(s);
p2->p_stats->p_start = time;
p2->p_acflag = AFORK;
- p2->p_stat = SRUN;
- setrunqueue(p2);
+ if (p1->p_stopfork) {
+ p2->p_stat = SSTOP;
+ p1->p_stopfork--;
+ p2->p_stopfork = p1->p_stopfork;
+ p2->p_stopexec = p1->p_stopexec;
+ } else {
+ p2->p_stat = SRUN;
+ setrunqueue(p2);
+ }
SCHED_UNLOCK(s);
/*
* Now can be swapped.
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_exec.c,v
retrieving revision 1.161
diff -U4 -r1.161 kern_exec.c
--- sys/kern/kern_exec.c 2002/11/01 19:27:05 1.161
+++ sys/kern/kern_exec.c 2002/11/05 22:15:05
@@ -737,8 +737,21 @@
#ifdef LKM
lockmgr(&exec_lock, LK_RELEASE, NULL);
#endif
p->p_flag &= ~P_INEXEC;
+
+ if (p->p_stopexec) {
+ int s;
+
+ sigminusset(&contsigmask, &p->p_sigctx.ps_siglist);
+ SCHED_LOCK(s);
+ p->p_stopexec--;
+ p->p_stat = SSTOP;
+ mi_switch(p, NULL);
+ SCHED_ASSERT_UNLOCKED();
+ splx(s);
+ }
+
return (EJUSTRETURN);
bad:
p->p_flag &= ~P_INEXEC;
Index: lib/libc/gen/sysctl.3
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/gen/sysctl.3,v
retrieving revision 1.99
diff -U4 -r1.99 sysctl.3
--- lib/libc/gen/sysctl.3 2002/10/01 16:59:47 1.99
+++ lib/libc/gen/sysctl.3 2002/11/05 22:15:09
@@ -1272,8 +1272,10 @@
points to the current process, or the PID of the target process.
.Bl -column "USER_COLL_WEIGHTS_MAXXXX" "integerXXX" "yes" -offset
indent
.It Sy Pa Third level name Type Changeable
.It PROC\_PID\_CORENAME string yes
+.It PROC\_STOPEXEC short yes
+.It PROC\_STOPFORK short yes
.It PROC\_PID\_LIMIT node not applicable
.El
.Bl -tag -width "123456"
.Pp
@@ -1329,8 +1331,24 @@
.Pp
The fifth level name is one of PROC_PID_LIMIT_TYPE_SOFT or
PROC_PID_LIMIT_TYPE_HARD, to select respectively the soft or hard
limit.
Both are of type integer.
+.It Li PROC_STOPEXEC
+If non zero, the process will be stopped on next
+.Xr exec 2
+call, and PROC_STOPEXEC will be decreased by one at that time.
+The stopped process can be easily attached by a debugger such as
+.Xr gdb 1 .
+.It Li PROC_STOPFORK
+If non zero, the process' child will be stopped on next
+.Xr fork 2
+call, and PROC_STOPFORK will be decreased by one at that time, for both
+the parent and the child.
+This also apply to emulation specific system calls that
+fork a new process, such as
+.Fn sproc
+or
+.Fn clone .
.El
.Sh CTL_USER
The string and integer information available for the CTL_USER level
is detailed below.
Index: sbin/sysctl/sysctl.8
===================================================================
RCS file: /cvsroot/basesrc/sbin/sysctl/sysctl.8,v
retrieving revision 1.81
diff -U4 -r1.81 sysctl.8
--- sbin/sysctl/sysctl.8 2002/10/03 15:41:47 1.81
+++ sbin/sysctl/sysctl.8 2002/11/05 22:15:10
@@ -355,8 +355,10 @@
.It proc.\*[Lt]pid\*[Gt].rlimit.memoryuse.hard integer yes
.It proc.\*[Lt]pid\*[Gt].rlimit.memoryuse.soft integer yes
.It proc.\*[Lt]pid\*[Gt].rlimit.stacksize.hard integer yes
.It proc.\*[Lt]pid\*[Gt].rlimit.stacksize.soft integer yes
+.It proc.\*[Lt]pid\*[Gt].stopexec short yes
+.It proc.\*[Lt]pid\*[Gt].stopfork short yes
.It user.bc_base_max integer no
.It user.bc_dim_max integer no
.It user.bc_scale_max integer no
.It user.bc_string_max integer no
Index: sbin/sysctl/sysctl.c
===================================================================
RCS file: /cvsroot/basesrc/sbin/sysctl/sysctl.c,v
retrieving revision 1.59
diff -U4 -r1.59 sysctl.c
--- sbin/sysctl/sysctl.c 2002/11/03 07:06:06 1.59
+++ sbin/sysctl/sysctl.c 2002/11/05 22:15:12
@@ -318,8 +318,9 @@
{
int indx, type, state, len;
int special = 0;
void *newval = 0;
+ short shortval;
int intval, newsize = 0;
quad_t quadval;
size_t size;
struct list *lp;
@@ -553,8 +554,14 @@
return;
}
if (newsize > 0) {
switch (type) {
+ case CTLTYPE_SHORT:
+ shortval = (short)atoi(newval);
+ newval = &shortval;
+ newsize = sizeof shortval;
+ break;
+
case CTLTYPE_INT:
intval = atoi(newval);
newval = &intval;
newsize = sizeof intval;
@@ -647,8 +654,20 @@
return;
}
switch (type) {
+ case CTLTYPE_SHORT:
+ if (newsize == 0) {
+ if (!nflag)
+ printf("%s = ", string);
+ printf("%hd\n", *(short *)buf);
+ } else {
+ if (!nflag)
+ printf("%s: %hd -> ", string, *(short
*)buf);
+ printf("%hd\n", *(short *)newval);
+ }
+ return;
+
case CTLTYPE_INT:
if (newsize == 0) {
if (!nflag)
printf("%s = ", string);
--
Emmanuel Dreyfus.
"Of course, it runs NetBSD" -- http://www.netbsd.org
manu@netbsd.org