rmtodd@uokmax.UUCP (Richard Michael Todd) (06/05/87)
As most of you have probably noticed, the 'commands' list in the display produced by pressing F1 is often inaccurate. From what I've heard on the net, the display gets even more confused if you have the memory compaction mods posted by ganesh@utah-cs.UUCP. Below I detail the problems with the dump code and their solutions. (I don't have the mem. compaction mods installed, so I don't guarantee that the fixes I present here will solve that part of the problem with F1. It looks as if they should.) In kernel/dmp.c, the names of the executing user processes are kept track of through an array called aout, indexed by process number. This array contains pointers to the starts of the command strings for the processes. Zero indicates an inactive process slot. Problem 1: Whenever the system task (kernel/system.c) does an exec or exit for a process, it does a subroutine call to notify the dump routine, which sets the appropriate entry in aout[] to the command name (for exec) or 0 (for exit). Alas, system does not inform the dump routines when a process forks. Thus when a process forks (and the child does not immediately do an exec), the dump routine still has aout[] for the child set to zero and thus will not display what command the child is executing. The fix is simple: a new routine in dmp.c (named set_n_forked) to handle forks, and changing the system task fork routine to notify dmp.c. The context diffs below include this fix. Problem 2: The aout[] array stores the physical addresses of the command strings, not the virtual addresses. This means that if a process is moved from one section of memory to another, the dump routine will still look for the command string in the original location. No wonder it gets confused by the memory compaction. The fix is simple: Change dmp.c to store virtual addresses in aout[] and do the umap() call to derive physical addresses at dump time. This doesn't appear to add a significant amount of overhead to the dump. This fix is also included in the c-diffs below. Problem 3: The main loop in the p_dmp routine includes code to automatically display "/bin/sh" for process 3, even though that may not be what proc. 3 is executing. Seeing "/bin/sh" is a bit disconcerting when you know darn well it's executing /usr/bin/login. Fix: delete this code. However,when you do this, you soon discover: Problem 4. Processes created by INIT have null strings for argv[0]. This problem was concealed by problem 3 (though it wouldn't have stayed concealed long when someone added another tty line and INIT had an immediate descendant that wasn't process 3). INIT uses a special variant of exec, execn, that passes no arguments or environment pointers. This allows it to get away with not allocating a 1K buffer on the stack like all the other versions of exec have to. If you don't mind having INIT take up an extra 1K, apply the patch below to cause INIT to use a different exec variant. With these patches installed, the F1 display seems to be fairly accurate. It will display a null string in the command field only when the process is actually in the middle of the exec system call. Before, it'll show the name it inherited from its parent; after, it'll show its new name. A slight difference between UNIX and MINIX is apparent: login shells (exec'd by /usr/bin/login) display only "-" in their command field in MINIX, whereas under UNIX, the argv[0] string is "-" followed by the shell's name (i.e. "-csh" appears for a login C-shell). If you think this is worth fixing in MINIX, change login.c. Here are the context diffs to kernel/dmp.c, kernel/system.c, and tools/init.c. Enjoy. *** kernel/dmp.c.old Fri May 29 07:54:15 1987 --- kernel/dmp.c.new Thu Jun 4 21:37:47 1987 *************** *** 11,17 #include "proc.h" #define NSIZE 20 ! phys_bytes aout[NR_PROCS]; /* pointers to the program names */ char nbuff[NSIZE+1]; int vargv; --- 11,17 ----- #include "proc.h" #define NSIZE 20 ! vir_bytes aout[NR_PROCS]; /* pointers to the program names */ char nbuff[NSIZE+1]; int vargv; *************** *** 55,62 /* Fetch the command string from the user process. */ index = rp - proc - NR_TASKS; if (index > LOW_USER && aout[index] != 0) { ! phys_copy(aout[index], dst, (long) NSIZE); ! aout[NSIZE] = 0; for (np = &nbuff[0]; np < &nbuff[NSIZE]; np++) if (*np <= ' ' || *np >= 0177) *np = 0; if (index == LOW_USER + 1) --- 55,66 ----- /* Fetch the command string from the user process. */ index = rp - proc - NR_TASKS; if (index > LOW_USER && aout[index] != 0) { ! /* look up physical address of process name data */ ! ltmp = umap(proc_addr(index),D,aout[index],NSIZE); ! if (ltmp == 0) continue; ! /* and copy the name string */ ! phys_copy(ltmp, dst, (long) NSIZE); ! nbuff[NSIZE] = 0; for (np = &nbuff[0]; np < &nbuff[NSIZE]; np++) if (*np <= ' ' || *np >= 0177) *np = 0; printf("%s", nbuff); *************** *** 59,68 aout[NSIZE] = 0; for (np = &nbuff[0]; np < &nbuff[NSIZE]; np++) if (*np <= ' ' || *np >= 0177) *np = 0; ! if (index == LOW_USER + 1) ! printf("/bin/sh"); ! else ! printf("%s", nbuff); } printf("\n"); } --- 63,69 ----- nbuff[NSIZE] = 0; for (np = &nbuff[0]; np < &nbuff[NSIZE]; np++) if (*np <= ' ' || *np >= 0177) *np = 0; ! printf("%s", nbuff); } printf("\n"); } *************** *** 122,128 phys_bytes src, dst, count; if (ptr == (char *) 0) { ! aout[proc_nr] = (phys_bytes) 0; return; } --- 123,129 ----- phys_bytes src, dst, count; if (ptr == (char *) 0) { ! aout[proc_nr] = (vir_bytes) 0; return; } *************** *** 131,135 dst = umap(proc_addr(SYSTASK), D, &vargv, 2); phys_copy(src, dst, 2L); ! aout[proc_nr] = umap(proc_addr(proc_nr), D, vargv, NSIZE); } --- 132,144 ----- dst = umap(proc_addr(SYSTASK), D, &vargv, 2); phys_copy(src, dst, 2L); ! aout[proc_nr] = vargv; ! } ! /* ! ** When a fork is done, dmp needs to know about it so that the entry in the ! ** aout table can be copied for the child process. ! ** Function added 5-29-86 by rmtodd@uokmax ! */ ! set_n_forked(parent,child) int parent,child; { ! aout[child] = aout[parent]; } *** kernel/system.c.old Fri May 29 07:54:31 1987 --- kernel/system.c.new Fri May 29 08:19:50 1987 *************** *** 139,144 rpc->sys_time = 0; rpc->child_utime = 0; rpc->child_stime = 0; return(OK); } --- 139,145 ----- rpc->sys_time = 0; rpc->child_utime = 0; rpc->child_stime = 0; + set_n_forked(k1,k2); /* notify F1 process table dump routine about fork */ return(OK); } *** tools/init.c.old Sun Feb 6 00:34:36 2106 --- tools/init.c.new Sun Feb 6 00:48:28 2106 *************** *** 5,10 */ #include "../h/signal.h" #define PIDSLOTS 10 #define STACKSIZE 256 --- 5,11 ----- */ #include "../h/signal.h" + #include "../h/const.h" #define PIDSLOTS 10 #define STACKSIZE (256+MAX_ISTACK_BYTES) *************** *** 7,13 #include "../h/signal.h" #define PIDSLOTS 10 ! #define STACKSIZE 256 #define DIGIT 8 char name[] = {"/dev/tty?"}; /* terminal names */ --- 8,15 ----- #include "../h/const.h" #define PIDSLOTS 10 ! #define STACKSIZE (256+MAX_ISTACK_BYTES) ! /* ensure there's always enough space to exec */ #define DIGIT 8 char name[] = {"/dev/tty?"}; /* terminal names */ *************** *** 33,39 if (open("/etc/rc", 0) < 0) exit(-1); open("/dev/tty0", 1); /* std output */ open("/dev/tty0", 1); /* std error */ ! execn("/bin/sh"); exit(-2); /* impossible */ } --- 35,41 ----- if (open("/etc/rc", 0) < 0) exit(-1); open("/dev/tty0", 1); /* std output */ open("/dev/tty0", 1); /* std error */ ! execl("/bin/sh","sh",0); exit(-2); /* impossible */ } *************** *** 90,99 if (open(name, 0) != 0) exit(-3); /* standard input */ if (open(name, 1) != 1) exit(-3); /* standard output */ if (open(name, 1) != 2) exit(-3); /* standard error */ ! execn("/usr/bin/login"); ! execn("/bin/login"); ! execn("/bin/sh"); /* last resort, if mount of /usr failed */ ! execn("/usr/bin/sh"); /* last resort, if mount of /usr failed */ return; /* impossible */ } } --- 92,101 ----- if (open(name, 0) != 0) exit(-3); /* standard input */ if (open(name, 1) != 1) exit(-3); /* standard output */ if (open(name, 1) != 2) exit(-3); /* standard error */ ! execl("/usr/bin/login","login",0); ! execl("/bin/login","login",0); ! execl("/bin/sh","sh",0); /* last resort, if mount of /usr failed */ ! execl("/usr/bin/sh","sh",0); /* last resort, if mount of /usr failed */ return; /* impossible */ } }