Revision: 54866
          http://brlcad.svn.sourceforge.net/brlcad/?rev=54866&view=rev
Author:   brlcad
Date:     2013-03-26 01:40:38 +0000 (Tue, 26 Mar 2013)
Log Message:
-----------
restore stdout and stderr when we're done with the GUI by capturing them with a 
dup() call and then later restoring back with dup2().  this fixes a problem 
where an atexit() callback couldn't write out anything during shutdown 
(SIGPIPE) because Tcl had destroyed the channel we set up.  document and 
descope a couple of the globals while we're at it.  untested, but this should 
work fine on windows as well because dup/dup2 are c89 and msdn-supported.  
begging for some _WIN32 cleanup consolidation (the duplication seems 
unnecessary).

Modified Paths:
--------------
    brlcad/trunk/src/mged/mged.c

Modified: brlcad/trunk/src/mged/mged.c
===================================================================
--- brlcad/trunk/src/mged/mged.c        2013-03-26 00:22:49 UTC (rev 54865)
+++ brlcad/trunk/src/mged/mged.c        2013-03-26 01:40:38 UTC (rev 54866)
@@ -120,12 +120,23 @@
 /* should only be accessed via INTERP define in mged.h */
 Tcl_Interp *ged_interp = (Tcl_Interp *)NULL;
 
-int pipe_out[2];
-int pipe_err[2];
+/* these two file decriptors are where we store fileno(stdout) and
+ * fileno(stderr) during graphical startup so that we may restore them
+ * when we're done (which is needed so atexit() calls to bu_log() will
+ * still work).
+ */
+static int stdfd[2] = {1, 2};
+
+/* FIXME: these are problematic globals */
 struct ged *gedp = GED_NULL;
 struct db_i *dbip = DBI_NULL;  /* database instance pointer */
 struct rt_wdb *wdbp = RT_WDB_NULL;
+
+/* called by numerous functions to indicate truthfully whether the
+ * views need to be redrawn.
+ */
 int update_views = 0;
+
 int (*cmdline_hook)() = NULL;
 jmp_buf jmp_env;               /* For non-local gotos */
 double frametime;              /* time needed to draw last frame */
@@ -1024,13 +1035,18 @@
 }
 
 
-
 /*
  * M A I N
  */
 int
 main(int argc, char *argv[])
 {
+    /* pipes used for setting up read/write channels during graphical
+     * initialization.
+     */
+    int pipe_out[2];
+    int pipe_err[2];
+
     int rateflag = 0;
     int c;
     int read_only_flag=0;
@@ -1447,12 +1463,15 @@
         */
 
        if (classic_mged) {
+           /* start up a text command console */
 
            if (!run_in_foreground && use_pipe) {
                notify_parent_done(parent_pipe[1]);
            }
 
        } else {
+           /* start up the GUI */
+
            struct bu_vls vls = BU_VLS_INIT_ZERO;
            int status;
 
@@ -1505,8 +1524,10 @@
 
            } else {
 
-               /* close out stdout/stderr as we're proceeding in GUI mode */
 #ifdef HAVE_PIPE
+               /* we're going to close out stdout/stderr as we
+                * proceed in GUI mode, so create some pipes.
+                */
                result = pipe(pipe_out);
                if (result == -1)
                    perror("pipe");
@@ -1515,6 +1536,9 @@
                    perror("pipe");
 #endif  /* HAVE_PIPE */
 
+               /* since we're in GUI mode, display any bu_bomb()
+                * calls in text dialog windows.
+                */
                bu_bomb_add_hook(mged_bomb_hook, INTERP);
            } /* status -- gui initialized */
        } /* classic */
@@ -1585,32 +1609,48 @@
 #endif
     } else {
        struct bu_vls vls = BU_VLS_INIT_ZERO;
+       int sout = fileno(stdout);
+       int serr = fileno(stderr);
 
+       /* stash stdout */
+       stdfd[0] = dup(sout);
+       if (stdfd[0] == -1)
+           perror("dup");
+
+       /* stash stderr */
+       stdfd[1] = dup(serr);
+       if (stdfd[1] == -1)
+           perror("dup");
+
        bu_vls_printf(&vls, "output_hook output_callback");
        Tcl_Eval(INTERP, bu_vls_addr(&vls));
        bu_vls_free(&vls);
 
+/* FIXME: windows has dup() and dup2(), so this should work there too */
 #if !defined(_WIN32) || defined(__CYGWIN__)
        {
            ClientData outpipe, errpipe;
 
-           /* Redirect stdout */
-           (void)close(1);
+           (void)close(fileno(stdout));
+
+           /* since we just closed stdout, fd 1 is what dup() should return */
            result = dup(pipe_out[1]);
            if (result == -1)
                perror("dup");
-           (void)close(pipe_out[1]);
+           (void)close(pipe_out[1]); /* only a write pipe */
 
-           /* Redirect stderr */
-           (void)close(2);
+           (void)close(fileno(stderr));
+
+           /* since we just closed stderr, fd 2 is what dup() should return */
            result = dup(pipe_err[1]);
            if (result == -1)
                perror("dup");
-           (void)close(pipe_err[1]);
+           (void)close(pipe_err[1]); /* only a write pipe */
 
            outpipe = (ClientData)(size_t)pipe_out[0];
            chan = Tcl_MakeFileChannel(outpipe, TCL_READABLE);
            Tcl_CreateChannelHandler(chan, TCL_READABLE, std_out_or_err, 
outpipe);
+
            errpipe = (ClientData)(size_t)pipe_err[0];
            chan = Tcl_MakeFileChannel(errpipe, TCL_READABLE);
            Tcl_CreateChannelHandler(chan, TCL_READABLE, std_out_or_err, 
errpipe);
@@ -2431,6 +2471,7 @@
     char place[64];
     struct dm_list *p;
     struct cmd_list *c;
+    int ret;
 
     (void)sprintf(place, "exit_status=%d", exitcode);
 
@@ -2457,8 +2498,15 @@
     /* no longer send bu_log() output to Tcl */
     bu_log_delete_hook(gui_output, (genptr_t)INTERP);
 
-    /* restore stdout/stderr */
-    /* !!! */
+    /* restore stdout/stderr just in case anyone tries to write before
+     * we finally exit (e.g., an atexit() callback).
+     */
+    ret = dup2(stdfd[0], fileno(stdout));
+    if (ret == -1)
+       perror("dup2");
+    ret = dup2(stdfd[1], fileno(stderr));
+    if (ret == -1)
+       perror("dup2");
 
     /* Be certain to close the database cleanly before exiting */
     Tcl_Preserve((ClientData)INTERP);

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Own the Future-Intel® Level Up Game Demo Contest 2013
Rise to greatness in Intel's independent game demo contest.
Compete for recognition, cash, and the chance to get your game 
on Steam. $5K grand prize plus 10 genre and skill prizes. 
Submit your demo by 6/6/13. http://p.sf.net/sfu/intel_levelupd2d
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to