[M3devel] proposal for dealing with lazy console--please review and comment!

Olaf Wagner wagner at elegosoft.com
Fri Jun 13 15:33:47 CEST 2008


Hi Randy,

thanks for the excellent summary. I'm not totally against your suggested
extensions; I only try to avoid the additional variables (though they
may be in the spirit of the interface).

You need three additional boolean variables in Stdio.i3 to determine
if one of them is lazy. If instead we had a class LazyConsoleWr.T
as a subclass of Wr.T, it could be assigned to the existing
Stdio.stdout variable on Windows. The only addition of this type
could be the boolean function isVisible().

You could then check for the `lazyness' of the writer by calling
ISTYPE( Stdio.stdout, LazyConsoleWr.T ), and if that yields true,
determine if the lazy console is visible by NARROW( Stdio.stdout,  
LazyConsoleWr.T ).isVisible().

This would be a more object-oriented approach. I'm not sure if it
really is worth the effort or if we shouldn't just live with the
additional variables though. I'm also not sure if it is feasible
from an implementation point of view, as I haven't had a look at
the initialization code in Windows.

As this hasn't been discussed on the m3devel list, and others
may have interesting opinions on this, I'd like to raise this
issue there, too, in the hope that we agree on a solution soon.
I've added your original proposal at the end for reference.

Best regards,

Olaf

Quoting Randy Coleburn <rcoleburn at scires.com>:

> I agree that adding variables to an interface is not normally a good
> idea, BUT that is the way Stdio is set up currently.  It uses variables
> for stdout, stderr, stdin, and bufferedStderr.  The client is free to
> change these assignments (and indeed I have programs that do) to change
> the runtime behavior.  For example, you can make Stdio.stdout a TeeWr.T
> to get output going to both stdout and a log file at the same time.
>
> Stdio provides Wr.T's for stdout & stderr, and a Rd.T for stdin.  The
> client doesn't really know anything else about them.  I gather that Jay
> is suggesting that I internally subtype these to be something else and
> then externally check for the type, but I don't think this is feasible
> without some interface changes that may break existing code.  (I welcome
> more discussion on this point.)
>
> The problem we have with the whole lazy console allocation issue is
> that the behavior is not documented in an interface and thus there is no
> way to control it.  Indeed, the whole mess is hidden in the LazyConsole
> module buried inside the Win32 subfolder.  For Unix, there is no such
> thing as lazy console allocation and indeed it is possible for one of
> the Stdout variables to be NIL.  On cm3 v4.1, it is also possible for
> one of the Stdout variables to be NIL, especially when the program is a
> GUI-mode program.
>
> So from a platform-independent view, we currently (cm3 v d5.7.0) have
> the following four possibilities for each of the Stdio variables:
> 1.  variable represents a valid writer/reader to an allocated console
> window (or other file/device if command line redirection or pipelining
> is used);
> 2.  variable represents a lazy-allocated console window that is not yet
> visible;
> 3.  variable represents a lazy-allocated console window that has popped
> up on the screen (probably occluding part of the real gui window);
> 4.  variable is NIL because the process has no standard file handle of
> this type (but only if not running on Windows).
>
> Since the lazy-allocation is hidden from view, the client code has no
> way of knowing reliably at runtime which of the 4 states the program is
> in, and on Windows the state can change dynamically from #2 to #3 (it is
> not constant as when on Unix).
>
> On cm3 v4.1, states #2 & #3 did not exist, so clients could simply
> check if the variable was NIL to know whether I/O to the Stdout
> variables would work.  But now, on cm3 v5.7 there is no way to make this
> check reliably on all platforms because on Windows state #4 cannot exist
> and states #2 and #3 are hidden from the programmer.  Further, since
> this behavior is not documented in an interface, the change from 4.1 to
> 5.7 breaks existing 4.1 code.  When I say "breaks" I don't mean
> necessarily that the program crashes, but rather that the behavior is
> different than expected and thus "broken".
>
> Now the primary advantage (possibly the only advantage) to the new lazy
> console allocation scheme on Windows is that your GUI-mode program won't
> crash if you write to stdout without ensuring it is non-NIL.  (Maybe
> this begs the question of whether the lazy-allocation is really
> needed.)
>
> The proposal I made has the following advantages:
> A.  It does not break any existing code.
> B.  It keeps the same spirit of Stdio in terms of using variables.
> C.  It gives programmers the opportunity to prevent or allow the lazy
> pop-up console windows.
> D.  If programmers don't make a choice about the lazy pop-up windows,
> there is no change in behavior from current operation.
> E.  It works on Unix or Windows (thus is platform-independent)
> F.  It allows programmers to go back and easily adjust old code built
> for cm3 v4.1 to work as expected when built using cm3 5.7.
>
> The proposal has the following disadvantages:
> X.  It continues the practice of putting variables in an interface
> (assuming this practice is frowned upon)
> Y.  Since it augments two prominent interfaces (Stdio & Process), it
> will require rebuilding of everything.
> Z.  Programmers using features of the revised interfaces won't be able
> to compile their code using older versions of cm3.
>
> Here is a quick example showing the utility of knowing at runtime about
> the lazy allocation:  Suppose you have a -GUI mode program.  There is a
> lot of code in libraries et al that expects to write to stdout to
> provide error messages, etc.  If the user calls my -GUI program with the
> wrong arguments, I want to give him an error message.  In the current
> situation on Windows, if I write to stdout or stderr, I will get a
> pop-up console window that will flash up briefly, but disappear as soon
> as the program terminates.  On Unix, the behavior is different since
> there is no pop-up console window.  If I knew at runtime that the
> stdout/stderr was lazy-allocated, I could pause for a few seconds to
> allow the user to see the error message on the pop-up console, or I
> could redirect the message to a file, or I could even require the user
> to acknowledge the pop-up console message by pressing Enter on the
> keyboard before terminating the program.  I could also choose not to
> send output to stdout when the console is lazy-allocated and thus
> prevent an extra icon from showing up in the task bar.  In short, I
> believe the lazy-allocation needs to be exposed so programmers can deal
> with it appropriately for the operating context of their program.
>
> If you don't want to go the route of my proposal, I'm welcome to hear
> another suggestion on how to expose runtime knowledge of the lazy
> allocation.
>
> Regards,
> Randy

Original proposal:

1.  Add procedure
     AreStdFileHandlesLazy (VAR stdIn_IsLazy, stdOut_IsLazy,  
stdErr_IsLazy: BOOLEAN)
to interface Process.  This won't break any existing code since it is  
a new procedure addition, but it will force rebuilding of everything.

2.  Adjust internals of Process implementations to deal with  
implementation of this new procedure.  The procedure's parameter  
output values for all platforms will be FALSE, except for Windows  
where they will depend on whether the file is lazily allocated.  These  
changes will be transparent to all clients.

3.  Add following variables to Stdio interface:
     stdIn_IsLazy, stdOut_IsLazy, stdErr_IsLazy: BOOLEAN;
This change won't break any existing code, but it will force  
rebuilding of everything.

4.  Modify Stdio implementation to properly initialize the new  
variables during module initialization.
This change will be transparent to all clients.

Now, with these changes, it will be possible for a client to know  
whether stdout, stderr, and/or stdin represent lazily allocated  
consoles or not, then act accordingly.

For example, if I want to make sure messages written to stdout are  
recorded even for a GUI-app, but I don't want a popup, I could do the  
following:
    IF (Stdio.stdOut_IsLazy) OR (Stdio.stdout = NIL)
    THEN
       Stdio.stdout := FileWr.Open("myLogFile.txt");
       Stdio.stdOut_IsLazy := FALSE;
    END;
Now the above code fragment does show the possibility of a race  
condition in multi-threaded code.  I suggest that a comment be added  
to the Stdio interface that states any manipulation of the exposed  
variables should be done from single-threaded code or that the client  
should implement use of a mutex.  Otherwise, we could change Stdio to  
have get/set procedures, but that would break a lot of existing code.   
Indeed, instead of changing the Stdio interface, it would be better  
IMO to just provide an extra interface/implementation that provides  
these functions and tell new multi-threaded clients to use the  
thread-friendly version.

Please let me know what you think about this proposal.  If it is okay,  
I'd like to go ahead and make the changes to the repository, including  
adding a warning comment about thread friendliness.  I won't provide  
the extra thread-friendly interface/implementation of Stdio unless you  
want it.

Now that I think about it, I should also add the following function  
procedures to Stdio (3 variants, one each for stdout, stderr, and  
stdin) and that would probably eliminate need for the thread-friendly  
interface:
    PROCEDURE EnsureNotLazyStdOut (alternateWr: Wr.T) : BOOLEAN =
    (* If stdout is NIL or lazily allocated, replace it by  
alternateWr, which must be a valid writer (non-nil).  Returns TRUE if  
alternateWr is substituted for stdout; otherwise returns FALSE.  Note  
that this function is thread-safe. *)
    BEGIN
       <*ASSERT alternateWr # NIL*>
       LOCK privateMutex DO
          IF (Stdio.stdOut_IsLazy) OR (Stdio.stdout = NIL)
          THEN
             Stdio.stdout := alternateWr;
             Stdio.stdOut_IsLazy := FALSE;
             RETURN TRUE;
          ELSE
             RETURN FALSE;
          END;
       END;
    END EnsureNotLazyStdOut;

-- 
Olaf Wagner -- elego Software Solutions GmbH
                Gustav-Meyer-Allee 25 / Gebäude 12, 13355 Berlin, Germany
phone: +49 30 23 45 86 96  mobile: +49 177 2345 869  fax: +49 30 23 45 86 95
    http://www.elegosoft.com | Geschäftsführer: Olaf Wagner | Sitz: Berlin
Handelregister: Amtsgericht Charlottenburg HRB 77719 | USt-IdNr: DE163214194




More information about the M3devel mailing list