octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: signals hanling in octave


From: John W. Eaton
Subject: Re: signals hanling in octave
Date: Fri, 20 Oct 2006 12:54:16 -0400

On 19-Oct-2006, Paul Kienzle wrote:

| On Oct 19, 2006, at 4:21 PM, Miroslaw Dach wrote:
| 
| > Dear All,
| >
| >   I am using mex program under octave. The only missing function in 
| > octave 2.9.9 implementation (which I need to use) is mexAtExit.
| > This function registers the handler function which is call before 
| > exiting from Matlab. As the replacement of that function on octave I 
| > have tried to use atexit but my function is not call as the first one 
| > before closing the octave and octave simply stalls. John has  
| > suggested to me to add the pointer in the octave_mex_function class 
| > but i am not so familiar with octave code. I was just playing with the 
| > standard c signal function to register my handler but I do not know 
| > which signal is sent when octave quits.
| >
| > I would appreciate very much is somebody could help me on that.
| >
| 
| The functions you are interested in are in the src directory.
| 
|      ov-fcn.h    -  base octave function class
|      ov-mex-fcn.{cc,h}  - mex function class
|      mex.h, mex.cc   - mex function definitions
| 
| One thing you could do is hook into the destructor in ov-mex-fcn.cc. 
| Just before removing the function, you can call the 'exit_fcn_ptr' 
| handle if it is not 0.  This handle would be stored in the 
| octave_mex_function class along with mex_fcn_ptr.  Don't forget to 
| initialize it to 0.  Add an at_exit(fcn) method to octave_mex_function 
| which sets exit_fcn_ptr.

Yes, this is what I was thinking about doing.  You need to do it this
way rather than just with atexit, because the function registered with
mexAtExit needs to be called when the mex function is cleared, not
just when Octave exits.

The difficulty I see is that the order of calls to the destructors is
unpredictible, so there could be trouble if some other function
registered with Octave's atexit function mexAtExit calls a mex
function that has already been cleared.  Then that function must be
reloaded for the call to succeed.  What happens to "clear all" in that
case?

For example, if we have

  void mex_2_cleanup (void)
  {
    mxArray *argout[1];
    mexCallMATLAB (0, mxArray *argout[], 0, 0, "mex1");
  }

and we register this function with mexAtExit in mex2.c, then when
clear all is issued, if mex2 is deleted before mex1, all is well.  But
if mex1 is deleted first, then when mex2 is deleted, mex1 must be
reloaded.  Should Octave try to be smart enough to deal with this
situation, or should we just leave it up to the user to be smart
enough to not do stupid things?  What does Matlab do?  Does it matter?

| In class mex defined in mex.cc you will need to define an at_exit(fcn) 
| method which sets the exit_fcn_handle of the octave_mex_function 
| object.  mexAtExit(fcn) is then a call to mex_context->at_exit(fcn).
| 
| Writing mex::at_exit(fcn) will be a bit tricky.
| 
| The clean way would be to pass a pointer to the octave_function handle 
| 'this' through C_mex or Fortran_mex.  Store this handle in class mex 
| when it is created.  It can then be used directly by function_name and 
| at_exit to access octave_mex_function.

It doesn't seem that this would be too difficult, so I think we
should implement it this way.  Here are the changes I checked in,
which uses some of your code.

The patch also includes your callstyle changes because I forgot to
actually check those in before making these additional changes.  Oops.

Thanks,

jwe


src/ChangeLog:

2006-10-20  Paul Kienzle  <address@hidden>

        * ov-mex-fcn.h (octave_mex_function::atexit): New function.
        (octave_mex_function::exit_fcn_ptr): New data member.
        * ov-mex-fcn.cc (octave_mex_function::exit_fcn_ptr): New data member.
        (octave_mex_function::octave_mex_function): Initialize it.
        (octave_mex_function::~octave_mex_function):
        If we have an exit function, call it.

2006-10-20  John W. Eaton  <address@hidden>

        * variables.cc (delete_symbol_tables): New function.
        * variables.h: Provide decl.
        * toplev.cc (do_octave_atexit): Call it.

        * mex.cc (mex::mex): New arg, a pointer to the current mex function.
        (mex::curr_mex_fcn): New data member.
        (mex::current_mex_function): New function.
        (mexAtExit): Set exit function pointer in current mex file object.

2006-10-20  Paul Kienzle  <address@hidden>

        * mex.cc (enum callstyle): Delete enum definition.
        (Fortran_mex, C_mex): Delete functions.
        (call_mex): First arg is now bool.
        * ov-mex-fcn.cc (call_mex): Fix decl to match new definition.
        (Fortran_mex, C_mex): Delete decls.
        (octave_mex_function::do_multi_index_op): Simplify call to call_mex.


Index: src/mex.cc
===================================================================
RCS file: /cvs/octave/src/mex.cc,v
retrieving revision 1.12
diff -u -u -r1.12 mex.cc
--- src/mex.cc  20 Oct 2006 03:03:12 -0000      1.12
+++ src/mex.cc  20 Oct 2006 16:51:44 -0000
@@ -19,6 +19,7 @@
 #include "oct-map.h"
 #include "oct-obj.h"
 #include "ov.h"
+#include "ov-mex-fcn.h"
 #include "ov-usr-fcn.h"
 #include "pager.h"
 #include "parse.h"
@@ -1904,7 +1905,8 @@
 {
 public:
 
-  mex (void) : memlist (), arraylist (), fname (0) { }
+  mex (octave_mex_function *f)
+    : curr_mex_fcn (f), memlist (), arraylist (), fname (0) { }
 
   ~mex (void)
   {
@@ -2098,6 +2100,11 @@
       arraylist.erase (p);
   }
 
+  octave_mex_function *current_mex_function (void) const
+  {
+    return curr_mex_fcn;
+  }
+
   // 1 if error should be returned to MEX file, 0 if abort.
   int trap_feval_error;
 
@@ -2109,6 +2116,9 @@
 
 private:
 
+  // Pointer to the mex function that corresponds to this mex context.
+  octave_mex_function *curr_mex_fcn;
+
   // List of memory resources that need to be freed upon exit.
   std::set<void *> memlist;
 
@@ -2791,26 +2801,10 @@
 typedef void (*cmex_fptr) (int nlhs, mxArray **plhs, int nrhs, mxArray **prhs);
 typedef F77_RET_T (*fmex_fptr) (int& nlhs, mxArray **plhs, int& nrhs, mxArray 
**prhs);
 
-enum callstyle { use_fortran, use_C };
-
 octave_value_list
-call_mex (callstyle cs, void *f, const octave_value_list& args, int nargout)
+call_mex (bool have_fmex, void *f, const octave_value_list& args,
+         int nargout, octave_mex_function *curr_mex_fcn)
 {
-#if 0
-  // Don't bother trapping stop/exit
-  // FIXME -- should really push "mex_exit" onto the octave
-  // atexit stack before we start and pop it when we are through, but
-  // the stack handle isn't exported from toplev.cc, so we can't.  mex_exit
-  // would have to be declared as DEFUN(mex_exit,,,"") of course.
-  static bool unregistered = true;
-
-  if (unregistered)
-    {
-      atexit (mex_exit);
-      unregistered = false;
-    }
-#endif
-
   // Use at least 1 for nargout since even for zero specified args,
   // still want to be able to return an ans.
 
@@ -2829,7 +2823,7 @@
   // Save old mex pointer.
   unwind_protect_ptr (mex_context);
 
-  mex context;
+  mex context (curr_mex_fcn);
 
   unwind_protect::add (mex::cleanup, static_cast<void *> (&context));
 
@@ -2840,7 +2834,7 @@
     {
       mex_context = &context;
 
-      if (cs == use_fortran)
+      if (have_fmex)
        {
          fmex_fptr fcn = FCN_PTR_CAST (fmex_fptr, f);
 
@@ -2881,18 +2875,6 @@
   return retval;
 }
 
-octave_value_list
-Fortran_mex (void *f, const octave_value_list& args, int nargout)
-{
-  return call_mex (use_fortran, f, args, nargout);
-}
-
-octave_value_list
-C_mex (void *f, const octave_value_list& args, int nargout)
-{
-  return call_mex (use_C, f, args, nargout);
-}
-
 // C interface to mex functions:
 
 const char *
@@ -3128,10 +3110,17 @@
 }
 
 int
-mexAtExit (void (*/*f*/) (void))
+mexAtExit (void (*f) (void))
 {
-  // FIXME
-  error ("mexAtExit: not implemented");
+  if (mex_context)
+    {
+      octave_mex_function *curr_mex_fcn = mex_context->current_mex_function ();
+
+      assert (curr_mex_fcn);
+
+      curr_mex_fcn->atexit (f);
+    }
+
   return 0;
 }
 
Index: src/ov-mex-fcn.cc
===================================================================
RCS file: /cvs/octave/src/ov-mex-fcn.cc,v
retrieving revision 1.1
diff -u -u -r1.1 ov-mex-fcn.cc
--- src/ov-mex-fcn.cc   22 Jun 2006 00:57:28 -0000      1.1
+++ src/ov-mex-fcn.cc   20 Oct 2006 16:51:44 -0000
@@ -44,7 +44,8 @@
 octave_mex_function::octave_mex_function
   (void *fptr, bool fmex, const octave_shlib& shl,
    const std::string& nm)
-  : octave_function (nm), mex_fcn_ptr (fptr), have_fmex (fmex), sh_lib (shl)
+  : octave_function (nm), mex_fcn_ptr (fptr), exit_fcn_ptr (0),
+    have_fmex (fmex), sh_lib (shl)
 {
   mark_fcn_file_up_to_date (time_parsed ());
 
@@ -57,6 +58,9 @@
 
 octave_mex_function::~octave_mex_function (void)
 {
+  if (exit_fcn_ptr)
+    (*exit_fcn_ptr) ();
+
   octave_dynamic_loader::remove (my_name, sh_lib);
 }
 
@@ -118,10 +122,8 @@
 }
 
 extern octave_value_list
-C_mex (void *f, const octave_value_list& args, int nargout);
-
-extern octave_value_list
-Fortran_mex (void *f, const octave_value_list& args, int nargout);
+call_mex (bool have_fmex, void *f, const octave_value_list& args,
+         int nargout, octave_mex_function *curr_mex_fcn);
 
 octave_value_list
 octave_mex_function::do_multi_index_op (int nargout,
@@ -142,9 +144,7 @@
 
       unwind_protect::add (octave_call_stack::unwind_pop, 0);
 
-      retval = have_fmex
-       ? Fortran_mex (mex_fcn_ptr, args, nargout)
-       : C_mex (mex_fcn_ptr, args, nargout);
+      retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this);
 
       unwind_protect::run_frame ("mex_func_eval");
     }
Index: src/ov-mex-fcn.h
===================================================================
RCS file: /cvs/octave/src/ov-mex-fcn.h,v
retrieving revision 1.1
diff -u -u -r1.1 ov-mex-fcn.h
--- src/ov-mex-fcn.h    22 Jun 2006 00:57:28 -0000      1.1
+++ src/ov-mex-fcn.h    20 Oct 2006 16:51:44 -0000
@@ -81,10 +81,14 @@
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
 
+  void atexit (void (*fcn) (void)) { exit_fcn_ptr = fcn; }
+
 private:
 
   void *mex_fcn_ptr;
 
+  void (*exit_fcn_ptr) (void);
+
   bool have_fmex;
 
   octave_shlib sh_lib;
Index: src/toplev.cc
===================================================================
RCS file: /cvs/octave/src/toplev.cc,v
retrieving revision 1.187
diff -u -u -r1.187 toplev.cc
--- src/toplev.cc       9 Oct 2006 19:49:04 -0000       1.187
+++ src/toplev.cc       20 Oct 2006 16:51:44 -0000
@@ -617,6 +617,11 @@
     {
       deja_vu = true;
 
+      // Do this explicitly so that destructors for mex file objects
+      // are called, so that functions registered with mexAtExit are
+      // called.
+      delete_symbol_tables ();
+
       command_editor::restore_terminal_state ();
 
       // FIXME -- is this needed?  Can it cause any trouble?
Index: src/variables.cc
===================================================================
RCS file: /cvs/octave/src/variables.cc,v
retrieving revision 1.293
diff -u -u -r1.293 variables.cc
--- src/variables.cc    15 Aug 2006 06:06:16 -0000      1.293
+++ src/variables.cc    20 Oct 2006 16:51:45 -0000
@@ -104,6 +104,14 @@
   curr_caller_sym_tab = curr_sym_tab = top_level_sym_tab;
 }
 
+void
+delete_symbol_tables (void)
+{
+  delete fbi_sym_tab;
+  delete global_sym_tab;
+  delete top_level_sym_tab;
+}
+
 // Attributes of variables and functions.
 
 // Is this a command-style function?
Index: src/variables.h
===================================================================
RCS file: /cvs/octave/src/variables.h,v
retrieving revision 1.86
diff -u -u -r1.86 variables.h
--- src/variables.h     8 May 2006 20:23:07 -0000       1.86
+++ src/variables.h     20 Oct 2006 16:51:45 -0000
@@ -48,6 +48,7 @@
 extern bool at_top_level (void);
 
 extern void initialize_symbol_tables (void);
+extern void delete_symbol_tables (void);
 
 extern bool is_command_name (const std::string&);
 


reply via email to

[Prev in Thread] Current Thread [Next in Thread]