changeset 16485:8b783661e03f

improve exit sequence for GUI * octave-link.h, octave-link.cc (octave_link::accepting_events): Delete variable and all uses. (octave_link::link_enabled): New data member. (octave_link::octave_link): Don't set octave_exit. Initialize link_enabled. (octave_link::do_exit): Delete definition. Now pure virtual. Return bool. (octave_link::exit): Call instance->do_exit. (octave_link::enabled): New function. (ocave_link::process_events): New arg, disable. Optionally disable event processing. Use octave_link::enabled instead of instance_ok everywhere except for octave_link::exit. (octave_link::cleanup_instance): Delete. * octave-qt-link.h, octave-qt-link.cc (octave_qt_link::octave_qt_link): Accept thread as argument. Don't connect main_thread::finished signal. (octave_qt_link::~octave_qt_link): Don't delete main_thread. (octave_qt_link::do_exit): Emit exit_signal and return true. (octave_qt_link::exit_signal: New signal. (octave_qt_link::void octave_thread_finished_signal): Delete. * main-window.h, main-window.cc (main_window::_octave_main_thread): New member variable. (main_window::main_window): Initialize _octave_main_thread and _octave_qt_link to 0. (main_window::~main_window): Don't call octave_link::connect_link. Delete _octave_main_thread. (main_window::exit): Accept exit status as argument and call QApplication::exit instead of quit. (main_window::construct): Don't connect qApp::aboutToQuit to main_window::prepare_to_exit. (main_window::construct_octave_qt_link): Create _octave_main_thread and pass to _octave_qt_link. Don't connect _octave_qt_link::octave_thread_finished to main_window::exit. Connect _octave_qt_link::exit_signal to main_window::exit. * toplev.h, toplev.cc (main_loop): If quitting_gracefully, just return exit status instead of calling clean_up_and_exit. (do_octave_atexit): Now static. Call octave_link::process_events with disable arg set to true. (octave_atexit_functions): Now static. (clean_up_and_exit): New argument, safe_to_return. Call octave_link::exit and possibly return or wait for octave_link::exit to terminate the process. * octave.cc (octave_execute_interpreter): Don't alter return value from main_loop. Pass safe_to_return = true to clean_up_and_exit. Return retval instead of 0. (octave_initialize_interpreter): Don't call atexit.
author John W. Eaton <jwe@octave.org>
date Tue, 09 Apr 2013 23:08:24 -0400
parents fa842e78f491
children b1b8a963f095
files libgui/src/main-window.cc libgui/src/main-window.h libgui/src/octave-qt-link.cc libgui/src/octave-qt-link.h libinterp/interpfcn/octave-link.cc libinterp/interpfcn/octave-link.h libinterp/interpfcn/toplev.cc libinterp/interpfcn/toplev.h libinterp/octave.cc
diffstat 9 files changed, 204 insertions(+), 197 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/main-window.cc	Tue Apr 09 23:08:21 2013 -0400
+++ b/libgui/src/main-window.cc	Tue Apr 09 23:08:24 2013 -0400
@@ -70,7 +70,9 @@
     file_browser_window (new files_dock_widget (this)),
     doc_browser_window (new documentation_dock_widget (this)),
     editor_window (create_default_editor (this)),
-    workspace_window (new workspace_view (this))
+    workspace_window (new workspace_view (this)),
+    _octave_main_thread (0),
+    _octave_qt_link (0)
 {
   // We have to set up all our windows, before we finally launch octave.
   construct ();
@@ -78,23 +80,18 @@
 
 main_window::~main_window (void)
 {
-+  // Destroy the terminal first so that STDERR stream is redirected back
-+  // to its original pipe to capture error messages at exit.
+  // Destroy the terminal first so that STDERR stream is redirected back
+  // to its original pipe to capture error messages at exit.
 
   delete command_window;
-  delete _workspace_model;
-  delete status_bar;
-  delete history_window;
-  delete file_browser_window;
-  delete doc_browser_window;
+  delete workspace_window;
   delete editor_window;
-  delete workspace_window;
-
-  // Clean up all dynamically created objects to ensure they are
-  // deleted before this main_window is.  Otherwise, some will be
-  // attached to a non-existent parent.
-
-  octave_link::connect_link (0);
+  delete doc_browser_window;
+  delete file_browser_window;
+  delete history_window;
+  delete status_bar;
+  delete _workspace_model;
+  delete _octave_main_thread;
   delete _octave_qt_link;
 }
 
@@ -266,9 +263,9 @@
 }
 
 void
-main_window::exit (void)
+main_window::exit (int status)
 {
-  qApp->quit ();
+  qApp->exit (status);
 }
 
 void
@@ -545,9 +542,6 @@
 
   construct_tool_bar ();
 
-  connect (qApp, SIGNAL (aboutToQuit ()),
-           this, SLOT (prepare_to_exit ()));
-
   connect (this, SIGNAL (settings_changed (const QSettings *)),
            this, SLOT (notice_settings (const QSettings *)));
 
@@ -592,10 +586,12 @@
 void
 main_window::construct_octave_qt_link (void)
 {
-  _octave_qt_link = new octave_qt_link ();
+  _octave_main_thread = new octave_main_thread ();
 
-  connect (_octave_qt_link, SIGNAL (octave_thread_finished ()),
-           this, SLOT (exit ()));
+  _octave_qt_link = new octave_qt_link (_octave_main_thread);
+
+  connect (_octave_qt_link, SIGNAL (exit_signal (int)),
+           this, SLOT (exit (int)));
 
   connect (_octave_qt_link,
            SIGNAL (set_workspace_signal
--- a/libgui/src/main-window.h	Tue Apr 09 23:08:21 2013 -0400
+++ b/libgui/src/main-window.h	Tue Apr 09 23:08:24 2013 -0400
@@ -92,7 +92,7 @@
   void show_about_octave (void);
   void notice_settings (const QSettings *settings);
   void prepare_to_exit (void);
-  void exit (void);
+  void exit (int status);
   void reset_windows (void);
 
   void change_directory (const QString& dir);
@@ -206,6 +206,8 @@
   static const int current_directory_max_count = 16;
   QLineEdit *_current_directory_line_edit;
 
+  octave_main_thread *_octave_main_thread;
+
   octave_qt_link *_octave_qt_link;
 
   // Flag for closing whole application.
--- a/libgui/src/octave-qt-link.cc	Tue Apr 09 23:08:21 2013 -0400
+++ b/libgui/src/octave-qt-link.cc	Tue Apr 09 23:08:24 2013 -0400
@@ -34,17 +34,11 @@
 
 #include "octave-qt-link.h"
 
-octave_qt_link::octave_qt_link (void)
-  : octave_link (), main_thread (new octave_main_thread)
-{
-  connect (main_thread, SIGNAL (finished ()),
-           this, SIGNAL (octave_thread_finished ()));
-}
+octave_qt_link::octave_qt_link (octave_main_thread *mt)
+  : octave_link (), main_thread (mt)
+{ }
 
-octave_qt_link::~octave_qt_link (void)
-{
-  delete main_thread;
-}
+octave_qt_link::~octave_qt_link (void) { }
 
 void
 octave_qt_link::execute_interpreter (void)
@@ -53,6 +47,14 @@
 }
 
 bool
+octave_qt_link::do_exit (int status)
+{
+  emit exit_signal (status);
+
+  return true;
+}
+
+bool
 octave_qt_link::do_edit_file (const std::string& file)
 {
   emit edit_file_signal (QString::fromStdString (file));
--- a/libgui/src/octave-qt-link.h	Tue Apr 09 23:08:21 2013 -0400
+++ b/libgui/src/octave-qt-link.h	Tue Apr 09 23:08:24 2013 -0400
@@ -49,12 +49,14 @@
 
 public:
 
-  octave_qt_link (void);
+  octave_qt_link (octave_main_thread *mt);
 
   ~octave_qt_link (void);
 
   void execute_interpreter (void);
 
+  bool do_exit (int status);
+
   bool do_edit_file (const std::string& file);
 
   void do_change_directory (const std::string& dir);
@@ -91,6 +93,8 @@
 
 signals:
 
+  void exit_signal (int status);
+
   void edit_file_signal (const QString& file);
 
   void change_directory_signal (const QString& dir);
@@ -115,8 +119,6 @@
 
   void insert_debugger_pointer_signal (const QString&, int);
   void delete_debugger_pointer_signal (const QString&, int);
-
-  void octave_thread_finished (void);
 };
 
 #endif
--- a/libinterp/interpfcn/octave-link.cc	Tue Apr 09 23:08:21 2013 -0400
+++ b/libinterp/interpfcn/octave-link.cc	Tue Apr 09 23:08:24 2013 -0400
@@ -50,11 +50,9 @@
 
 octave_link::octave_link (void)
   : event_queue_mutex (new octave_mutex ()), gui_event_queue (),
-    debugging (false), accepting_events (true)
+    debugging (false), link_enabled (true)
 {
   command_editor::add_event_hook (octave_readline_hook);
-
-  octave_exit = octave_link::exit;
 }
 
 // OBJ should be an object of a class that is derived from the base
@@ -95,20 +93,6 @@
   event_queue_mutex->unlock ();
 }
 
-void
-octave_link::do_exit (int)
-{
-  accepting_events = false;
-
-  do_process_events ();
-}
-
-bool
-octave_link::instance_ok (void)
-{
-  return instance != 0;
-}
-
 DEFUN (__octave_link_edit_file__, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} __octave_link_edit_file__ (@var{file})\n\
--- a/libinterp/interpfcn/octave-link.h	Tue Apr 09 23:08:21 2013 -0400
+++ b/libinterp/interpfcn/octave-link.h	Tue Apr 09 23:08:24 2013 -0400
@@ -53,118 +53,130 @@
 
   static void generate_events (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_generate_events ();
   }
 
-  static void process_events (void)
+  // If disable is TRUE, then no additional events will be processed
+  // other than exit.
+
+  static void process_events (bool disable = false)
   {
-    if (instance_ok ())
-      instance->do_process_events ();
+    if (enabled ())
+      {
+        if (disable)
+          instance->link_enabled = false;
+
+        instance->do_process_events ();
+      }
   }
 
   static void discard_events (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_discard_events ();
   }
 
-  static void exit (int status)
+  static bool exit (int status)
   {
+    bool retval = false;
+
     if (instance_ok ())
-      instance->do_exit (status);
+      retval = instance->do_exit (status);
+
+    return retval;
   }
 
   template <class T>
   static void post_event (T *obj, void (T::*method) (void))
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_post_event (obj, method);
   }
 
   template <class T, class A>
   static void post_event (T *obj, void (T::*method) (A), A arg)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_post_event (obj, method, arg);
   }
 
   template <class T, class A>
   static void post_event (T *obj, void (T::*method) (const A&), const A& arg)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_post_event (obj, method, arg);
   }
 
   static void entered_readline_hook (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_entered_readline_hook ();
   }
 
   static void finished_readline_hook (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_finished_readline_hook ();
   }
 
   static bool
   edit_file (const std::string& file)
   {
-    return instance_ok () ? instance->do_edit_file (file) : false;
+    return enabled () ? instance->do_edit_file (file) : false;
   }
 
   static void change_directory (const std::string& dir)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_change_directory (dir);
   }
 
   static void set_workspace (const std::list<workspace_element>& ws)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_set_workspace (ws);
   }
 
   static void clear_workspace (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_clear_workspace ();
   }
 
   static void set_history (const string_vector& hist)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_set_history (hist);
   }
 
   static void append_history (const std::string& hist_entry)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_append_history (hist_entry);
   }
 
   static void clear_history (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_clear_history ();
   }
 
   static void pre_input_event (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_pre_input_event ();
   }
 
   static void post_input_event (void)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_post_input_event ();
   }
 
   static void enter_debugger_event (const std::string& file, int line)
   {
-    if (instance_ok ())
+    if (enabled ())
       {
         instance->debugging = true;
 
@@ -174,13 +186,13 @@
 
   static void execute_in_debugger_event (const std::string& file, int line)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_execute_in_debugger_event (file, line);
   }
 
   static void exit_debugger_event (void)
   {
-    if (instance_ok () && instance->debugging)
+    if (enabled () && instance->debugging)
       {
         instance->debugging = false;
 
@@ -191,7 +203,7 @@
   static void
   update_breakpoint (bool insert, const std::string& file, int line)
   {
-    if (instance_ok ())
+    if (enabled ())
       instance->do_update_breakpoint (insert, file, line);
   }
 
@@ -201,15 +213,18 @@
 
   static octave_link *instance;
 
-  static void cleanup_instance (void) { delete instance; instance = 0; }
-
   // No copying!
 
   octave_link (const octave_link&);
 
   octave_link& operator = (const octave_link&);
 
-  static bool instance_ok (void);
+  static bool instance_ok (void) { return instance != 0; }
+
+  static bool enabled (void)
+  {
+    return instance_ok () ? instance->link_enabled : false;
+  }
 
 protected:
 
@@ -220,39 +235,35 @@
   event_queue gui_event_queue;
 
   bool debugging;
-
-  bool accepting_events;
+  bool link_enabled;
 
   void do_generate_events (void);
   void do_process_events (void);
   void do_discard_events (void);
 
-  void do_exit (int status);
-
   template <class T>
   void do_post_event (T *obj, void (T::*method) (void))
   {
-    if (accepting_events)
-      gui_event_queue.add_method (obj, method);
+    gui_event_queue.add_method (obj, method);
   }
 
   template <class T, class A>
   void do_post_event (T *obj, void (T::*method) (A), A arg)
   {
-    if (accepting_events)
-      gui_event_queue.add_method (obj, method, arg);
+    gui_event_queue.add_method (obj, method, arg);
   }
 
   template <class T, class A>
   void do_post_event (T *obj, void (T::*method) (const A&), const A& arg)
   {
-    if (accepting_events)
-      gui_event_queue.add_method (obj, method, arg);
+    gui_event_queue.add_method (obj, method, arg);
   }
 
   void do_entered_readline_hook (void) { }
   void do_finished_readline_hook (void) { }
 
+  virtual bool do_exit (int status) = 0;
+
   virtual bool do_edit_file (const std::string& file) = 0;
 
   virtual void do_change_directory (const std::string& dir) = 0;
--- a/libinterp/interpfcn/toplev.cc	Tue Apr 09 23:08:21 2013 -0400
+++ b/libinterp/interpfcn/toplev.cc	Tue Apr 09 23:08:24 2013 -0400
@@ -57,6 +57,7 @@
 #include "graphics.h"
 #include "input.h"
 #include "lex.h"
+#include "octave-link.h"
 #include "oct-conf.h"
 #include "oct-conf-features.h"
 #include "oct-hist.h"
@@ -614,10 +615,7 @@
           recover_from_exception ();
           octave_stdout << "\n";
           if (quitting_gracefully)
-            {
-              clean_up_and_exit (exit_status);
-              break; // If user has overriden the exit func.
-            }
+            return exit_status;
         }
       catch (octave_execution_exception)
         {
@@ -641,13 +639,120 @@
 
 // Fix up things before exiting.
 
+static std::list<std::string> octave_atexit_functions;
+
+static void
+do_octave_atexit (void)
+{
+  static bool deja_vu = false;
+
+  OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ());
+
+  while (! octave_atexit_functions.empty ())
+    {
+      std::string fcn = octave_atexit_functions.front ();
+
+      octave_atexit_functions.pop_front ();
+
+      OCTAVE_SAFE_CALL (reset_error_handler, ());
+
+      OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0));
+
+      OCTAVE_SAFE_CALL (flush_octave_stdout, ());
+    }
+
+  if (! deja_vu)
+    {
+      deja_vu = true;
+
+      // Process pending events and disasble octave_link event
+      // processing with this call.
+
+      octave_link::process_events (true);
+
+      // Do this explicitly so that destructors for mex file objects
+      // are called, so that functions registered with mexAtExit are
+      // called.
+      OCTAVE_SAFE_CALL (clear_mex_functions, ());
+
+      OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
+
+      // FIXME -- is this needed?  Can it cause any trouble?
+      OCTAVE_SAFE_CALL (raw_mode, (0));
+
+      OCTAVE_SAFE_CALL (octave_history_write_timestamp, ());
+
+      if (! command_history::ignoring_entries ())
+        OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
+
+      OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ());
+
+      OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ());
+
+      OCTAVE_SAFE_CALL (close_files, ());
+
+      OCTAVE_SAFE_CALL (cleanup_tmp_files, ());
+
+      OCTAVE_SAFE_CALL (symbol_table::cleanup, ());
+
+      OCTAVE_SAFE_CALL (sysdep_cleanup, ());
+
+      OCTAVE_SAFE_CALL (flush_octave_stdout, ());
+
+      if (! quitting_gracefully && (interactive || forced_interactive))
+        {
+          octave_stdout << "\n";
+
+          // Yes, we want this to be separate from the call to
+          // flush_octave_stdout above.
+
+          OCTAVE_SAFE_CALL (flush_octave_stdout, ());
+        }
+
+      // Don't call singleton_cleanup_list::cleanup until we have the
+      // problems with registering/unregistering types worked out.  For
+      // example, uncomment the following line, then use the make_int
+      // function from the examples directory to create an integer
+      // object and then exit Octave.  Octave should crash with a
+      // segfault when cleaning up the typinfo singleton.  We need some
+      // way to force new octave_value_X types that are created in
+      // .oct files to be unregistered when the .oct file shared library
+      // is unloaded.
+      //
+      // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ());
+
+      OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ());
+    }
+}
+
 void
-clean_up_and_exit (int retval)
+clean_up_and_exit (int retval, bool safe_to_return)
 {
   do_octave_atexit ();
 
-  if (octave_exit)
-    (*octave_exit) (retval == EOF ? 0 : retval);
+  if (octave_link::exit (retval))
+    {
+      if (safe_to_return)
+        return;
+      else
+        {
+          // What should we do here?  We might be called from some
+          // location other than the end of octave_execute_interpreter,
+          // so it might not be safe to return.
+
+          // We have nothing else to do at this point, and the
+          // octave_link::exit function is supposed to take care of
+          // exiting for us.  Assume that job won't take more than a
+          // day...
+
+          gnulib::sleep (86400);
+        }
+    }
+  else
+    {
+      if (octave_exit)
+        (*octave_exit) (retval == EOF ? 0 : retval);
+    }
 }
 
 DEFUN (quit, args, ,
@@ -992,89 +1097,6 @@
 %!error system (1, 2, 3)
 */
 
-// FIXME -- this should really be static, but that causes
-// problems on some systems.
-std::list<std::string> octave_atexit_functions;
-
-void
-do_octave_atexit (void)
-{
-  static bool deja_vu = false;
-
-  OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ());
-
-  while (! octave_atexit_functions.empty ())
-    {
-      std::string fcn = octave_atexit_functions.front ();
-
-      octave_atexit_functions.pop_front ();
-
-      OCTAVE_SAFE_CALL (reset_error_handler, ());
-
-      OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0));
-
-      OCTAVE_SAFE_CALL (flush_octave_stdout, ());
-    }
-
-  if (! deja_vu)
-    {
-      deja_vu = true;
-
-      // Do this explicitly so that destructors for mex file objects
-      // are called, so that functions registered with mexAtExit are
-      // called.
-      OCTAVE_SAFE_CALL (clear_mex_functions, ());
-
-      OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
-
-      // FIXME -- is this needed?  Can it cause any trouble?
-      OCTAVE_SAFE_CALL (raw_mode, (0));
-
-      OCTAVE_SAFE_CALL (octave_history_write_timestamp, ());
-
-      if (! command_history::ignoring_entries ())
-        OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
-
-      OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ());
-
-      OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ());
-
-      OCTAVE_SAFE_CALL (close_files, ());
-
-      OCTAVE_SAFE_CALL (cleanup_tmp_files, ());
-
-      OCTAVE_SAFE_CALL (symbol_table::cleanup, ());
-
-      OCTAVE_SAFE_CALL (sysdep_cleanup, ());
-
-      OCTAVE_SAFE_CALL (flush_octave_stdout, ());
-
-      if (! quitting_gracefully && (interactive || forced_interactive))
-        {
-          octave_stdout << "\n";
-
-          // Yes, we want this to be separate from the call to
-          // flush_octave_stdout above.
-
-          OCTAVE_SAFE_CALL (flush_octave_stdout, ());
-        }
-
-      // Don't call singleton_cleanup_list::cleanup until we have the
-      // problems with registering/unregistering types worked out.  For
-      // example, uncomment the following line, then use the make_int
-      // function from the examples directory to create an integer
-      // object and then exit Octave.  Octave should crash with a
-      // segfault when cleaning up the typinfo singleton.  We need some
-      // way to force new octave_value_X types that are created in
-      // .oct files to be unregistered when the .oct file shared library
-      // is unloaded.
-      //
-      // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ());
-
-      OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ());
-    }
-}
-
 void
 octave_add_atexit_function (const std::string& fname)
 {
--- a/libinterp/interpfcn/toplev.h	Tue Apr 09 23:08:21 2013 -0400
+++ b/libinterp/interpfcn/toplev.h	Tue Apr 09 23:08:24 2013 -0400
@@ -52,16 +52,13 @@
 extern OCTINTERP_API int exit_status;
 
 extern OCTINTERP_API void
-clean_up_and_exit (int);
+clean_up_and_exit (int status, bool safe_to_return = false);
 
 extern OCTINTERP_API void recover_from_exception (void);
 
 extern OCTINTERP_API int main_loop (void);
 
 extern OCTINTERP_API void
-do_octave_atexit (void);
-
-extern OCTINTERP_API void
 octave_add_atexit_function (const std::string& fname);
 
 extern OCTINTERP_API bool
--- a/libinterp/octave.cc	Tue Apr 09 23:08:21 2013 -0400
+++ b/libinterp/octave.cc	Tue Apr 09 23:08:24 2013 -0400
@@ -891,12 +891,6 @@
   if (no_window_system)
     display_info::no_window_system ();
 
-  // Make sure we clean up when we exit.  Also allow users to register
-  // functions.  If we don't have atexit or on_exit, we're going to
-  // leave some junk files around if we exit abnormally.
-
-  atexit (do_octave_atexit);
-
   // Is input coming from a terminal?  If so, we are probably
   // interactive.
 
@@ -1008,14 +1002,11 @@
 
   int retval = main_loop ();
 
-  if (retval == 1 && ! error_state)
-    retval = 0;
-
   quitting_gracefully = true;
 
-  clean_up_and_exit (retval);
+  clean_up_and_exit (retval, true);
 
-  return 0;
+  return retval;
 }
 
 static bool