nathan@orstcs.UUCP (nathan) (03/03/86)
"That turns out not to be the case." -Niven & Pournelle Under certain FORTRAN compilers, I can write a clean, recursive Hoare quicksort. It would not be at all portable. FORTRAN is not a recursive language. Under certain C compilers, I can write a complex-number library whose functions are usable both in main-line code and in signal routines. It would not be at all portable. C is not a fully re-entrant language. What galls is that *most* of the language is! It's only in the area of structure handling that the specification is too loose to permit portability of programs which need re-entrancy. If, in the language specification, it doesn't say that interrupts won't mess up mainline code's variables, then I as a programmer can't count on that fact -- and any program I write which needs it is immediately, irreparably nonportable. C++ was intended to address the needs of implementors of large systems. The Unix kernel is one such system. The Unix kernel avoids use of structs as return values. Are we to avoid returning "class" items in C++ programs, except in constructors? I understand that addressing this issue raises some sticky implementation issues, *all* related to use of C as the intermediate language representation. I do not think that it therefore deserves to be swept under a rug. After all, the issue is not intractable. Let's call a bug a bug. For instance, one could define an explicit subset of C++, called "C++ but not re-entrant". Compilers that bypass the C stage, or are built around a re-entrant C compiler, need not be so hobbled and could then be called full "C++". A more difficult solution would be to work around the (quite prevalent) bug. For example, the C code generated could allocate return-value space in the caller's block and generate an extra pointer argument for the C function whose C++ "antecedent" returns a struct. The C function would copy its "return value" out via this pointer. The calling function would use the returned pointer to access the return value. Then even pcc-based compilers would work right. The extra argument wouldn't bother (most) pcc library routines. C-library calls still wouldn't be re-entrant, but C++ ones would. The only difficulty would be in object compatibility with other (unbuggy) C++ compilers. A note to Dr. Stroustrup: I hope that in harping on this point I am not making an enemy. I think C++ is a tremendous product that may rescue us all from almost certain Ada-ization. But as a builder of real-time systems, I'd love to see some indication that it will be useful (that is, portable) in what I and my kind do. Nathan C. Myers { tektronix | hplabs!hp-pcd }!orstcs!nathan OR nathan@oregon-state
jack@boring.UUCP (03/07/86)
The fact the functions returning structures are non-reentrant is not the only problem. *any* intelligent I/O subsystem will have to keep some sort of internal data structures, and an interrupt routine will immedeately blow the program away as soon as it tries to do I/O. Or, even worse, it will blow the program away two years later, when you've long gone somewhere else. The only safe things to do in an interrupt routine are - setting the InterruptHasOccurred flag, - longjmp - exit. By the way, can anyone point me to an application where I would want to calculate with complex numbers in an *interrupt routine*:-) -- Jack Jansen, jack@mcvax.UUCP The shell is my oyster.
jimc@ucla-cs.UUCP (03/07/86)
In article <34200005@orstcs.UUCP> nathan@orstcs.UUCP (nathan) writes: >Under certain C compilers, I can write a complex-number library >whose functions are usable both in main-line code and in signal >routines. It would not be at all portable. C is not a fully >re-entrant language. > >What galls is that *most* of the language is! It's only in the >area of structure handling that the specification is too loose >to permit portability of programs which need re-entrancy. > >If, in the language specification, it doesn't say that >interrupts won't mess up mainline code's variables, then I as >a programmer can't count on that fact -- and any program I write >which needs it is immediately, irreparably nonportable. > The draft "C" standard, X3J11/85-138, section B.2.3 "Signals and Exceptions", states: Functions must be implemented such that they may be interrupted at any time by a signal, and may be called by a signal handler with no alteration to data with automatic storage duration belonging to earlier invocations... The functions in the standard library are not guaranteed to be reentrant... As for the latter part, I believe it refers to things like asctime that store results in a static string. I have recommended a wording change to "Certain library functions, explicitly noted in the standard, may not be reentrant." -- James F. Carter (213) 206-1306 UCLA-SEASnet; 2567 Boelter Hall; 405 Hilgard Ave.; Los Angeles, CA 90024 UUCP:...!{ihnp4,ucbvax,{hao!cepu}}!ucla-cs!jimc ARPA:jimc@locus.UCLA.EDU
brooks@lll-crg.ARpA (Eugene D. Brooks III) (03/08/86)
>By the way, can anyone point me to an application where I would
There aren't many interrupt routines that need complex arithmetic.
There are however a few parallel applications which use complex arithmetic
and as long as structure return values are not properly reentrant you have
a serious problem with them in a parallel coding environment.
gwyn@brl-smoke.UUCP (03/09/86)
In article <6812@boring.UUCP> jack@mcvax.UUCP (Jack Jansen) writes: >*any* intelligent I/O subsystem will have to keep some sort >of internal data structures, and an interrupt routine will >immedeately blow the program away as soon as it tries to do >I/O. Or, even worse, it will blow the program away two years >later, when you've long gone somewhere else. Well, if one can implement an atomic semaphore (I know how to do this for a PDP-11 or a VAX), one can implement "conditional critical regions" to protect data structures from being clobbered by asynchronous interrupts. The 3B20A UNIX kernel uses semaphores for this purpose (it's the only symmetric multiprocessor implementation of UNIX that I am aware of). SVR2 STDIO makes a valiant attempt to permit use of STDIO routines from interrupt handlers. However, ... >The only safe things to do in an interrupt routine are >- setting the InterruptHasOccurred flag, >- longjmp >- exit. ... I agree with these sentiments, mostly. I wouldn't even say that longjmp is safe, since while the (non-interrupt) manipulation of data structures is occurring, they will be in an inconsistent state that could cause trouble later if the manipulations are not allowed to complete. To implement operating systems, however, the problem of asynchronous interrupts must be solved. Methods for parallel processing have been published in the past decade or so that are relevant to this issue. Ultimately one needs an atomic synchronizer and a queue to put blocked tasks on when they attempt to enter a locked region. (A blocked task is allowed to proceed when the locker leaves the shared region.) This seems like far too much complexity for normal user-mode applications, though, unless implemented as a package or class (probably with a small assembly-language locking module).
henry@utzoo.UUCP (Henry Spencer) (03/12/86)
> The only safe things to do in an interrupt routine are > - setting the InterruptHasOccurred flag, > - longjmp > - exit. Actually, neither longjmp nor exit is 100% safe. Longjmp will get you out fairly safely (unless your function-calling sequence has an interrupt window, like the V7 pdp11 one did [fixed in SysV]), but things may still be in a mess inside whatever was interrupted, with disastrous results the next time you call it. And exit invokes stdio's cleanup routine, which might run afoul of the same problem. _exit should be safe. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry