Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!csd4.milw.wisc.edu!leah!rpi!rpi.edu!deven From: deven@pawl.rpi.edu (Deven Corzine) Newsgroups: comp.sys.amiga.tech Subject: Re: Unix V7 functionality under (or along with) AmigaDOS? (*LONG*) Message-ID: Date: 15 Mar 89 20:19:20 GMT References: <0776.AA0776@julie> <6275@cbmvax.UUCP> Sender: usenet@rpi.edu Reply-To: shadow@pawl.rpi.edu (Deven Thomas Corzine) Organization: RPI Public Access Workstation Lab, Troy NY Lines: 258 In-reply-to: jesup@cbmvax.UUCP's message of 15 Mar 89 03:28:04 GMT In article <6275@cbmvax.UUCP> jesup@cbmvax.UUCP (Randell Jesup) writes: >In article <0776.AA0776@julie> mcr@julie.UUCP (Michael Richardson) writes: >>>> Shells are shells, period. The Workbench is a visual shell. >>>>Exit() itself does almost nothing, except return control to the "shell" >>>>as if the program had exited. >> But this also implies (correctly) that CLIs are NOT shells. They are >>special. That is the very first thing that strikes people about Unix, >>and where most if not all of its power comes from. Programs are programs. > No, sorry. The CLI is a shell, just like Workbench, or AmigaShell. >It so happens that the division isn't totally clean, and one should consider >the CLI structure as part of the program environment, since programs often >access it directly. Quite so. > 99% of unix users (not hackers) don't care much whether a Shell is >somehow special or just another program. The only people who care are >hackers/wizards and shell writers. Nor need they. The CLI tends to force itself on the programmer, in contrast. >>>Hmm. This seems the only reasonable way to go; replace CreateProc(), >>>and use AddTask(). I take it the extra segments in the SegArray >>>(pr_SegList) are such as that cleanup code for CreateProc() which are >>>not to be unloaded. May I safely assume that if I replace >>>CreateProc() with my own function which sets up a structure starting >> What stuff do you intend on adding? > No. I don't think we even want to hint whats in that SegArray, >since it's pretty useless, and I'd like to see it disappear. Ignore it. I'd be happy to. >>>output of the executed program, or set them to zero and define the >>>standard input, output and error channels in my own structure? (I >>>want stderr as a passed file descriptor, along with stdin and >>>stdout...) I want to break dependency from the CLI, yet still be able >> ^^^^^^^^^^^^^^^^^^^^^^^ >>>to run programs which depend on the CLI themselves. (possibly by >>>using or replacing the AmigaDOS RUN command.) >> I disagree. CA= won't document a lot of things because they say >> "it will break in 1.4" >> but they won't change things because >> "too many things would break" > "it will break in 1.4" means we want to break people who use >things they shouldn't. If they don't heed our warning, we may be more >ruthless than in the past about breaking people. At some point we >must move forward, or we're stuck forever with a stagnant, incomplete, >outdated system. Sometimes there is no choice but to break people >doing illegal things, and occasionally even legal things. Breaking >people doing legal things is a last resort, and will be trumpeted if >possible so people can revise. Often we will try to say "it'll work >for this new release, but is outdated and will not be supported after >that." This gives people 1 major release to revise their code. Seems a sensible enough system to me. >> That way, you can encourage people to write programs that conform >>to your standard (generic programs will just need a relinking with >>a new startup) instead of letting them run all their old >>code unmodified. If they need the old stuff, "C=+ESC" gets most >>people a CLI... > This is all amusing, but we are trying to reduce the number of >distinct environments in the system, not increase them. The current >WB/CLI(or shell) split makes the system tough to work with, especially for >novice users. Well said. Exactly my point. >> Wish read(), write(), were better documented. I don't really understand >>what they do... (internally) > Internals are supposed to be hidden. There is that. >>>I want to write a shell which will be more cleanly implemented than >>>the CLI (i.e. no BCPL) and which will start programs with argv AND >>>envp arrays, and have Unix-type calls available. >> Get out my head! That was my idea! :-) >> Actually that would be a good initial difference for this shell. >>Set a flag (pr_CIN and pr_COS==NULL? hmm. ) > No. Descriptive response. :-) >> How to pass argv and envp? This is a message passing operating >>system right? Well, send the task a message... How do you tell when >>the task is finished? Well, exit() returns this message (with an error >>code) and then does a Wait(). The exec.library (woops that name >>is taken. The Execute.library then--- I guess I mean Execute.device see >>below) then RemTasks it, and deallocates it (if it isn't on the resident >>list) and makes the error code available to the task. > Sounds like a WorkBench process to me. Indeed it does. >> What else? How about a standard tc_ExeceptionCode? >> Make SIGBREAKF_CTRL_C, and ^E exceptions. ^C will >>cause an "abort()" routine to be run. (signal() or sigvec()'able of course) >>The standard abort() should be able to run some number of clean up >>functions, and then it should call "exit()" > Can't be done unless you can GUARANTEE the PC will not be in a ROM >routine, or with a Forbid() or LockIBase or ... held. Exceptions aren't as >useful as you think. I haven't looked into exceptions too closely, but they seem to be of some value, at least. How much, I'm not quite sure. >> Also, when ^E is received, the task does a "Wait(SIGBREAKF_CTRL_F)" >>and PRESTO, Job control!!! (Or course, ^E is signal()/sigvec() settable too.) >>When the shell wishes the job to continue, just send a ^F signal. (Or >>any other agreed upon signal) >> >> This assumes something about the shell though: that it isn't part of the >>same task as the programs it runs. This is fine, as this CLI "subroutine" >>stuff bugs me a lot. > One can get job control (at least the unix ^z part of it) >without exceptions. The shell simply notices ^f and stops waiting for >the current sub-process to complete. Does require running all >programs in other processes. This has been done by at least one >person. But that isn't really job control. It's more like ^Z followed by a bg. It doesn't stop the job, only waiting for it. How about having a function to suspend a task? It could freeze the exec task, optionally causing an exception so the process can clean up some... >> It ISN'T fork()/exec(), but it does make a much more orthogonal >>system, shells send messages to "execute" servers, much the same >>way that comm programs send messages to "serial" devices... > In fact, exactly how I do it. Meaning? >> Have you talked to Colin (Plumb?) (microsoft!w-colinp) >> His extent based file system looks quite nice... > Not for HD's. Also might be kinda slow in some cases. Ayup. >> I suggest that you start by writting a file system handler that >>understands the AmigaDOS file system in C. Then rewrite it >>(with a different file system type) that is completely C. (Get >>rid of BSTR, etc... Incompatible, but that's ok.) > The BSTR stuff there's mildly annoying, but really isn't too big >a pain. Just use C pointers internally, and convert on packet reception/ >reply. Works well, and is ever so much more compatible. Indeed. I might not even bother to deal with packets directly (we'll see) but just call dos.library routines directly (from the system task) and have the system task handle BPTR/BSTR conversions... >>>Fork() would start with a FindTask(0L) call, allocate space for a new >>>Task structure, copy the data over, and similarly duplicate the text >>>and data segments, modifying the appropriate fields to point to the >> ^^^^^^^^^^^ >>>copies, and link in the new task to Exec with either AddTask() >>>(obviously preferable) or manually if necessary. >> As has been pointed out, this is VERY difficult without an MMU. > No, just expensive if you _don't_ do an exec soon thereafter. >Conceptually, it's easy. Indeed. >>>First, is whether this fork() routine would need to disable >>>multitasking (interrupts seem fine) at all, such as when copying the >> I don't think so. >>>Task structure of the current process. Or, is it perfectly safe and >>>consistent (no race conditions) to let multitasking continue >>>unhindered while it initializes the new Task structure? (Clearly, it >> ^^^^^^^^^^^ >> Nobody but you knows about the task structure until you AddTask. >>And at that point, you had better be finished fiddling with it, because >>the process is ready to run. > Well, you _could_ do a Forbid before the AddTask, but I wouldn't >advise it if you don't need to. That's what I had been wondering if I needed to do, but it seems unnecessary... I suppose a sorta neat kludge you could use would be to carefully set up the stack such that you call Forbid(), clean up the memory and resources you're using, including the memory the code being executed is in (hence the Forbid()) and set up the stack such that you call Forbid() and the return from it would actually call Exit()... Sorta messy and surely dangerous, but vaguely neat at the same time. :-) >>>Second, how should the fork() call make execution begin at the return >>>point of said fork() call? (Perhaps this question will answer itself >>>when I look up AddTask().) >> Look up the return address of the fork(). Put the return value under >>it, and give the address of a routine that will just do an "RTS". >>This stack is, of course a freshly copied stack, having all >>the frame pointers, changed. Even if you leave all the data and >>code shared, you must at least duplicate the stack. > The stack bit won't work without MMU, at the very least. You have >to make copies of the stack and data area, and then copy to the original >area on a task switch whichever one is about to run (don't copy if the right >tasks data is there - remember, other tasks cause switches as well). Yeah. Probably use and Exec-type list and have the switched-in data set at the head of the list... and only do copying (swapping?) operations if it's not the right one...) >> The fexec() library function would lookup the highest FileHandle assigned >>to ask (kept in an Exec list of course to eliminate that 20 files open bit) >>and duplicate each one. This list would be part of the standard stuff > You can't dup() a filehandle. I don't know what he had in mind, but I would be duping file _descriptors_, not file handles. The descriptors would point to handles, in a list. Such descriptors could be safely duplicated. As for implementation, I think the way to go is to number file descriptors sequentially starting at 0, as in Unix, with 0 for stdin, 1 for stdout and 2 for stderr. However, the file descriptors would NOT be kept in a static array, but instead in an Exec list, which would be sorted from most-recently-used to least-recently-used -- when it needs to use a file descriptor (for a read() or whatever) it would search the descriptor list starting at the head of the list until it finds the descriptor or hits the end of the list. When it finds the descriptor, it would Remove() the node from the list and AddHead() it to keep the most-used descriptors nearest to the head of the list. That should be the most efficient while keeping everything dynamic and flexible. Finding a free file descriptor for and open() or dup() call would be quite inefficient, however. Unless, perhaps, a list of file descriptor "holes" were kept... Only keeping track of unused descriptors up until the highest-numbered file descriptor (which would also be recorded) since all after that one are automatically free... Hey, sounds good to me. Any comments/suggestions? You see, I want to keep everything as dynamic as possible; that is a very good point of Exec which I want to remain consistent with. Plus, dynamic allocation is almost always better in the long run... Deven -- ------- shadow@pawl.rpi.edu ------- Deven Thomas Corzine --------------------- Cogito shadow@acm.rpi.edu 2346 15th Street Pi-Rho America ergo userfxb6@rpitsmts.bitnet Troy, NY 12180-2306 (518) 272-5847 sum... In the immortal words of Socrates: "I drank what?" ...I think.