david@torsqnt.UUCP (David Haynes) (01/20/89)
What should be the result of running the following program? #include <setjmp.h> main() { register int j; jmp_buf env; j = 1; if(setjmp(env) == 1) { printf("j = %d\n", j); exit(1); } printf("j = %d\n", j); j += 3; longjmp(env, 1); } Sequent, Ultrix and Vax C give results of j = 1, j = 4. Gcc gives a result of j = 1, j = 1. What does the ANSI standard say about this? -david-
henry@utzoo.uucp (Henry Spencer) (01/21/89)
In article <25@torsqnt.UUCP> david@torsqnt.UUCP (David Haynes) writes: >What does the ANSI standard say about this? If function foo() calls setjmp(), and then it or a function called by it calls longjmp(), the values of any local variables which are not volatile and which have changed since the setjmp() are *indeterminate*. Your program could give j = 1, j = 666 if the implementor felt like it. Note, this behavior is *not* limited to variables declared "register". In practice, it is highly likely that any self-respecting implementation will restrict this nasty behavior to variables declared "register", or even eliminate it entirely. (Some of us thought that it was both feasible and important to require one of these two approaches, in fact, but X3J11 did not agree.) It is also highly likely that the value will not in fact be random, but will be either the value as of setjmp() time or the value as of longjmp() time. However, strictly conforming programs cannot rely on any of this. -- Allegedly heard aboard Mir: "A | Henry Spencer at U of Toronto Zoology toast to comrade Van Allen!!" | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
guy@auspex.UUCP (Guy Harris) (01/21/89)
>What does the ANSI standard say about this?
The May 13, 1988 draft says that since "j" is of automatic storage
duration, isn't declared "volatile", and was changed between the calls
to "setjmp" and "longjmp", its value will be indeterminate after the
call to "longjmp". Either behavior is conformant, as would be setting
"j" to 666....
chris@mimsy.UUCP (Chris Torek) (01/21/89)
In article <25@torsqnt.UUCP> david@torsqnt.UUCP (David Haynes) writes: >What should be the result of running the following program? [example of register variables and longjmp deleted] >Sequent, Ultrix and Vax C give results of j = 1, j = 4. >Gcc gives a result of j = 1, j = 1. >What does the ANSI standard say about this? The ANSI standard says that register variables, like all other automatic variables, must be declared `volatile' for you to be able to assume the output will be `j = 1, j = 4'. Of course, since there is no `volatile' qualifier in most existing C compilers, in practise this means that you must not declare variables as register in order to count on them (so that `#define volatile /*empty*/' will work). (I guess you were not reading when I posted this the last two or three times last month. . . .) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
moore%cdr.utah.edu@wasatch.UUCP (Tim Moore) (01/21/89)
In article <25@torsqnt.UUCP> david@torsqnt.UUCP (David Haynes) writes: #include <setjmp.h> main() { register int j; jmp_buf env; j = 1; if(setjmp(env) == 1) { printf("j = %d\n", j); exit(1); } printf("j = %d\n", j); j += 3; longjmp(env, 1); } Sequent, Ultrix and Vax C give results of j = 1, j = 4. Gcc gives a result of j = 1, j = 1. What does the ANSI standard say about this? -david- Gcc follows the ANSI standard which, when strictly interpreted, says that "the only automatic variables guaranteed to remain valid are those declared volatile" (quoted from the gcc manual). Traditional compilers put local variables in the stack in functions that call setjump. If you look at the assembly code output of Sequent, Ultrix, Vax C, and gcc with the "-traditional" flag you will see that j isn't really being stored in a register. -Tim Moore 4560 M.E.B. internet:moore@cs.utah.edu University of Utah ABUSENET:{ut-sally,hplabs}!utah-cs!moore Salt Lake City, UT 84112
scs@adam.pika.mit.edu (Steve Summit) (01/21/89)
Here are my rules for using setjmp/longjmp and remembering which variables are preserved: 1. Never use setjmp and longjmp. 2. If rule 1 must be broken, do not depend on the values of any variables after setjmp has "returned" due to a call to longjmp. These rules are admittedly conservative, but as long as I follow them I never have problems with setjmp or longjmp or which variables are preserved. I believe I have broken rule 1 twice; I have had problems with variable preservation approximately 50% of those times. Therefore I conclude that rule 1 is a good rule. Steve Summit scs@adam.pika.mit.edu Ten people will now sanctimoniously flame me, saying that the problem is not with setjmp/longjmp but with my (lack of) understanding of them. Save it. I could remember the details and rationale of the variable preservation rules if I wanted to. Since I consider longjmp an abysmal idea in the first place, and I have been able to get along without it virtually all of the time, I don't choose to keep my knowledge on it current. It is also unnecessary to point out to me all of the cases where longjmp has been found indispensable; I'm familiar with the arguments.
cquenel@polyslo.CalPoly.EDU (96 more school days) (01/22/89)
Since we're on the subject again, I have a question coming from the IMPLEMENTATION department. Assuming that volatile variables are written out to memory before any procedure call. (Even if this is not sufficient, assume that volatile variables have been dealt with.) Should it ever be necessary/desirable to restore any registers on a long-jump BESIDES the frame-pointer and/or stack-pointer ? That is to say: If I can get all my volatile variables out of my registers, then I don't need to restore ANY of them ? (According to ANSI) I mention this because I remember implementing it once, and at the time, I seem to recall the "common", vax-ish, old-fashioned implementation restored a gob of regular registers as well. --chris What you don't know can hurt you, only you won't know it. ------------------------------------------------------------------------------- | Nothing the God of Bio-Mechanics wouldn't let you in heaven for ? | ------------------------------------------------------------------------------- | Chris Quenelle | Smart Mailers -> cquenel@polyslo.CalPoly.EDU | | Cal Poly State Univ. |-------------------------------------------------| | San Luis Obispo, CA 93407 | On a clear disk you can seek forever. | -------------------------------------------------------------------------------
ark@alice.UUCP (Andrew Koenig) (01/23/89)
In article <7222@polyslo.CalPoly.EDU>, cquenel@polyslo.CalPoly.EDU (96 more school days) writes: > Should it ever be necessary/desirable to restore any registers > on a long-jump BESIDES the frame-pointer and/or stack-pointer ? No, unfortunately. Once upon a time, the VAX setjmp worked by saving all the registers in the jmp_buf and longjmp restored it. That means that if you say: register foo; jmp_buf jb; foo = 3; if (setjmp(jb)) { /* exception stuff */ } foo = 7; func(); and func calls longjmp(jb), foo will be 3 and not 7 when the `exception stuff' is executed. John Reiser figured out a way around it -- a nifty version of longjmp that unwound the stack, restoring the correct registers at each iteration -- and that went into at least some VAX C implementations. However, when it came to the ANSI committee, they decided it would be too hard to mandate this kind of implementation. So they took the least restrictive route possible -- longjmp doesn't have to work at all unless you beg it. -- --Andrew Koenig ark@europa.att.com
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/23/89)
In article <8812@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >Once upon a time, the VAX setjmp worked by ... I seem to recall at least three distinct implementations of setjmp/logjmp in PDP-11 UNIX and something like four implementations in various versions of VAX UNIX. Reiser's was pretty good, but it would have been foolish to rely on it for any sort of portable code, since other implementations didn't necessarily work the same way. >However, when it came to the ANSI committee, they decided it >would be too hard to mandate this kind of implementation. >So they took the least restrictive route possible -- longjmp >doesn't have to work at all unless you beg it. longjmp() has to do the essential "goto" action and return the right value for the setjmp() invocation (which is constrained to be in one of the contexts for which this can reasonably be guaranteed). After a longjmp, all accessible objects are required to have the values they had when longjmp() (NOT setjmp()) was invoked, except that cached autos inside the function containing the setjmp are allowed to be out of sync. That's to keep aggressive optimizers from having to treat setjmp() invocations in a "magic" way. Really, setjmp/longjmp is just a groady "goto" and should be avoided for the same reasons as the ordinary "goto". In fact it is even more violent than an ordinary "goto", which is why it has to be more loosely constrained. I don't think I've even seen a case in which setjmp/longjmp was the best way to design code, let alone essential. The nearest to a valid use I know of is to allow a SIGINT to abort processing and fly back to a main command loop (e.g. in the "ed" editor), but even there the longjmp can cause stdio data structures to be left in an inconsistent state. Asynchronous concurrent processes really need to be designed around better tools than setjmp/longjmp.
henry@utzoo.uucp (Henry Spencer) (01/23/89)
In article <7222@polyslo.CalPoly.EDU> cquenel@polyslo.CalPoly.EDU (96 more school days) writes: >Assuming that volatile variables are written out to memory >before any procedure call. (Even if this is not sufficient, >assume that volatile variables have been dealt with.) > >Should it ever be necessary/desirable to restore any registers >on a long-jump BESIDES the frame-pointer and/or stack-pointer ? Assuming that any other registers needed by the compiler -- not all implementations get by with just an FP and SP -- have been dealt with, ANSI C conformance doesn't require anything more. However, an implementation that simply trashes the registers (rather, allows them to be trash) or, still worse, does likewise for automatic variables not declared "register" (i.e. by promoting them to registers and then not preserving them), is probably not going to sell well when word gets around. The old de-facto rule was that register variables had either current values or values as of the setjmp call, and that other automatics weren't touched at all. Minimal ANSI conformance will thus break essentially every longjmp-using program in existence. Don't expect the customers to be too delighted about that. Your best quick solution is to save all registers at setjmp time and then restore them at longjmp time, and avoid promoting automatic variables. The preferred solution, more work, is to notice the use of setjmp (there are enough restrictions on it that you can do that) and save/restore everything around all function calls within a function that uses setjmp. -- Allegedly heard aboard Mir: "A | Henry Spencer at U of Toronto Zoology toast to comrade Van Allen!!" | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
jas@ernie.Berkeley.EDU (Jim Shankland) (01/23/89)
In article <9480@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >Really, setjmp/longjmp is just a groady "goto" and should be >avoided for the same reasons as the ordinary "goto". In fact >it is even more violent than an ordinary "goto", which is why >it has to be more loosely constrained. I don't think I've >even seen a case in which setjmp/longjmp was the best way to >design code, let alone essential. You can build a pretty nice exception mechanism on top of setjmp/longjmp. Having some functions (memory allocation is a good example) raise exceptions rather than returning an error status can unclutter your code and give your weary typing fingers a rest. (Not as much as not checking error statuses at all, but we all know better than that -- don't we?) Jim Shankland jas@ernie.berkeley.edu "I've been walking in a river all my life, and now my feet are wet"
cquenel@polyslo.CalPoly.EDU (101 more school days) (01/23/89)
I write: > Should it ever be necessary/desirable to restore any registers > on a long-jump BESIDES the frame-pointer and/or stack-pointer ? Andrew Koenig explains: [at one time VAX implementations would restore "register" variables] [this was arguably useful.] I see this as a BAD thing to try to guarantee. I agree with the way ANSI did it. To the best of my understanding the "register" storage class has always been a "hint" to the compiler. Since many modern compilers will fairly often out-right ignore these hints, it makes the use of this feature EXTREMELY unportable at best. Consider a very straight-forward example: I use this restoral feature to restore a register variable through a longjump. How many variables can I restore this way ? How many registers variables can I effectively use ? Depending on a "register" variable to actually BE in a register is (as far as I'm concerned) a BAD thing. I hope there weren't too many people who were in favor of this in the ANSI committees. Since setjmp/longjmp is such a work-around/violate-all-the-rules/ just-get-me-the-f*ck-back-to-where-I-started/ sorta feature, (That is to say, a LAST RESORT, to be used almost exclusively in system dependant routines.) I would say that it SHOULDN'T actually restore anything. If you need anything to be restored, then save it yourself when you do a setjump in a volatile variable. I think this newer definition of setjmp/longjmp is much cleaner and provides only what is necessary and most useful. As a compiler writer, it certainly makes sense to me to only implement what can be guaranteed. That is, to provide well-defined services that can be relied on, and don't provide anything that might/might-not work. Comments anyone ? --chris If you understand what you're doing, you're not learning anything. ------------------------------------------------------------------------------- | Nothing the God of Bio-Mechanics wouldn't let you in heaven for ? | ------------------------------------------------------------------------------- | Chris Quenelle | Smart Mailers -> cquenel@polyslo.CalPoly.EDU | | Computer Systems Lab | Dumb Mailers -> !ucbvax!voder!polyslo!cquenel | | Cal Poly State Univ. |-------------------------------------------------| | San Luis Obispo, CA 93407 | On a clear disk you can seek forever. | -------------------------------------------------------------------------------
geoff@warwick.UUCP (Geoff Rimmer) (01/23/89)
In article <25@torsqnt.UUCP> david@torsqnt.UUCP (David Haynes) writes: >What should be the result of running the following program? > >#include <setjmp.h> > >main() >{ > register int j; > jmp_buf env; > > j = 1; > if(setjmp(env) == 1) { > printf("j = %d\n", j); > exit(1); > } > printf("j = %d\n", j); > j += 3; > longjmp(env, 1); >} > >Sequent, Ultrix and Vax C give results of j = 1, j = 4. >Gcc gives a result of j = 1, j = 1. >What does the ANSI standard say about this? I don't know what the ANSI standard says, but our manual page for setjmp() mentions in passing that register variables have unpredictable values code after the return from longjmp So, it's probably just luck that the Sequent, Ultrix and Vax C compiler give what you'd expect from a non-register variable: j = 1, j = 4 Geoff ------------------------------------------------------------ Geoff Rimmer, Computer Science, Warwick University, England. geoff@uk.ac.warwick.emerald "Oo, have we got a video?" "If anyone else asks me that question, I'm going to put head through the window." - The Young Ones, 1984 (?) ------------------------------------------------------------
dave@micropen (David F. Carlson) (01/24/89)
In article <25@torsqnt.UUCP>, david@torsqnt.UUCP (David Haynes) writes: > What should be the result of running the following program? > register int j; > jmp_buf env; > > Sequent, Ultrix and Vax C give results of j = 1, j = 4. > Gcc gives a result of j = 1, j = 1. > What does the ANSI standard say about this? > According to SVr3.0 setjmp(3): BUGS: The values of the registers on the second return from setjmp are the register values at the time of the first call to setjmp, not those at the time longjmp. This doesn't answer the ANSI question per se, but it does point out that using register variables around setjmp/longjmp is a fool's game. Play it safe, use a condom. -- David F. Carlson, Micropen, Inc. micropen!dave@ee.rochester.edu "The faster I go, the behinder I get." --Lewis Carroll
henry@utzoo.uucp (Henry Spencer) (01/24/89)
In article <8812@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >...John Reiser figured out a way around it -- a nifty version of >longjmp that unwound the stack, restoring the correct registers >at each iteration -- and that went into at least some VAX C >implementations. > >However, when it came to the ANSI committee, they decided it >would be too hard to mandate this kind of implementation... Don't forget that it was (relatively) easy on the VAX because one of the things that the all-singing-all-dancing VAX procedure call does is to save a register mask. This makes the VAX stack pretty much self-describing, at the cost of slowing down every function call and increasing the use of stack space. Most other implementations consider that too high a price to pay. -- Allegedly heard aboard Mir: "A | Henry Spencer at U of Toronto Zoology toast to comrade Van Allen!!" | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
crossgl@ingr.com (Gordon Cross) (01/24/89)
In article <9480@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: > >I don't think I've even seen a case in which setjmp/longjmp was the best >way to design code, let alone essential. I tend to disagree with this. I do avoid the use of setjmp/longjmp where they are not needed but try to correctly handle error recovery in a large interactive program without them! I have developed a caller-configurable error processor that takes care of such monsters nicely: an error is reported, handled, and recovered from simply by using something like if (read (descriptor, buffer, sizeof (buffer)) == -1) report_error (READFAIL, ERR_FATAL); do_normal_stuff (); /* report_error does NOT return on FATAL!! */ -- Gordon Cross UUCP: uunet!ingr!crossgl "all opinions are 111 Westminister Way INTERNET: crossgl@ingr.com mine and not those Madison, AL 35758 MA BELL: (205) 772-7842 of my employer."
cquenel@polyslo.CalPoly.EDU (96 more school days) (01/24/89)
henry@utzoo.uucp writes : >However, an implementation that simply trashes the registers (rather, >allows them to be trash) or, still worse, does likewise for automatic >variables not declared "register" (i.e. by promoting them to registers >and then not preserving them), is probably not going to sell well when >word gets around. Promoting register variables to automatic is not strictly necessary to not restore it on a longjmp. (if you can follow that sentance structure). Automatic variables need not be restored according to ANSI. Older machines had the effect of restoring variables that were left on the stack, but my argument is this : That there is actually not that much code out there (that purports to be portable :-) ) that DEPENDS on this behaviour. I looked at the bourne shell, and it uses setjmp/longjmp only for goto-purposes. Given the current breed of compiler writers, I would expect a fair number of compilers NOT to attempt to save miscellaneous registers. Consider a register file that is divided into SAVED and NOTSAVED registers which (by convention) are/are-not saved on a procedure call. Do we save the NOTSAVED class registers on a setjmp ? What about a machine like the Pyramid with sliding register windows. It has 4 classes of registers. Global Registers : not touched on a procedure call. Parameter Registers : Contain parameters on entry to routine Local Registers : For normal automatic variables Temporary Registers : For transient temporaries in expressions >The old de-facto rule was that register variables >had either current values or values as of the setjmp call, and that >other automatics weren't touched at all. If this "existing practice" could be supported with a reasonable expense, I would say go for it, but the following things argue against it: -- With many new architectures, it's not easy to do. (It doesn't come for free when restoring the frame-pointer) -- Compiler technology has improved to the point where the concept of what is "in registers" and what isn't is not only hard to guarantee, but in some of the more different architectures, might not even make sense. (As I've said in a previous posting) -- The real purpose of setjmp/longjmp is as a global goto when you have to go around the stack. It shouldn't need any "features" that make it easier to use.o -- When a signal handler (or other equivalently nasty program) needs to save state, then it can store (!) just the variables it needs in volatile variables that it keeps associated with the setjmp. -- No semi-legitimate uses of setjmp/longjmp that come to mind actually would require the restoral of variables to function. >will thus break essentially every longjmp-using program in existence. Do you have some evidence here ? --chris The life of a signal-handler is nasty, brutish and short.
chris@mimsy.UUCP (Chris Torek) (01/24/89)
In article <7249@polyslo.CalPoly.EDU> cquenel@polyslo.CalPoly.EDU (101 more school days) writes: >I see [making registers work as well as automatics around setjmp/longjmp] >as a BAD thing to try to guarantee. and bases this argument on the idea that `register' is a compiler hint and need not actually use a machine register. >As a compiler writer, it certainly makes sense to me to only implement >what can be guaranteed. ... But the contents of *all* automatic variables (register or not) *can* be guaranteed without too much trouble, and without requiring `volatile' qualifiers. If you will accept as the definition of a `very good' compiler `one that does interprocedural analysis and register allocation', then a good compiler must (since it may allocate registers to variables that are not automatic) make guarantees that will stand up for automatic variables even in the presence of longjmp, and the problem vanishes entirely. So a very good compiler will make such guarantees. Other compilers could simply turn off optimisation in functions containing calls to setjmp(). >I think this newer definition of setjmp/longjmp is much cleaner >and provides only what is necessary and most useful. This is a separate (and much more sensible) line of argument with which I happen not to agree: opinion as to elegance. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) (01/25/89)
henry@utzoo.uucp (Henry Spencer) writes: [ quoting andrew koenig (alice!ark) on john reiser's implementation of longjmp() that unwound the stack to restore all register variables that had been saved in previous stack frames ] > >However, when it came to the ANSI committee, they decided it > >would be too hard to mandate this kind of implementation... > > Don't forget that it was (relatively) easy on the VAX because one of the > things that the all-singing-all-dancing VAX procedure call does is to save > a register mask. This makes the VAX stack pretty much self-describing, > at the cost of slowing down every function call and increasing the use > of stack space. Most other implementations consider that too high a > price to pay. a setjmp/longjmp implementation that restores all variables (including those in registers) falls out of a caller saves function call protocol. no muss, no fuss, just restore the stack pointer and pc. this will work in the presence of inter-procedural optimization, if setjmp() is marked as a function that trashes all registers. this is one of the several reasons i consider caller-saves a better approach to function call protocol. paul haahr princeton!haahr or haahr@princeton.edu
gregg@ihlpb.ATT.COM (Wonderly) (01/25/89)
From article <5771@phoenix.Princeton.EDU>, by haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr): > a setjmp/longjmp implementation that restores all variables (including > those in registers) falls out of a caller saves function call protocol. > no muss, no fuss, just restore the stack pointer and pc. this will > work in the presence of inter-procedural optimization, if setjmp() is > marked as a function that trashes all registers. > > this is one of the several reasons i consider caller-saves a better > approach to function call protocol. Except that this kills any efficency that one might try to gain through the use of normal scratch registers at the lowest level of function call. What is the expense of for (i=0; i < cnt; ++i) cnt[i] = strlen (str[i]); when caller saves verses the case where called saves? If caller uses a lot of registers, it will continually save/restore them if caller saves whereas when called saves, it can decide when all of that work should really be done. It strikes me that setjmp() could save all GP registers. I know of at least one implementation were a jmp_buf is enough space for the entire register set. longjmp() of course just reloads the registers grabs the return value passed, and jumps to the return address given to it (on the stack or elsewhere). The expense is a consideration but the results are guaranteed in the cases I can think of. Unwinding the stack doesn't seem necessary and in fact seems counter productive. Of course there are those that would argue that setjmp()/longjmp() must be efficient because they want to call setjmp in a tight loop some place! -- Gregg Wonderly DOMAIN: gregg@ihlpb.att.com AT&T Bell Laboratories UUCP: att!ihlpb!gregg
chris@mimsy.UUCP (Chris Torek) (01/25/89)
In article <7283@polyslo.CalPoly.EDU> cquenel@polyslo.CalPoly.EDU (96 more school days) writes: >-- The real purpose of setjmp/longjmp is as a global goto > when you have to go around the stack. It shouldn't > need any "features" that make it easier to use. ... >-- No semi-legitimate uses of setjmp/longjmp that come to mind > actually would require the restoral of variables to function. These are the key points (and, incidentally, tie in to the `B&D' discussion in comp.lang.misc). For the sake of argument (which is to say that I do not necessarily believe this myself), consider the following use of setjmp/longjmp: /* return type of signal functions, either int or void */ typedef void sigreturn_t; static struct jbstack { jmp_buf cur; jmp_buf *prev; } *jbstack; sigreturn_t stop(int sig) { longjmp(jbstack->cur, 1); } struct foo *timed_fiddle_with(struct foo *base) { int fd; sigreturn_t (*oldalarm)(); struct jbstack j; j.prev = jbstack; jbstack = &j; if (setjmp(&j.cur)) { /* timeout */ jbstack = j.prev; (void) signal(SIGALRM, oldalarm); free((void *)base); return NULL; } (void) alarm(base->timeout); oldalarm = signal(SIGALARM, stop); fd = open(base->name, base->mode); (void) alarm(0); base->fd = fd; jbstack = j.prev; return base; } (longjmp is required wherever signals do not interrupt system calls.) This is really the beginning of a general exception mechanism with protection against stack unwinding, so that routines can clean up after themselves if interrupted (even if the interruption leaps from a low-level routine all the way back to main()). It can be argued that implementing such an exception mechanism using longjmp is a reasonable thing. Indeed, a number of languages provide more direct methods (e.g., Mesa and various Lisps); C provides sufficient primitives, leaving the discipline to use them to the programmer. Now, clearly one can sprinkle `volatile' qualifiers into the declarations in timed_fiddle_with(), so that it will work under pANS C. But (at least some of) the variables so declared are not in fact volatile---the value of `base', in particular, *never changes!* The qualifier is being (mis)used strictly for its side effect of inhibiting optimisation, not because the variable that is so qualified behaves in a way that is not described by the virtual machine. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
tim@crackle.amd.com (Tim Olson) (01/26/89)
In article <7283@polyslo.CalPoly.EDU> cquenel@polyslo.CalPoly.EDU (96 more school days) writes: | henry@utzoo.uucp writes : | >However, an implementation that simply trashes the registers (rather, | >allows them to be trash) or, still worse, does likewise for automatic | >variables not declared "register" (i.e. by promoting them to registers | >and then not preserving them), is probably not going to sell well when | >word gets around. | | What about a machine like the Pyramid with sliding register | windows. It has 4 classes of registers. | Global Registers : not touched on a procedure call. | Parameter Registers : Contain parameters on entry to routine | Local Registers : For normal automatic variables | Temporary Registers : For transient temporaries in expressions Register-windowed machines are usually very easy to write setjmp()/longjmp() for, because the registers are treated as a "stack-cache". Thus, all you have to save is the current stack-cache pointer in the jmpbuf, and restore it upon a longjmp(). This makes automatic variables act just as statics do: their value is that as of the time of the longjmp(). This is much cleaner than the botch of saving the register contents in the jmpbuf and restoring them. Of course, you still have to worry about optimizations such as register coalescing, etc. -- Tim Olson Advanced Micro Devices (tim@crackle.amd.com)
ark@alice.UUCP (Andrew Koenig) (01/26/89)
In article <9467@ihlpb.ATT.COM>, gregg@ihlpb.ATT.COM (Wonderly) writes: > It strikes me that setjmp() could save all GP registers. I know of at > least one implementation were a jmp_buf is enough space for the entire > register set. longjmp() of course just reloads the registers grabs the > return value passed, and jumps to the return address given to it (on the > stack or elsewhere). The expense is a consideration but the results are > guaranteed in the cases I can think of. Yup, that's what the folks thought who did the first VAX implementation, too. It doesn't work. Consider this case: register x; jmp_buf j; x = 3; if (setjmp(j)) { stuff } x = 4; longjmp(j,1); You will see that when `stuff' is executed, x will have been restored to 3. -- --Andrew Koenig ark@europa.att.com
cquenel@polyslo.CalPoly.EDU (94 more school days) (01/26/89)
Sorry for the length guys, but I think this will clear a lot up. Present are responses follow to the following people: henry@utzoo.uucp writes : ark@alice.UUCP (Andrew Koenig) writes: chris@mimsy.UUCP (Chris Torek) writes: geoff@warwick.UUCP (Geoff Rimmer) writes: haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes : tim@crackle.amd.com (Tim Olson) writes: In the last few articles I'm afraid I've been misunderstood a little bit. I'd like to try again. I think some people have there has been some confusion over two behaviours associated with variables at longjmp time. I will use the word CONSERVED when a variable is unaffected by a long jump. I will use the word RESTORED when a variable is given the value that it had at setjmp-time (either "for free" or by copying it's old value back into it). Under older systems, automatic variables were CONSERVED, and register variables were RESTORED. To illustrate the difference consider the following pseudo-code: routine() { /* register */ int i; i = BEFORE_VALUE; call to set_jmp(); i = AFTER_VALUE; call to routine_which_calls_long_jmp(); } If i is declared REGISTER, then "normally" it would be RESTORED. It's value would be BEFORE_VALUE. If i is NOT declared register, then normally it would be CONSERVED. It's value would be AFTER_VALUE. ANSI guarantees that variables declared volatile will be CONSERVED. It does not say that ANY variables have to be restored. On stack-based machines with conventional registers and calling sequences you get automatic variable CONSERVATION for free. (You have to write out all your automatic variables that are alive in registers.) On those conventional systems, you also get RESTORED automatics under the following circumstances: If you declare it to be of register storage class, AND the compiler ACTUALLY puts it in a register. While I don't know of any compiler that GUARANTEES that ALL "register" declarations result in actual registers being used, I'm sure some people would assume that it is a safe bet that ONE or TWO register declarations will be honored. Although this is non-portable strictly speaking, it probably works most of the time. I see no problem with a compiler going beyond the ANSI spec and guaranteeing that ALL automatic variables will be CONSERVED. I think this is a very reasonable thing. And it can be achieved without added setjmp-time baggage, on a fairly conventional machine. No general registers need to stored for this to happen ! My argument is that no code would rely on registers being RESTORED. Returning from a longjmp and having all your local registers trashed would be a hassle to deal with, I admit. But the alternative is to have them be the values at the time the setjmping procedure called the longjmping procedure. From the Pyramid man page on setjmp/longjmp: ... All memory-bound data have values as of the time longjmp was called. The machine registers are restored to the values they had at the time that setjmp was called. But, because the register storage class is only a hint to the C compiler, variables declared as register variables may not necessarily be assigned to machine registers, so their values are unpredictable after a longjmp. This is especially a problem for programmers try- ing to write machine-independent C routines. ... [There follows an example with a careful note NOT to modify register variables after calling setjmp. This is because their values will be indeterminate on a Pyramid. It would not be too much trouble to conserve them, just ignore the register declaration in a routine that calls setjmp.] henry@utzoo.uucp writes : >However, an implementation that simply trashes the registers (rather, >allows them to be trash) or, still worse, does likewise for automatic >variables not declared "register" (i.e. by promoting them to registers >and then not preserving them), is probably not going to sell well when >word gets around. You are correct, perhaps ANSI could have guaranteed that automatics would be CONSERVED. My point was that none should be RESTORED. ark@alice.UUCP (Andrew Koenig) writes: >...John Reiser figured out a way around it -- a nifty version of >longjmp that unwound the stack, restoring the correct registers >at each iteration -- and that went into at least some VAX C >implementations. This allows register variables to be truly RESTORED without the space and time overhead of saving all the registers in the jmp_buf. However, the calling convention that supported it was rather luxurious (read : expensive) in its own right. chris@mimsy.UUCP (Chris Torek) writes: >But the contents of *all* automatic variables (register or not) *can* be >guaranteed without too much trouble, and without requiring `volatile' >qualifiers. Granted, they can be guaranteed CONSERVED. They are not RESTORED. I wrote previously: >I think this newer definition of setjmp/longjmp is much cleaner >and provides only what is necessary and most useful. chris@mimsy.UUCP (Chris Torek) writes: >This is a separate (and much more sensible) line of argument with >which I happen not to agree: opinion as to elegance. I think that CONSERVING all automatic variables but RESTORING none of them is more elegant than CONSERVING all non-register automatic variables and sort-of-restoring or maybe-restoring register variables. I say that CONSERVING them all and RESTORING non of them is best. geoff@warwick.UUCP (Geoff Rimmer) writes: >I don't know what the ANSI standard says, but our manual page for >setjmp() mentions in passing that > > register variables have unpredictable values code after the > return from longjmp > >So, it's probably just luck that the Sequent, Ultrix and Vax C >compiler give what you'd expect from a non-register variable: It seems like restoring register variables to an unknown state is a pretty common thing to do. My argument is that all these venders instead of saying "register variables are in an unknown state" should NOT RESTORE THEM, and should write them to the stack, and should say that they are CONSERVED. It ocurrs to me that this would require the following extra work on the part of their compilers: reserving space for register variables on the stack and dumping even [registers that could be guaranteed across procedure calls] to the stack. haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes : >a setjmp/longjmp implementation that restores all variables (including >those in registers) falls out of a caller saves function call protocol. >no muss, no fuss, just restore the stack pointer and pc. this will >work in the presence of inter-procedural optimization, if setjmp() is >marked as a function that trashes all registers. Using a full caller-saves convention by itself will not even allow you to CONSERVE register variables, much less RESTORE them. (Although when Paul said "restore" he may have meant CONSERVE). When the first return from setjmp takes place, all those nicely saved register values are popped off the stack. NEVER TO BE PUSHED AGAIN. :-) If you want your registers to be RESTORED, you have to save them in the jmp_buf. haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes : >this is one of the several reasons i consider caller-saves a better >approach to function call protocol. Both pure-caller-save and pure-callee-save have their benefits, but I personally believe that a combined caller-callee saves protocal works best. tim@crackle.amd.com (Tim Olson) writes: [In response to my saying that register windows made setjmp a big deal] >Register-windowed machines are usually very easy to write >setjmp()/longjmp() for, because the registers are treated as a >"stack-cache". Thus, all you have to save is the current stack-cache >pointer in the jmpbuf, and restore it upon a longjmp(). This makes >automatic variables act just as statics do: their value is that as of >the time of the longjmp(). This is much cleaner than the botch of >saving the register contents in the jmpbuf and restoring them. > >Of course, you still have to worry about optimizations such as register >coalescing, etc. You are correct. I was in error. Sliding register window machines SHOULD be easy to write setjmp/longjmp for. The simple solution of restoring the Control Stack (or Register Stack) Pointer to its old value have the effect of CONSERVING register variables, but not of RESTORING to their values at setjmp time. I think this is a very sane way to do it. --chris ------------------------------------------------------------------------------- | Nothing the God of Bio-Mechanics wouldn't let you in heaven for ? | ------------------------------------------------------------------------------- | Chris Quenelle | Smart Mailers -> cquenel@polyslo.CalPoly.EDU | | Computer Systems Lab | Dumb Mailers -> !ucbvax!voder!polyslo!cquenel | | Cal Poly State Univ. |-------------------------------------------------| | San Luis Obispo, CA 93407 | On a clear disk you can seek forever. | -------------------------------------------------------------------------------
cquenel@polyslo.CalPoly.EDU (93 more school days) (01/27/89)
In article <15626@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: > >Now, clearly one can sprinkle `volatile' qualifiers into the >declarations in timed_fiddle_with(), so that it will work under pANS >C. But (at least some of) the variables so declared are not in fact >volatile---the value of `base', in particular, *never changes!* The >qualifier is being (mis)used strictly for its side effect of inhibiting >optimisation, not because the variable that is so qualified behaves in >a way that is not described by the virtual machine. This depends on how you look at it. If you think of "volatile" as meaning "this has to live in memory", then it makes sense to me. Or if you consider that the setjmp/longjmp mechanism in a very real sense DOES violate the "virtual machine", then volatile is a very appropriate description. Some people seem to think that ideally, setjmp/longjmp should take the program back in TIME. I think that *conceptually* longjmp should only take the program back to a previous execution point. A C routine (IMHO) has only one existence. If a routine runs through part A and then setjmps and then runs through part B and then longjmps. I would *expect* that it's state would be the state after the execution of part B. That is the way my working defenition of the "C" virtual machine works. --chris
rbutterworth@watmath.waterloo.edu (Ray Butterworth) (01/27/89)
In article <9467@ihlpb.ATT.COM>, gregg@ihlpb.ATT.COM (Wonderly) writes: > > this is one of the several reasons i consider caller-saves a better > > approach to function call protocol. > Except that this kills any efficency that one might try to gain through > the use of normal scratch registers at the lowest level of function call. > What is the expense of > for (i=0; i < cnt; ++i) > cnt[i] = strlen (str[i]); > when caller saves verses the case where called saves? If caller uses a > lot of registers, it will continually save/restore them if caller saves > whereas when called saves, it can decide when all of that work should > really be done. I think you've got it backwards. If the caller saves, and the compiler has any smarts at all, it will go something like: /* save all active registers now */ for (i=0; i < cnt; ++i) cnt[i] = strlen (str[i]); /* restore all active registers now */ i.e. if the current function uses N registers, and strlen uses n registers, then with caller saving there are N saves and N restores, and with callee saving there are cnt*n saves and cnt*n restores. So which is better depends upon which is smaller, N or cnt*n. For strlen(), n might be small, but in general I think that N is usually a lot smaller than cnt*n.
prc@maxim.ERBE.SE (Robert Claeson) (01/27/89)
In article <9480@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > Really, setjmp/longjmp is just a groady "goto" and should be > avoided for the same reasons as the ordinary "goto"... > it is even more violent than an ordinary "goto", which is why > it has to be more loosely constrained. I don't think I've > even seen a case in which setjmp/longjmp was the best way to > design code, let alone essential. The nearest to a valid use > I know of is to allow a SIGINT to abort processing and fly > back to a main command loop (e.g. in the "ed" editor), but > even there the longjmp can cause stdio data structures to be > left in an inconsistent state. Asynchronous concurrent > processes really need to be designed around better tools than > setjmp/longjmp. Okay, all you portable code types, maybe you can help me with making this more portable (ie, to not use setjmp/longjmp). In a single-key (not character) keyboard read routine I've written, I recognizes function keys and returns a single, generic value for them instead of the usual character. I do this by setting an alarm(1) and reading character by character until I've got a non-redundant string, which in the case of a printable character (an 'a' for example) is that single character. If a complete function key sequence is found before that alarm() is performed, the alarm is cleared and a value is returned. But if I keep reading from the keyboard without finding a real key, a SIGALRM handler is called, which just does a longjmp back to a setjmp in the main (non-static) function. Then the complete string, except for the first character, is stored in a buffer that will be read instead of the keyboard on subsequent calls to the function. The first character read is returned. This is how I handles single Escape keystrokes. I could probably read the clock, do a tight loop that reads the keyboard non-blocking and check the clock on each iteration, but that would probably take too much CPU, so I don't want to do that. Now, make this portable and non CPU-intensive. If you think the algorithm needs to be changed, just tell me. -- Robert Claeson, ERBE DATA AB, P.O. Box 77, S-175 22 Jarfalla, Sweden "No problems." -- Alf Tel: +46 758-202 50 EUnet: rclaeson@ERBE.SE uucp: uunet!erbe.se!rclaeson Fax: +46 758-197 20 Internet: rclaeson@ERBE.SE BITNET: rclaeson@ERBE.SE
ch@maths.tcd.ie (Charles Bryant) (01/27/89)
In article <5771@phoenix.Princeton.EDU> haahr@princeton.edu (Paul Gluckauf Haahr) writes: >a setjmp/longjmp implementation that restores all variables (including >those in registers) falls out of a caller saves function call protocol. >no muss, no fuss, just restore the stack pointer and pc. this will >work in the presence of inter-procedural optimization, if setjmp() is >marked as a function that trashes all registers. > Could you explain this further please. Consider the example: foo() { register a,b,c; /* useful work with a,b,c so all are live */ if (setjmp(jb)==1) { something using a, b, and c } a += b+c; fna(); /* only a is live */ return a; } fna() { longjmp(jb,1); } Then the stack will look like this: call to setjmp: <addr in foo> a b c <addr foo will return to> call to longjmp: <addr in fna> <addr in foo> a <addr foo will return to> setjmp can't know what registers were saved (i.e. a, b, c) so it must save the sp as the address where a is saved. if longjmp restores the sp to this value, 'foo' will assign a = <addr in fna> b = <addr in foo> c = a at time of longjmp Is this reasoning correct? Does the compiler have to save ALL the registers for every function call in 'foo' which potentially could call longjmp or is in a different file? -- Charles Bryant. Working at Datacode Electronics Ltd.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/28/89)
In article <470@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: >Now, make this portable and non CPU-intensive. If you think the >algorithm needs to be changed, just tell me. I assume you're not using stdio to do this, since longjmping from a signal handler is unsafe if a stdio routine was active at the time of the alarm. A SVID-conforming UNIX provides several ways to do the sort of thing you're attempting, for example using VMIN and VTIME which obviate the need for SIGALRM. Or, you could just set a global flag in your alarm handler and return, since a SVID- conforming UNIX will abort a read() from a terminal when the alarm occurs. By testing for EINTR after the read() returns, and using the global flag as additional verification, you can make the main control logic do the right thing. There is no fully portable way to do what you're attempting, and using longjmp is not a solution because it is unreliable in this context.
meissner@tiktok.dg.com (Michael Meissner) (01/31/89)
In article <470@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: | Okay, all you portable code types, maybe you can help me with making | this more portable (ie, to not use setjmp/longjmp). | | In a single-key (not character) keyboard read routine I've written, | I recognizes function keys and returns a single, generic value for them | instead of the usual character. I do this by setting an alarm(1) and | reading character by character until I've got a non-redundant string, which | in the case of a printable character (an 'a' for example) is that single | character. Both of the modern UNIX varients have methods to do timed reads from a character device without resorting to alarm. In Berkeley-based UNIXes (UNICI?), you do a select on the file descriptor(s) with the given timeout specified in the struct timeval structure. This will also work on pipes. Note there are some additional macros to use in setting up the bit array of file descriptors for 4.3 based systems that were not available in 4.2, but they are easy enough to provide. In System V based UNIXes, you do an ioctl to set MIN/TIME to be the minimum number of characters to read and the timeout in tenths of a second. This only works on terminals (and pty's if provided). Some version of System V.3 (V.3.1?) is susposed to have rewritten the terminal subsystem into streams (and pipes?). If so, you can then use poll, which provides the same basic functionality as select, except that it is limited to streams devices. Given that you set an appropriate timeout, non of the above solutions are CPU intensive, and they don't have the gapping holes of interrupting the main task at possibly the wrong time that alarm, and signal open up. | I could probably read the clock, do a tight loop that reads the | keyboard non-blocking and check the clock on each iteration, but that | would probably take too much CPU, so I don't want to do that. | | Now, make this portable and non CPU-intensive. If you think the | algorithm needs to be changed, just tell me. As an aside, I've used systems at times, where the latency between characters could be really high, and such simple minded function key mappings would break occansionally. For example, when I was in our Mass. plant, I would find times when the main network down to our North Carolina plant would be out. I eventually resorted to calling a California site, and from there calling North Carolina. I think I went through about 5-10 hosts, with each host sometimes buffering the I/O... -- Michael Meissner, Data General. Uucp: ...!mcnc!rti!xyzzy!meissner Arpa: meissner@dg-rtp.DG.COM (or) meissner%dg-rtp.DG.COM@relay.cs.net
jf@cci632.UUCP (Jens Fiederer) (02/02/89)
In article <9480@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: > >I don't think I've even seen a case in which setjmp/longjmp was the best >way to design code, let alone essential. While I have never used setjmp/longjmp myself, I have never written a large interpreter (for example, a full blown LISP) in C. Writing a LISP interpreter in SAIL, I found a non-local goto facility very useful to help in error handling. My feeling is that setjmp/longjmp have their legitimate uses, be they ever so few. Jens
paul@sun505.UUCP (Paul E. Black) (02/03/89)
In article <26109@cci632.UUCP> jf@ccird3.UUCP (Jens Fiederer) writes: > >While I have never used setjmp/longjmp myself, ... [m]y feeling is >that setjmp/longjmp have their legitimate uses, be they ever so few. I agree. I helped write an IC design editor. The structuring seemed better to put a setjmp in the top loop of the "command interpreter" (the code which reads the keyboard & mouse and decides which function should be dispatched). Then any command which needs to terminate can easily do a longjmp. In about 75 000 lines of code, there are less than 40 uses of setjmp and longjmp. Those are confined to just three usage areas. Paul E. Black | UUCP: ...{pyramid,amdahl,ames}!oliveb!cirrusl!paul CIRRUS LOGIC, Inc. | Internet: cirrusl!paul@olivetti.com 1463 Centre Pointe Dr. | Voice: (408) 945-8305 x 210 Milpitas, CA 95035 USA
prc@maxim.ERBE.SE (Robert Claeson) (02/05/89)
I wrote: | In a single-key (not character) keyboard read routine I've written, | I recognizes function keys and returns a single, generic value for them | instead of the usual character. I do this by setting an alarm(1) and | reading character by character until I've got a non-redundant string, which | in the case of a printable character (an 'a' for example) is that single | character. In article <3112@xyzzy.UUCP>, meissner@tiktok.dg.com (Michael Meissner) writes: ..... > In System V based UNIXes, you do an ioctl to set MIN/TIME to be the > minimum number of characters to read and the timeout in tenths of a > second. This only works on terminals (and pty's if provided). ..... Does this really work that good? A function key (control) character sequence can be of arbitrary length. The up-arrow key on my keyboard sends three characters, whereas a typical F-key sends 5 characters. So how do I know what to put into VMIN? > As an aside, I've used systems at times, where the latency between > characters could be really high, and such simple minded function key > mappings would break occansionally. What better function key mapping algorithms are there? I've played with don't having any timeouts at all for these cases, but then I cannot use the single escape key (or whatever key the function key sequences starts with). -- Robert Claeson, ERBE DATA AB, P.O. Box 77, S-175 22 Jarfalla, Sweden "No problems." -- Alf Tel: +46 758-202 50 EUnet: rclaeson@ERBE.SE uucp: uunet!erbe.se!rclaeson Fax: +46 758-197 20 Internet: rclaeson@ERBE.SE BITNET: rclaeson@ERBE.SE
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/05/89)
In article <483@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: >Does this really work that good? A function key (control) character >sequence can be of arbitrary length. The up-arrow key on my keyboard >sends three characters, whereas a typical F-key sends 5 characters. The character sequence should follow ANSI X3.64, meaning that it begins with an ESC character and continues through an alpha. That can be parsed without any timeouts at all. What probably is contributing to the confusion is that you bought keyboards that have an ESC key the user can press that violates the X3.64 standard. Remove the key or tell your users how to recover from it (treating a second consecutive ESC specially is one way).
les@chinet.chi.il.us (Leslie Mikesell) (02/06/89)
In article <483@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: >> In System V based UNIXes, you do an ioctl to set MIN/TIME to be the >> minimum number of characters to read and the timeout in tenths of a >> second. This only works on terminals (and pty's if provided). >..... >Does this really work that good? A function key (control) character >sequence can be of arbitrary length. The up-arrow key on my keyboard >sends three characters, whereas a typical F-key sends 5 characters. >So how do I know what to put into VMIN? Put something fairly large in VMIN and something small in VTIME. Then make read() requests for many characters at a time. The read() will return when at least one character is typed and either VTIME has elapsed between characters or VMIN characters have been entered. Increasing VMIN/VTIME beyond what you need to capture the function key strings will increase efficiency (by reducing the read() system calls) at the cost of response time if the operator can type faster than VTIME expires. In any case, this approach should be much more efficient that wrapping alarm()'s around single character read()s. Les Mikesell
les@chinet.chi.il.us (Leslie Mikesell) (02/06/89)
In article <9597@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >What probably is contributing to the confusion is that you bought >keyboards that have an ESC key the user can press that violates the >X3.64 standard. Remove the key or tell your users how to recover >from it (treating a second consecutive ESC specially is one way). It must be fun to run vi/emacs/ksh/etc. on a keyboard that has not ESC key. Les Mikesell
prc@maxim.ERBE.SE (Robert Claeson) (02/06/89)
In article <9597@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > In article <483@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: > >Does this really work that good? A function key (control) character > >sequence can be of arbitrary length. The up-arrow key on my keyboard > >sends three characters, whereas a typical F-key sends 5 characters. > > The character sequence should follow ANSI X3.64, meaning that it begins > with an ESC character and continues through an alpha. That can be > parsed without any timeouts at all. I have already written code to parse ANSI X3.64 sequences, but since there's so many non-ANSI terminals out there, I'm not really sure I want to lock myself into ANSI-compatible terminals (even though I'd like to). > What probably is contributing to the confusion is that you bought > keyboards that have an ESC key the user can press that violates the > X3.64 standard. Remove the key or tell your users how to recover > from it (treating a second consecutive ESC specially is one way). I'd like to get rid of all escape keys in the world (that's why I only buy VT220-style keyboards nowadays), but on the other hand, I don't think an escape key violates the standard. As I recall, all function key sequences should start with the CSI 8-bit character or 7-bit character sequence (ESC [) and end with an alphanumeric character. Oh, come to think of it, maybe I should get rid of my table-driven code and invent "terminal handlers" instead. You know, determine the terminal type (with ESC Z or by reading the TERM variable) and start an appropriate process that handles all i/o to the terminal, and have my application talk to that process (via good 'ole pipes, message queues or shared memory). -- Robert Claeson, ERBE DATA AB, P.O. Box 77, S-175 22 Jarfalla, Sweden "No problems." -- Alf Tel: +46 758-202 50 EUnet: rclaeson@ERBE.SE uucp: uunet!erbe.se!rclaeson Fax: +46 758-197 20 Internet: rclaeson@ERBE.SE BITNET: rclaeson@ERBE.SE
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/07/89)
In article <7644@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes: >It must be fun to run vi/emacs/ksh/etc. on a keyboard that has not >ESC key. If you were following the discussion you should have heard how reliance on ESC timing causes problems. If you don't like removal of the ESC key then follow my second suggestion instead.
wayne@dsndata.uucp (Wayne Schlitt) (02/07/89)
In article <9597@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > > What probably is contributing to the confusion is that you bought > keyboards that have an ESC key the user can press that violates the > X3.64 standard. Remove the key or tell your users how to recover > from it (treating a second consecutive ESC specially is one way). *gack*. you cant be serious. do you ever use vi or emacs? both of them need to use a single ESC key to work. if the X3.64 standard says you can use the escape key, then the X3.64 standard isnt going to be used much. -wayne
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/07/89)
In article <WAYNE.89Feb6150523@dsndata.uucp> wayne@dsndata.uucp (Wayne Schlitt) writes: >you cant be serious. Mostly I am. >do you ever use vi or emacs? When I'm forced to I do. >both of them need to use a single ESC key to work. No, as a matter of fact EMACS wants a "meta" key. On terminals lacking a suitable "meta" key, ESC is often substituted. This use of ESC never was essential, it's just a kludge that should have been avoided in the first place. (TECO was the first and worst offender, but at least it predated X3.64 so it had an excuse.) >if the X3.64 standard says you can[not] use the escape key, >then the X3.64 standard isnt going to be used much. That's not exactly what it says. It does require that escape sequences be properly handled, and in many environments that can't be reliably done if you let users bang away on a separate ESC key. Note that I suggested a second alternative if you don't like the one about removing the ESC key.
prc@maxim.ERBE.SE (Robert Claeson) (02/08/89)
In article <7644@chinet.chi.il.us>, les@chinet.chi.il.us (Leslie Mikesell) writes: > It must be fun to run vi/emacs/ksh/etc. on a keyboard that has not > ESC key. Sort of. All keyboards that I know of that lacks an ESC key has another key as a substitute. For example, on the VT220 keyboard, one can use ctrl-3 or ctrl-[. -- Robert Claeson, ERBE DATA AB, P.O. Box 77, S-175 22 Jarfalla, Sweden "No problems." -- Alf Tel: +46 758-202 50 EUnet: rclaeson@ERBE.SE uucp: uunet!erbe.se!rclaeson Fax: +46 758-197 20 Internet: rclaeson@ERBE.SE BITNET: rclaeson@ERBE.SE
daveh@marob.MASA.COM (Dave Hammond) (02/08/89)
In article <9597@smoke.BRL.MIL> (Doug Gwyn (VLD/VMB) <gwyn>) writes [concerning multi-byte keystroke sequences]: > >The character sequence should follow ANSI X3.64, meaning that it begins >with an ESC character and continues through an alpha. That can be >parsed without any timeouts at all. Considering the number of display manufacturers *not* using ANSI X3.64 sequences, this seems a bit narrow-minded. >What probably is contributing to the confusion is that you bought >keyboards that have an ESC key the user can press that violates the >X3.64 standard. Remove the key or tell your users how to recover >from it (treating a second consecutive ESC specially is one way). The very "feature" which drove me away from VT-220's was the lack of a real ESC key. Substituting Shift-F12 (or even programming an unshifted F-key) just doesn't cut it. I'm sure you can think of several programs which would break without an ESC key. Handling keyboards which may transmit their multi-byte sequence intro key as a single byte key is not especially difficult. You do have to rely on some sort of timeout, but there are adequate calls available on most OS's to either read with timeout or peek at the keyboard queue. Timeouts of 1/4 to 1/2 sec. on a 9600 baud serial line are adequate to distinguish between single bytes and failed sequences -- and barely noticeable as a "delay" to the user. -- Dave Hammond ...!uunet!masa.com!marob!daveh daveh@marob.masa.com
rob@hathi.eng.ohio-state.edu (Rob Carriere) (02/09/89)
In article <501@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: >In article <7644@chinet.chi.il.us>, les@chinet.chi.il.us (Leslie Mikesell) writes: >> It must be fun to run vi/emacs/ksh/etc. on a keyboard that has not >> ESC key. >Sort of. All keyboards that I know of that lacks an ESC key has another >key as a substitute. For example, on the VT220 keyboard, one can use >ctrl-3 or ctrl-[. Yeah. You should hear what my finger reflexes have to say about that, though. SR
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/09/89)
In article <501@maxim.ERBE.SE> prc@maxim.ERBE.SE (Robert Claeson) writes: -In article <7644@chinet.chi.il.us>, les@chinet.chi.il.us (Leslie Mikesell) writes: -> It must be fun to run vi/emacs/ksh/etc. on a keyboard that has not -> ESC key. -Sort of. All keyboards that I know of that lacks an ESC key has another -key as a substitute. For example, on the VT220 keyboard, one can use -ctrl-3 or ctrl-[. I don't know about ctrl-3, but ctrl-[ almost certainly transmits the ASCII ESC code, so it amounts to an ESC key. That brings one right back to the original problem, of distinguishing between legitimate escape sequences and human-typed garbage.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/09/89)
In article <546@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes: >You do have to rely on some sort of timeout, but there are adequate >calls available ... Apparently you missed the posting that explained why timeout is NOT adequate.