Path: utzoo!mnetor!uunet!lll-winken!lll-lcc!ames!ll-xn!husc6!bbn!socrates.bbn.com!dm From: dm@socrates.bbn.com (David Mankins) Newsgroups: comp.os.minix Subject: Re: Job control? Message-ID: <20350@bbn.COM> Date: 1 Feb 88 23:42:45 GMT References: <712@silver.bacs.indiana.edu> <2596@encore.UUCP> Sender: news@bbn.COM Reply-To: dm@socrates.bbn.com.UUCP (David Mankins) Organization: BBN Advanced Computers, Inc., Cambridge, MA Lines: 187 > Sorry, but job-control currently does not exist in MINIX, and it would > be non-trivial to add support. I plan to do this someday (I even have > hooks in my TTY driver for its eventual support), but I have no idea > exactly when. Off the top of my head, if you wanted to support job > control you would have to AT LEAST do the following: > > (1) Add support for stopping processes. This involves > adding a new process state (STOPPED) and modifying > the scheduler to know not to activate such processes. > > (2) Add support for the equivalent of the wait3() system call. > > (3) Modify the shell (or preferably write a C-shell clone) to > take advantage of the new support. A few years ago, a friend of mine and I implemented a facility very similar to job control in our V7 kernel (running on a very obscure bit of hardware), which had none of these disadvantages, and required a tiny change to the tty driver, and a simple window manager/job controller. The result was actually superior (in some ways) to Berkeley job control (no programs had to be changed to work with it, programs which don't do i/o don't EVER get blocked). The point of our job control was not to suspend a process, really, but to prevent the output of a program from splatting on the terminal while you were working with some other program. What we were REALLY doing was implementing a window manager system that didn't require PTYs. I/O was permitted by process-groups. I shall describe our window manager implementation, the simplification of turning it into job control is trivial. The things we did to UNIX are documented in: Franklin & Mankins, ``A simple window management facility for the UNIX timesharing system'', _USENIX Summer 1983 Toronto Conference Proceedings_. Unfortunately, the paper as reprinted in the proceedings is missing one of its early pages. I no longer have the paper in electronic form, or I would offer to send it to folks. I will send a Xerox copy to you, Mr. Paradis, since your terminal driver seems to be all the rage. I don't have MINIX (nor even a MINIXable PC) myself. We were doing a window manager for a terminal which was able to restrict output to rectangular regions, and which could save part of a region in a rectangular region of the screen (the BBN Bitgraph). A less-interesting version was possible for VT100s, with their scrolling-region commands, and I also once wrote a job-controller that used the same mechanism to work on dumb terminals. The basic idea was: there was a process to which the kernel would send a signal when the user typed a ^Z. This process would read the current tty modes and save them, then would interpret user commands to change to another window, would tell the terminal to switch to the new window's region, and would restore the new window's terminal modes. We added the following UNIX calls: set_tty_manager(tty_fd) Make the current process the terminal manager, if one has not already been assigned (this was an IOCTL, ``TIOCSMAN''). get_tty_manager(tty_fd) returns process-id Find out the terminal manager's process id (-1 if there's no window manager). Another IOCTL, ``TIOGMAN''. relinquish_tty_managerhood() Undo a set_tty_manager. IOCTL TIOCRMAN. setpgrp(proc_id, pgroup) getpgrp(proc_id) returns pgroup Set and get the process group for process proc_id. set_tty_pgroup(tty_fd, pgroup) get_tty_pgroup(tty_fd) returns pgroup set and get the process group for the terminal (implemented as two ioctl calls, TIOCSPGRP and TIOCGPGRP. get_blocked_process(tty_fd, &gbp_struct) Fill in the gbp_struct with a process id, the process's pgroup, and the reason the process is blocked (TTY_INPUT -- the process tried to do a read on the terminal; TTY_OUTPUT -- the process tried to do a write to the terminal; and TTY_IOCTL -- the process tried to do an IOCTL on the terminal. This routine returns -1 when the calling process is not the terminal's window manager, and it BLOCKS if there are no more blocked processes to handle. killpg(pgroup, signal) send the indicated signal to all processes in the specified process group. We also added three new mode bits, a new signalling character (the moral equivalent of BSD job control's ^Z), and an ioctl, TIOCSTUFF, to allow stuffing characters into a process's terminal input queue. In addition, our UNIX had a means of telling whether a read on the terminal would block. I don't know if MINIX has such a thing. The mode bits: TL_PGROUPIO: enables the whole package -- a process that is not in the TTY's process group will be block at an attempt to read, write, or ioctl. All tty-related ioctls will block (if the process's process-group isn't the same as the tty), even those that only inquire of the terminal modes without changing them, because a program would get confused if it reads the terminal modes associated with, for example a screen editor. TL_DEFINPUT: holds up the user's typing. When it is set, further typein by the user is not processed, but is held in a special queue until TL_DEFINPUT is turned off. At that time the contents of the queue are fed to the rest of the terminal driver as though they had just been typed. TL_DEFINPUT is necessary principally during the change from one window to another, when the terminal modes (or the region state in a window manager) may be incorrect. TL_BLREAD: is like TL_DEFINPUT but on the other side of the input queue. It blocks all terminal reads, even those performed by processes in the current process-group. This bit is not necessary for job control, but is useful if you're implementing a window manager. What this bit does is it allows OUTPUT to the terminal without permitting input. The scenario is this: you're interacting with rogue in window A the compilation in window B tries to write to the terminal, but blocks. the kernel returns to the window manager, which was blocked in a get_blocked_process() call. the window manager restores window B's terminal modes, switches the terminal to window B sets the tty to window B's process-group, the compiler's write takes place in window B While window B is active, what the user types on the keyboard wants to go unprocessed by the tty driver, because the user thinks s/he is typing at rogue. Okay, with TL_PGROUPIO enabled and a terminal manager (or job-controller) assigned via set_tty_manager(), the user wants a way of talking to the window manager: enter the job-control character. The user types ^Z, the kernel does: 1) sends a new signal, SIGATTN to the window manager 2) changes the process group of the terminal to that of the window manager 3) turns on TL_DEFINPUT mode. These three actions are combined to allow typeahead and responsiveness. The user may type ^Z and follow it immediately with a window manager command (e.g., switch to a window, make a new window, etc.). These commands should not be read by the process in the current window, nor should they be echoed in that window (TL_DEFINPUT prevents that). The effect of ^Z is in effect EVEN IN RAW MODE. We took this drastic step because we wanted a uniform interface. We didn't want to change every raw-mode program to know about this. To send a ^Z to a program, the user types two of them, and the window manager uses TIOCSTUFF to stuff the character into the input buffer of the current window. TIOCSTUFF and the is_there_input() call are used to allow other forms of typeahead. When the user types ^Z, there may be unprocessed characters in a window's input queue. The window manager uses is_there_input() to drain the tty input buffer (without blocking in a read) and will later use TIOCSTUFF to shove the characters into the current window's input queue when the user returns to this window. The paper gives a thorough discussion of the changes to the UNIX tty driver and also outlines the implementation of the window manager (down to the level of pseudo-code). Well, despite 8500 characters worth of exposition, it really was a simple change to the kernel (the window manager was a little hairy, the job controller was trivial). I THINK this method could be used to implement a multi-window environment for MINIX without the headaches of implementing full-blown virtual terminals, but I'm not sure. Only 365 days of America Held Hostage remain! dave mankins