CPPFLAGS+= -DUSE_STATECTL
.endif
+.if ${USE_TRACE} != "no"
+CPPFLAGS+= -DUSE_TRACE
+.endif
+
# These come last, so the profiling buffer is at the end of the data segment
SRCS+= profile.c do_sprofile.c
#define USE_EXEC 1 /* update process after execute */
#define USE_CLEAR 1 /* clean up after process exit */
#define USE_EXIT 1 /* a system process wants to exit */
-#define USE_TRACE 1 /* process information and tracing */
#define USE_GETKSIG 1 /* retrieve pending kernel signals */
#define USE_ENDKSIG 1 /* finish pending kernel signals */
#define USE_KILL 1 /* send a signal to a process */
# Makefile for Process Manager (PM)
PROG= pm
SRCS= main.c forkexit.c break.c exec.c time.c alarm.c \
- signal.c utility.c table.c trace.c getset.c misc.c \
+ signal.c utility.c table.c getset.c misc.c \
profile.c dma.c schedule.c
.if ${USE_MCONTEXT} != "no"
CPPFLAGS+= -DUSE_MCONTEXT
.endif
+.if ${USE_TRACE} != "no"
+SRCS+= trace.c
+CPPFLAGS+= -DUSE_TRACE
+.endif
+
DPADD+= ${LIBSYS} ${LIBTIMERS}
LDADD+= -lsys -ltimers
/* Cause a signal if this process is traced.
* Do this before making the process runnable again!
*/
+#if USE_TRACE
if (rmp->mp_tracer != NO_TRACER && !(rmp->mp_trace_flags & TO_NOEXEC))
{
sn = (rmp->mp_trace_flags & TO_ALTEXEC) ? SIGSTOP : SIGTRAP;
check_sig(rmp->mp_pid, sn, FALSE /* ksig */);
}
+#endif /* USE_TRACE */
new_sp= (char *)rmp->mp_frame_addr;
r= sys_exec(rmp->mp_endpoint, new_sp, rmp->mp_name, pc);
tell_vfs(rmc, &m);
+#if USE_TRACE
/* Tell the tracer, if any, about the new child */
if (rmc->mp_tracer != NO_TRACER)
sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);
+#endif /* USE_TRACE */
/* Do not reply until VFS is ready to process the fork
* request
tell_vfs(rmc, &m);
+#if USE_TRACE
/* Tell the tracer, if any, about the new child */
if (rmc->mp_tracer != NO_TRACER)
sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);
+#endif /* USE_TRACE */
/* Wakeup the newly created process */
setreply(rmc-mproc, OK);
/* If the process has children, disinherit them. INIT is the new parent. */
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
if (!(rmp->mp_flags & IN_USE)) continue;
+#if USE_TRACE
if (rmp->mp_tracer == proc_nr) {
/* This child's tracer died. Do something sensible. */
tracer_died(rmp);
}
+#endif /* USE_TRACE */
if (rmp->mp_parent == proc_nr) {
/* 'rmp' now points to a child to be disinherited. */
rmp->mp_parent = INIT_PROC_NR;
panic("exit_restart: vm_exit failed: %d", r);
}
+#if USE_TRACE
if (rmp->mp_flags & TRACE_EXIT)
{
/* Wake up the tracer, completing the ptrace(T_EXIT) call */
mproc[rmp->mp_tracer].mp_reply.reply_trace = 0;
setreply(rmp->mp_tracer, OK);
}
+#endif /* USE_TRACE */
/* Clean up if the parent has collected the exit status */
if (rmp->mp_flags & TOLD_PARENT)
children++; /* this child is acceptable */
+#if USE_TRACE
if (rp->mp_tracer == who_p) {
if (rp->mp_flags & TRACE_ZOMBIE) {
/* Traced child meets the pid test and has exited. */
}
}
}
+#endif /* USE_TRACE */
if (rp->mp_parent == who_p) {
if (rp->mp_flags & ZOMBIE) {
/* See if we have to notify a tracer process first. */
if (rmp->mp_tracer != NO_TRACER && rmp->mp_tracer != rmp->mp_parent) {
+#if USE_TRACE
rmp->mp_flags |= TRACE_ZOMBIE;
t_mp = &mproc[rmp->mp_tracer];
return;
tell_tracer(rmp);
+#endif /* USE_TRACE */
}
else {
rmp->mp_flags |= ZOMBIE;
child->mp_flags |= TOLD_PARENT; /* avoid informing parent twice */
}
+#if USE_TRACE
/*===========================================================================*
* tell_tracer *
*===========================================================================*/
check_parent(child, TRUE /*try_cleanup*/);
}
}
+#endif /* USE_TRACE */
/*===========================================================================*
* cleanup *
/* trace.c */
_PROTOTYPE( int do_trace, (void) );
_PROTOTYPE( void stop_proc, (struct mproc *rmp, int sig_nr) );
+#if ! USE_TRACE
+#define do_trace no_sys
+#define stop_proc no_sys
+#endif
/* utility.c */
_PROTOTYPE( pid_t get_free_pid, (void) );
panic("");
}
+#if USE_TRACE
if (trace == TRUE && rmp->mp_tracer != NO_TRACER && signo != SIGKILL) {
/* Signal should be passed to the debugger first.
* This happens before any checks on block/ignore masks; otherwise,
return;
}
+#endif
if (rmp->mp_flags & VFS_CALL) {
(void) sigaddset(&rmp->mp_sigpending, signo);
return;
}
+#if USE_TRACE
if ((rmp->mp_flags & STOPPED) && signo != SIGKILL) {
/* If the process is stopped for a debugger, do not deliver any signals
* (except SIGKILL) in order not to confuse the debugger. The signals
(void) sigaddset(&rmp->mp_ksigpending, signo);
return;
}
+#endif /* USE_TRACE */
if (!badignore && sigismember(&rmp->mp_catch, signo)) {
/* Signal is caught. First interrupt the process's current call, if
* applicable. This may involve a roundtrip to VFS, in which case we'll
if (rmp->mp_flags & (VFS_CALL | EXITING)) return;
if (rmp->mp_flags & TRACE_EXIT) {
+#if USE_TRACE
/* Tracer requested exit with specific exit value */
exit_proc(rmp, rmp->mp_exitstatus, FALSE /*dump_core*/);
+#endif /* USE_TRACE */
}
else if (rmp->mp_flags & PM_SIG_PENDING) {
/* We saved signal(s) for after finishing a VFS call. Deal with this.
#MINIX-specific vars
_MKVARS.yes+= \
MKWATCHDOG MKACPI MKAPIC MKMCONTEXT MKDEBUGREG MKSYSDEBUG \
- MKLIVEUPDATE MKSTATECTL
+ MKLIVEUPDATE MKSTATECTL MKTRACE
.for var in ${_MKVARS.yes}
${var}?= yes
.endfor
MKSYSDEBUG:= no
MKLIVEUPDATE:= no
MKSTATECTL:= no
+MKTRACE:= no
.endif
#
#
.for var in USE_HESIOD USE_INET6 USE_KERBEROS USE_LDAP USE_PAM USE_YP \
USE_WATCHDOG USE_ACPI USE_APIC USE_MCONTEXT USE_DEBUGREG USE_SYSDEBUG \
-USE_LIVEUPDATE USE_STATECTL
+USE_LIVEUPDATE USE_STATECTL USE_TRACE
.if (${${var:S/USE_/MK/}} == "no")
${var}:= no
.else