The Unix Heritage Society mailing list
 help / color / mirror / Atom feed
* [TUHS] Another odd comment in V6
@ 2017-02-14 14:14 Noel Chiappa
  2017-02-14 14:35 ` Paul Ruizendaal
  2017-02-14 15:48 ` Random832
  0 siblings, 2 replies; 15+ messages in thread
From: Noel Chiappa @ 2017-02-14 14:14 UTC (permalink / raw)


    > From: Paul Ruizendaal

    > There's an odd comment in V6, in tty.c, just above ttread():
    > ...
    > That comment is strange, because it does not describe what the code
    > does.

I can't actually find anyplace where the PC is backed up (except on a
segmentation fault, when extending the stack)?

So I suspect that the comment is a tombstone; it refers to what the code did
at one point, but no longer does.

    > The comment isn't there in V5 or V7.

Which is consistent with it documenting a temporary state of affairs...


    > I wonder if there is a link to the famous Gabriel paper

I suspect so. Perhaps they tried backing up the PC (in the case where a system
call is interrupted by a software interrupt in the user's process), and
decided it was too much work to do it 'right' in all instances, and punted.

The whole question of how to handle software interrupts while a process is
waiting on some event, while in the kernel, is non-trivial, especially in
systems which use the now-universal approach of i) writing in a higher-level
stack oriented language, and ii) 'suspending' with a sub-routine call chain on
the kernel stack.

Unix (at least, in V6 - I'm not familiar with the others) just trashes the
whole call stack (via the qsav thing), and uses the intflg mechanism to notify
the user that a system call was aborted. But on systems with e.g. locks, it
can get pretty complicated (try Googling Multics crawl-out). Many PhD theses
have looked at these issues...


    > Actually, research Unix does save the complete state of a process and
    > could back up the PC. The reason that it doesn't work is in the syscall
    > API design, using registers to pass values etc. If all values were
    > passed on the stack it would work.

Sorry, I don't follow this?

The problem with 'backing up the PC' is that you 'sort of' have to restore the
arguments to the state they were in at the time the system call was first
made. This is actually easier if the arguments are in registers.

I said 'sort of' because the hard issue is that there are system calls (like
terminal I/O) where the system call is potentially already partially executed
(e.g.  a read asking for 10 characters from the user's console may have
already gotten 5, and stored them in the user's buffer), so you can't just
simply completely 'back out' the call (i.e. restore the arguments to what they
were, and expect the system call to execute 'correctly' if retried - in the
example, those 5 characters would be lost).

Instead, you have to modify the arguments so that the re-tried call takes up
where it left off - in the example above, tries to read 5 characters, starting
5 bytes into the buffer). The hard part is that the return value (of the
number of characters actually read) has to count the 5 already read! Without
the proper design of the system call interface, this can be hard - how does
the system distinguish between the _first_ attempt at a system call (in which
the 'already done' count is 0), and a _later_ attempt? If the user passes in
the 'already done' count, it's pretty straightforward - otherwise, not so
much!

Alan Bawden wrote a good paper about PCLSR'ing which explores some of these
issues.

	Noel


^ permalink raw reply	[flat|nested] 15+ messages in thread
* [TUHS] Another odd comment in V6
@ 2017-02-21 19:23 Norman Wilson
  2017-02-22  9:59 ` Tony Finch
  0 siblings, 1 reply; 15+ messages in thread
From: Norman Wilson @ 2017-02-21 19:23 UTC (permalink / raw)


Noel:

  Instead, you have to modify the arguments so that the re-tried call takes up
  where it left off - in the example above, tries to read 5 characters, starting
  5 bytes into the buffer). The hard part is that the return value (of the
  number of characters actually read) has to count the 5 already read! Without
  the proper design of the system call interface, this can be hard - how does
  the system distinguish between the _first_ attempt at a system call (in which
  the 'already done' count is 0), and a _later_ attempt? If the user passes in
  the 'already done' count, it's pretty straightforward - otherwise, not so
  much!

====

Sometime in the latter days of the Research system (somewhere
between when the 9/e and 10/e manuals were published), I had
an inspiration about that, and changed things as follows:

When a system call like read is interrupted by a signal:
-- If no characters have been copied into the user's
buffer yet, return -1 and set errno to EINTR (as would
always have been done in Heritage UNIX).
-- If some data has already been copied out, return the
number of characters copied.

So no data would be lost.  Programs that wanted to keep
reading into the same buffer (presumably until a certain
terminator character is encountered or the buffer is full
or EOF) would have to loop, but a program that didn't loop
in that case was broken anyway: it probably wouldn't work
right were its input coming from a pipe or a network connection.

I don't remember any programs breaking when I made that change,
but since it's approaching 30 years since I did it, I don't
know whether I can trust my memory.  Others on this list may
have clearer memories.

All this was a reaction to the messy (both in semantics and
in implementation) compromise that had come from BSD, to
have separate `restart the system call' and `interrupt the
system call' states.  I could see why they did it, but was
never satisfied with the result.  If only I'd had my inspiration
some years earlier, when there was a chance of it getting out
into the real world and influencing POSIX and so on.  Oh, well.

Norman Wilson
Toronto ON


^ permalink raw reply	[flat|nested] 15+ messages in thread
* [TUHS] Another odd comment in V6
@ 2017-02-14 16:17 Noel Chiappa
  0 siblings, 0 replies; 15+ messages in thread
From: Noel Chiappa @ 2017-02-14 16:17 UTC (permalink / raw)


    > From: Random832

    > You could return the address of the last character read, and let the
    > user code do the math.

Yes, but that's still 'design the system call to work with interrupted and
re-started system calls'.

    > If the terminal is in raw/cbreak mode, the user code must handle a
    > "partial" read anyway, so returning five bytes is fine.

As in, if a software interrupt happens after 5 characters are read in, just
terminate the read() call and have it return 5? Yeah, I suppose that would
work.

    > If it's in canonical mode, the system call does not copy characters into
    > the user buffer until they have pressed enter.

I didn't remember that; that TTY code makes my head hurt! I've had to read it
(to add 8-bit input and output), but I can't remember all the complicated
details unless I'm looking at it!


    > Maybe there's some other case other than reading from a terminal that it
    > makes sense for, but I couldn't think of any while writing this post.

As the Bawden paper points out, probably a better example is _output_ to a
slow device, such as a console. If the thing has already printed 5 characters,
you can't ask for them back! :-)

So one can neither i) roll the system call back to make it look like it hasn't
started yet (as one could do, with input, by stuffing the characters back into
the input buffer with kernel ungetc()), or ii) wait for it to complete (since
that will delay delivery of the software interrupt). One can only interrupt
the call (and show that it didn't complete, i.e. an error), or have
re-startability (i.e. argument modification).

	Noel


^ permalink raw reply	[flat|nested] 15+ messages in thread
* [TUHS] Another odd comment in V6
@ 2017-02-14 15:40 Noel Chiappa
  0 siblings, 0 replies; 15+ messages in thread
From: Noel Chiappa @ 2017-02-14 15:40 UTC (permalink / raw)


    > From: Lars Brinkhoff

    > Nick Downing <downing.nick at gmail.com> writes:

    >> By contrast the MIT guy probably was working with a much smaller/more
    >> economical system that didn't maintain a kernel stack per process.

I'm not sure I'd call ITS 'smaller'... :-)

    > PCLSRing is a feature of MIT' ITS operating system, and it does have a
    > separate stack for the kernel.

I wasn't sure if there was a separate kernel stack for each process; I checked
the ITS source, and there is indeed a separate stack per process. There are
also three other stacks in the kernel that are used from time to time (look
for 'MOVE P,' for places where the SP is loaded).

Oddly enough, it doesn't seem to ever _save_ the SP - there are no 'MOVEM P,'
instructions that I could find!

	Noel


^ permalink raw reply	[flat|nested] 15+ messages in thread
* [TUHS] Another odd comment in V6
@ 2017-02-14  8:46 Paul Ruizendaal
  2017-02-14 11:27 ` Nick Downing
  0 siblings, 1 reply; 15+ messages in thread
From: Paul Ruizendaal @ 2017-02-14  8:46 UTC (permalink / raw)



There's an odd comment in V6, in tty.c, just above ttread():

/*
 * Called from device's read routine after it has
 * calculated the tty-structure given as argument.
 * The pc is backed up for the duration of this call.
 * In case of a caught interrupt, an RTI will re-execute.
 */

That comment is strange, because it does not describe what the code does. The comment isn't there in V5 or V7.

I wonder if there is a link to the famous Gabriel paper about "worse is better" (http://dreamsongs.com/RiseOfWorseIsBetter.html). In arguing its points, the paper includes this story:

---
Two famous people, one from MIT and another from Berkeley (but working on Unix) once met to discuss operating system issues. The person from MIT was knowledgeable about ITS (the MIT AI Lab operating system) and had been reading the Unix sources. He was interested in how Unix solved the PC loser-ing problem. The PC loser-ing problem occurs when a user program invokes a system routine to perform a lengthy operation that might have significant state, such as IO buffers. If an interrupt occurs during the operation, the state of the user program must be saved. Because the invocation of the system routine is usually a single instruction, the PC of the user program does not adequately capture the state of the process. The system routine must either back out or press forward. The right thing is to back out and restore the user program PC to the instruction that invoked the system routine so that resumption of the user program after the interrupt, for example, re-enters the system routine. It is called PC loser-ing because the PC is being coerced into loser mode, where loser is the affectionate name for user at MIT.

The MIT guy did not see any code that handled this case and asked the New Jersey guy how the problem was handled. The New Jersey guy said that the Unix folks were aware of the problem, but the solution was for the system routine to always finish, but sometimes an error code would be returned that signaled that the system routine had failed to complete its action. A correct user program, then, had to check the error code to determine whether to simply try the system routine again. The MIT guy did not like this solution because it was not the right thing.

The New Jersey guy said that the Unix solution was right because the design philosophy of Unix was simplicity and that the right thing was too complex. Besides, programmers could easily insert this extra test and loop. The MIT guy pointed out that the implementation was simple but the interface to the functionality was complex. The New Jersey guy said that the right tradeoff has been selected in Unix -- namely, implementation simplicity was more important than interface simplicity.
---

Actually, research Unix does save the complete state of a process and could back up the PC. The reason that it doesn't work is in the syscall API design, using registers to pass values etc. If all values were passed on the stack it would work. As to whether it is the right thing to be stuck in a read() call waiting for terminal input after a signal was received...

I always thought that this story was entirely fictional, but now I wonder. The Unix guru referred to could be Ken Thompson (note how he is first referred to as "from Berkeley but working on Unix" and then as "the New Jersey guy").

Who can tell me more about this? Any of the old hands?

Paul



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-02-22  9:59 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-14 14:14 [TUHS] Another odd comment in V6 Noel Chiappa
2017-02-14 14:35 ` Paul Ruizendaal
2017-02-14 15:48 ` Random832
2017-02-14 16:06   ` Dan Cross
  -- strict thread matches above, loose matches on Subject: below --
2017-02-21 19:23 Norman Wilson
2017-02-22  9:59 ` Tony Finch
2017-02-14 16:17 Noel Chiappa
2017-02-14 15:40 Noel Chiappa
2017-02-14  8:46 Paul Ruizendaal
2017-02-14 11:27 ` Nick Downing
2017-02-14 12:27   ` Paul Ruizendaal
2017-02-14 12:46     ` Nick Downing
2017-02-14 14:03   ` Lars Brinkhoff
2017-02-14 14:18     ` Nick Downing
2017-02-14 15:50       ` Random832

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).