doug@snitor.uucp (Doug Moen) (02/09/91)
In article <9102080401.AA29237@jumbo.pa.dec.com> gnelson (Greg Nelson) writes: > 2) The NEW expression's behaviour is not defined in the case that > not enough memory is left. Is this a checked runtime error, or > does it return NIL? If it returns NIL, then it isn't returning > a "new" value. If it is a checked runtime error, how do you > allocate all available memory without crashing? > >The report should have defined this to be a checked runtime error. >If you want to allocate all available memory without crashing, you >have to use a lower-level, implementation-dependent interface. I strongly disagree. The report should have defined this to raise an exception. There are many programs for which crashing on memory exhaustion is unacceptable behaviour. Examples include: text editors, shells, window managers, daemons providing essential system services, and just about any interactive program. In order to write any of these programs in Modula-3, it is necessary to: - use a low-level, implementation-dependent interface for allocating memory (which means the program isn't portable) - avoid using any library module that calls NEW. This means avoiding most standard modules, including Text and Thread. These are very serious restrictions, which lead me to believe that Modula-3 is simply not suitable for writing interactive programs or daemons that are required to be robust. The text editor I use is written in C, and does not crash when it runs out of memory or temp file space. Instead, it displays an error message, and permits me to save my changes before exiting. This robustness has saved my bacon on at least one occasion. Last year, I wrote an image editor using Motif & the X Toolkit. This editor has prodigious memory requirements, since the images we deal with can be quite large. The X Toolkit aborts your program if it runs out of memory. As a result, it is possible to crash my editor simply by opening a large number of windows. Of course, when the editor crashes, you lose all of your work. This has actually happened to users of my program. I find this most upsetting, since to fix the bug, I would have to reimplement Motif and the X Toolkit. The preface to the Modula-3 report says: "The goal of Modula-3 is to be as simple and safe as it can be while meeting the needs of modern systems programmers." Modula-3 can't meet these goals until NEW has been redefined to raise an exception on memory exhaustion.
emery@aries.mitre.org (David Emery) (02/11/91)
Ada provides an exception (STORAGE_ERROR) that is raised when the allocator cannot return any memory. I have likened this to a parachute that opens on impact, in that it meets its absolute requirements but is unusable in most practical situations. It is not enough to have an exception, you also have to define what can be done to handle the exception. In the case of Ada, STORAGE_ERROR can be raised in (at least) 2 circumstances: 1. out of heap 2. out of stack There is no good way to tell the difference between these two occurances. Furthermore, if you've run out of stack, you probably can't do anything at this point, because anything interesting (such as calling a cleanup routine) would require more stack space. My point here is that if you want to be able to recover from storage exhaustion, you need more than notification. You also need some understanding of what is permissible and not permissible after the exception has been raised. Finally, you'd like very much to have this defined in such a way that your program is portable (i.e. maybe the language should define a minimum permissible set of operations/actions, which can be extended by an implementation.) dave emery
rminnich@super.ORG (Ronald G Minnich) (02/11/91)
In article <jr5onv9pm@snitor.uucp> doug@snitor.uucp (Doug Moen) writes: >In article <9102080401.AA29237@jumbo.pa.dec.com> gnelson (Greg Nelson) writes: >> ... <discussion of memory allocation> >>The report should have defined this to be a checked runtime error. >>If you want to allocate all available memory without crashing, you >>have to use a lower-level, implementation-dependent interface. >I strongly disagree. The report should have defined this to raise >an exception. It is worth remembering that 13 or so years ago the choice was between a real low-level language (C) and a nicer language (from many points of view) Pascal. It is amazing how similar the arguments are back then and now between, e.g., Mod 3 and C++. Some of them are identical (initialization, for example)! Problem was, Pascal tended to blow your program out of the water on failed file opens, failed memory allocs, and so on. While Pascal was nice from many points of view, its unrealistic model for programming (e.g. if you can't alloc, die) rendered it useless for most people, and, sad to say, C won. I hope the same mistakes are not repeated in Modula 3. Failed memory allocation should be an exception. Just about anything that can go wrong should be able to be handled by the program. ron -- "Socialism is the road from capitalism to communism, but we never promised to feed you on the way!"-- old Russian saying "Socialism is the torturous road from capitalism to capitalism" -- new Russian saying (Wash. Post 9/16)
gnelson (Greg Nelson) (02/12/91)
Doug Moen proposes that Modula-3 define an exception to be raised by NEW when storage is exhausted, arguing that this is necessary in order to write robust programs, such as a text editor that saves edits when storage is exhausted. Eliot Moss and Mick Jordan point out that if this approach is used to provide robust programs, it should probably be extended to many other checked runtime errors, perhaps to all of them. With this approach, the main body of, say, a robust text-editor would use a TRY-EXCEPT: TRY <main body of text editor> EXCEPT RunTimeError(ErrCode) => Wr.PrintText(Stdio.stderr, CodeToMessage(errCode)); Wr.PrintText(Stdio.stderr, "Saving edits..."); <save edits> END Of course, as Dave Emery points out, <save edits> has to be coded very carefully (for example, it must not allocate any storage). In fact, Wr.PrintText might allocate storage, so the TRY-EXCEPT-ELSE code above is useless as it stands. But we can imagine providing a very robust library procedure that prints a TEXT on Stdio.stderr without allocating any storage or depending on anything except the very lowest levels of the runtime system, and use it instead of Wr.PrintText. A more serious problem with the approach is that Modula-3 programs are multi-threaded. The TRY--EXCEPT--END construct above has to be wrapped around every thread, not just the main thread, since storage exhaustion could happen anywhere in the program. The programmer writing the text editor can wrap the TRY--EXCEPT--END around all the threads forked directly by his program, although he might complain that this is awkward. But even this is not enough, since library packages fork background worker threads. For example, the Trestle window system forks two threads to buffer the queue of events from the X server. The Trestle implementation can hardly be expected to wrap the TRY--EXCEPT--END code around the threads that it forks, since the action <save edits> is entirely foreign to Trestle. The solution to these problems is to provide an interface through which clients can register procedures to be executed when a program aborts due to a checked runtime error. A text editor could register a procedure that saves the edits. An elevator control program could provide a procedure that stops the elevator by the most primitive mechanism available. A program development environment could enter the debugger. The design of this interface is quite system-dependent, as these examples suggest, but it should not be difficult to provide a single interface that works in, say, all standard Unix environments. SRC Modula-3 does not yet provide such an interface, but Eric Muller tells me that one is on the way. Greg Nelson
muller@src.dec.com (Eric Muller) (02/12/91)
In article <9102120059.AA15796@jumbo.pa.dec.com>, gnelson (Greg Nelson) writes: > Of course, as Dave Emery points out, <save edits> has to be coded very > carefully (for example, it must not allocate any storage). In fact, > Wr.PrintText might allocate storage, so the TRY-EXCEPT-ELSE code above > is useless as it stands. But we can imagine providing a very robust > library procedure that prints a TEXT on Stdio.stderr without allocating > any storage or depending on anything except the very lowest levels > of the runtime system, and use it instead of Wr.PrintText. The SmallIO interface in the core library will provide that functionality in SRC Modula-3 1.6. > The design of this interface is quite system-dependent, > as these examples suggest, but it should not be difficult to provide > a single interface that works in, say, all standard Unix environments. > SRC Modula-3 does not yet provide such an interface, but Eric Muller > tells me that one is on the way. New in RTMisc.i3: TYPE Exitor <: REFANY; PROCEDURE RegisterExitor (p: PROCEDURE (n: INTEGER)): Exitor; (* Registers the procedure p to be executed when Exit is called or when a checked runtime error is dectected; it is passed the argument of Exit, -1 for checked runtime errors. The registered procedures are executed in the reverse order of registration. *) PROCEDURE UnregisterExitor (e: Exitor); (* removes e's procedure from the registered set. *) PROCEDURE Exit (n: INTEGER); (* call the registered exitors and terminate the program with status 'n' *) -- Eric.
weikart@prl.dec.com (Chris Weikart) (02/12/91)
In article <42601@super.ORG> rminnich@super.ORG (Ronald G Minnich) writes: > It is worth remembering that 13 or so years ago the choice was > between a real low-level language (C) and a nicer language (from many > points of view) Pascal. It is amazing how similar the arguments > are back then and now between, e.g., Mod 3 and C++. Some of them > are identical (initialization, for example)! > > Problem was, Pascal tended to blow your > program out of the water on failed file opens, failed memory allocs, > and so on. While Pascal was nice from many points of view, its > unrealistic model for programming (e.g. if you can't alloc, die) > rendered it useless for most people, and, sad to say, C won. It wasn't so simple. Pascal "lost" partly because of various rigidities, but mostly because of U*ix.
Mike_Spreitzer.PARC@xerox.com (02/13/91)
Installing global failure-handlers will solve some problems, but how does it solve the following? Imagine a bitmap editor program. It allows the user to open multiple windows on bitmaps from multiple files. At one point, with some windows already open, a user asks to open a new window on the 23 megabyte contents of a particular file. Wouldn't it be nice if the editor could say something like "I'm sorry, I can't now edit a new bitmap that big", rather than "Memory exhausted, saving all files and exiting..." ? If we can only register procedures to do a little work before the editor aborts, I don't see a good way to get the desired behavior. Mike
macrakis@gr.osf.org (Stavros Macrakis) (02/13/91)
In article <9102120059.AA15796@jumbo.pa.dec.com> gnelson (Greg Nelson) writes:
Doug Moen proposes that Modula-3 define an exception to be raised
by NEW when storage is exhausted.... Of course, as Dave Emery
points out, [the exception handler] has to be coded very
carefully.... [Discussion of multithreading problems...]
The solution to these problems is to provide an interface through which
clients can register procedures to be executed when a program aborts
due to a checked runtime error....
There are many cases where running out of memory is not a fatal error
which should give rise only to cleanup activities. In particular, in
interactive systems, the execution of a given command may exhaust
memory, and thus have to be aborted, although the overall interactive
environment should recover gracefully.
An even simpler case: some network protocols include requests to
allocate buffers of given size. If the buffer allocation fails, you
should send a NACK to the requester, not die.
-s
Stavros Macrakis
Open Software Foundation Research Institute
Mail: 2 av de Vignate, 38610 Gieres (Grenoble), France
Net: macrakis@gr.osf.org
Phone: +33/76.63.48.82 Fax: +33/76.51.05.32