octave-maintainers
[Top][All Lists]
Advanced

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

Re: Threadsafe octave patch


From: John Swensen
Subject: Re: Threadsafe octave patch
Date: Fri, 10 Nov 2006 20:07:49 -0500
User-agent: Thunderbird 1.5.0.8 (Macintosh/20061025)

Has anyone had a chance to glance at this patch? I just want to get some feedback on whether this sort of solution would be an acceptable addition to Octave for ensuring threadsafe interaction between an IDE and the octave internals. As a synopsis, the relevant data is pushed by Octave into a mutex protected buffer at the end of the while loop in the main_loop() funcion in toplevel.cc and in the MAYBE_DO_BREAKPOINT macro in pt-bp.h.

John Swensen

John Swensen wrote:
The attached patch is my first attempt at creating a threadsafe mechanism for my IDE to access octave internals. Currently the following functionalities are implemented:
1) List of variables in scope with name, type, size, etc.
2) Ability to request full variables
3) Request history information

Planned functionality:
Set/clear/step in/step out for breakpoints
Allow this to be turned on and off

Please let me know if this is an acceptable solution or if there are changes you would like me to make before it would be accepted.

John Swensen

------------------------------------------------------------------------

Index: Makefile.in
===================================================================
RCS file: /cvs/octave/src/Makefile.in,v
retrieving revision 1.417
diff -c -p -r1.417 Makefile.in
*** Makefile.in 13 Oct 2006 18:11:27 -0000      1.417
--- Makefile.in 10 Nov 2006 03:28:35 -0000
*************** INCLUDES := Cell.h base-list.h c-file-pt
*** 103,109 ****
        oct-prcstrm.h oct-procbuf.h oct-stdstrm.h oct-stream.h zfstream.h \
        oct-strstrm.h oct-lvalue.h oct.h octave.h ops.h pager.h \
        parse.h pr-output.h procstream.h sighandlers.h siglist.h \
!       sparse-xdiv.h sparse-xpow.h symtab.h sysdep.h \
        token.h toplev.h unwind-prot.h utils.h variables.h version.h \
        xdiv.h xpow.h \
        $(OV_INCLUDES) \
--- 103,109 ----
        oct-prcstrm.h oct-procbuf.h oct-stdstrm.h oct-stream.h zfstream.h \
        oct-strstrm.h oct-lvalue.h oct.h octave.h ops.h pager.h \
        parse.h pr-output.h procstream.h sighandlers.h siglist.h \
!       sparse-xdiv.h sparse-xpow.h symtab.h sysdep.h threadsafe.h \
        token.h toplev.h unwind-prot.h utils.h variables.h version.h \
        xdiv.h xpow.h \
        $(OV_INCLUDES) \
*************** DIST_SRC := Cell.cc bitfcns.cc c-file-pt
*** 174,180 ****
        octave.cc zfstream.cc oct-strstrm.cc oct-lvalue.cc pager.cc \
        parse.y pr-output.cc procstream.cc sighandlers.cc \
        siglist.c sparse-xdiv.cc sparse-xpow.cc strcasecmp.c \
!       strncase.c strfns.cc symtab.cc syscalls.cc sysdep.cc \
        token.cc toplev.cc unwind-prot.cc utils.cc variables.cc \
        xdiv.cc xpow.cc \
        $(OV_SRC) \
--- 174,180 ----
        octave.cc zfstream.cc oct-strstrm.cc oct-lvalue.cc pager.cc \
        parse.y pr-output.cc procstream.cc sighandlers.cc \
        siglist.c sparse-xdiv.cc sparse-xpow.cc strcasecmp.c \
!       strncase.c strfns.cc symtab.cc syscalls.cc sysdep.cc threadsafe.cc \
        token.cc toplev.cc unwind-prot.cc utils.cc variables.cc \
        xdiv.cc xpow.cc \
        $(OV_SRC) \
Index: pt-bp.h
===================================================================
RCS file: /cvs/octave/src/pt-bp.h,v
retrieving revision 1.18
diff -c -p -r1.18 pt-bp.h
*** pt-bp.h     16 Jun 2006 05:09:41 -0000      1.18
--- pt-bp.h     10 Nov 2006 03:28:35 -0000
*************** Software Foundation, Inc., 51 Franklin S
*** 28,33 ****
--- 28,34 ----
  #include "ov-usr-fcn.h"
  #include "pt-walk.h"
  #include "pt-pr-code.h"
+ #include "threadsafe.h"
  #include "toplev.h"
class tree;
*************** extern bool octave_debug_on_interrupt_st
*** 187,192 ****
--- 188,195 ----
   \
            tree::break_statement = this; \
   \
+                 ov_server.process_octave_internals_data(); \
+  \
            do_keyboard (); \
          } \
      } \
Index: threadsafe.cc
===================================================================
RCS file: threadsafe.cc
diff -N threadsafe.cc
*** /dev/null   1 Jan 1970 00:00:00 -0000
--- threadsafe.cc       10 Nov 2006 03:28:35 -0000
***************
*** 0 ****
--- 1,278 ----
+ /*
+ + Copyright (C) 2006 John P. Swensen + + This file is part of Octave. + + Octave is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ + Octave is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ + You should have received a copy of the GNU General Public License
+ along with Octave; see the file COPYING.  If not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ + */ + + #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+ + #include "threadsafe.h"
+ #include "pager.h"
+ #include "errno.h"
+ #include <iostream>
+ #include <sstream>
+ #include <vector>
+ #include <string>
+ using std::ostringstream;
+ using std::cout;
+ using std::endl;
+ using std::vector;
+ using std::string;
+ + octave_server ov_server; + + ///////////////////////////////////////////////////////////////////////////////
+ vector<variable_info_t> create_var_list(void)
+ {
+   static vector<variable_info_t> lastVars;
+   vector<variable_info_t> retval;
+   // This method prints information for sets of symbols, but only one
+   // set at a time (like, for instance: all variables, or all
+   // built-in-functions).
+ + // This method invokes print_symbol_info_line to print info on every
+   // symbol.
+ + //int status = 0; + + // XXX FIXME XXX Should separate argv to lists with and without dots.
+   if ( top_level_sym_tab != NULL )
+   {
+     if ( global_command == 0 )
+     {
+       Array<symbol_record *> xsymbols = top_level_sym_tab->symbol_list ( 
string_vector(), 0xFF, SYMTAB_ALL_SCOPES);
+       Array<symbol_record *> xsubsymbols = top_level_sym_tab->subsymbol_list 
( string_vector(), 0xFF, SYMTAB_ALL_SCOPES);
+ + int sym_len = xsymbols.length (), subsym_len = xsubsymbols.length (),
+                                                      len = sym_len + 
subsym_len;
+ + Array<symbol_record *> symbols (len); + + if (len > 0)
+       {
+         //size_t bytes = 0;
+         //size_t elements = 0;
+ + int i; + + // Joining symbolic tables.
+         for (i = 0; i < sym_len; i++)
+           symbols(i) = xsymbols(i);
+ + for (i = 0; i < subsym_len; i++)
+           symbols(i+sym_len) = xsubsymbols(i);
+       }
+ + for (int j = 0; j < len; j++)
+       {
+         if ( symbols(j)->is_user_variable() )
+         {
+           variable_info_t tempVar;
+           tempVar.variable_name = symbols(j)->name();
+           tempVar.size.push_back( symbols(j)->rows() );
+           tempVar.size.push_back( symbols(j)->columns() );
+           tempVar.byte_size = symbols(j)->byte_size();
+           tempVar.type_name = symbols(j)->type_name();
+ + retval.push_back(tempVar);
+         }
+       }
+ + }
+   }
+   else
+   {
+     std::cout << "Empty top_level_sym_tab: waiting until next iteration" << 
std::endl;
+   }
+ + if ( lastVars != retval )
+   {
+     lastVars = retval;
+     return retval;
+   }
+   else
+   {
+     return vector<variable_info_t>();
+   }
+ + } + + ///////////////////////////////////////////////////////////////////////////////
+ string_vector create_history_list(void)
+ {
+   static int previousLen = 0;
+   int currentLen = command_history::length();
+ + if ( global_command == 0 && currentLen != previousLen )
+   {
+     string_vector hlist;
+     for( int i = previousLen ; i < currentLen ; i++ )
+         hlist.append( command_history::get_entry(i) );
+     previousLen = currentLen;
+     return hlist;
+   }
+   else
+   {
+     return string_vector();
+   }
+ }
+ + ///////////////////////////////////////////////////////////////////////////////
+ octave_server::octave_server( bool startTcpServer )
+ {
+       pthread_mutex_init(&octave_lock_mutex, NULL);
+       
+       if( startTcpServer )
+       {
+               // Begin a TCPIP server so the threadsafe information can be 
accessed via a socket      
+       }
+ }
+ + ///////////////////////////////////////////////////////////////////////////////
+ octave_server::~octave_server( void )
+ {
+       
+ }
+ + + ///////////////////////////////////////////////////////////////////////////////
+ status_t octave_server::process_requested_variables(void)
+ {
+   // Take the list of requested variables
+   requested_variables = std::vector<octave_value>();
+   for( unsigned int i = 0 ; i < variables_request_list.size() ; i++ )
+   {
+     symbol_record* rec = top_level_sym_tab->lookup( 
variables_request_list[i], false, false );     
+     octave_value temp( rec->def() );
+     requested_variables.push_back( temp );
+ } + variables_request_list = std::vector<std::string>(); + + return 0;
+ }
+ + + ///////////////////////////////////////////////////////////////////////////////
+ status_t octave_server::process_octave_internals_data(void)
+ {
+       // Acquire mutex - in this case, block until it is free
+       pthread_mutex_lock(&octave_lock_mutex);
+       
+       // Process breakpoint directives
+       
+       
+       
+       
+       
+       // Retrieve variables
+       process_requested_variables();
+       variable_symtab_list = create_var_list();
+       
+       // Process history
+       history_list = create_history_list();
+       
+       // Release the mutex
+       pthread_mutex_unlock(&octave_lock_mutex);
+       
+       return 0;
+ }
+ + ///////////////////////////////////////////////////////////////////////////////
+ std::vector<octave_value> octave_server::get_requested_variables_values(void)
+ {
+       std::vector<octave_value> retval;
+       
+       // Acquire mutex: if-fail, then return nothing
+       if( !pthread_mutex_trylock(&octave_lock_mutex) )
+       {
+               if( requested_variables.size() == 0 && 
variables_request_list.size() != 0 )
+                       process_requested_variables();
+               
+               retval = requested_variables;
+               requested_variables = std::vector<octave_value>();
+       
+               // Release mutex
+               pthread_mutex_unlock(&octave_lock_mutex);
+       }
+       return retval;
+       
+ }
+ + ///////////////////////////////////////////////////////////////////////////////
+ status_t octave_server::set_requested_variables_names( 
std::vector<std::string> variable_names )
+ {
+       status_t retval = -1;
+       
+       // Acquire mutex: if-fail, then return an error, indicating it should 
be attempted again on the
+       // next iteration
+       if( !pthread_mutex_trylock(&octave_lock_mutex) )
+       {
+               variables_request_list = variable_names;
+ retval = 0; +
+               // Release mutex
+               pthread_mutex_unlock(&octave_lock_mutex);
+       }
+       return retval;
+ }
+ + ///////////////////////////////////////////////////////////////////////////////
+ std::vector<variable_info_t>    octave_server::get_variable_info_list(void)
+ {
+       std::vector<variable_info_t> retval;
+       
+       // Acquire mutex: if-fail, then return nothing
+       if( !pthread_mutex_trylock(&octave_lock_mutex) )
+       {
+               retval = variable_symtab_list;
+               variable_symtab_list = std::vector<variable_info_t>();
+       
+               // Release mutex
+               pthread_mutex_unlock(&octave_lock_mutex);
+       }
+       return retval;
+ }
+ + + ///////////////////////////////////////////////////////////////////////////////
+ string_vector octave_server::get_history_list(void)
+ {
+       string_vector retval;
+       // Acquire mutex: if-fail, then return nothing
+       if( !pthread_mutex_trylock(&octave_lock_mutex) )
+       {
+               retval = history_list;
+               history_list = string_vector();
+       
+               // Release mutex
+               pthread_mutex_unlock(&octave_lock_mutex);
+       }
+       return retval;
+ }
+ + + + /*
+ ;;; Local Variables: ***
+ ;;; mode: C++ ***
+ ;;; End: ***
+ */
Index: threadsafe.h
===================================================================
RCS file: threadsafe.h
diff -N threadsafe.h
*** /dev/null   1 Jan 1970 00:00:00 -0000
--- threadsafe.h        10 Nov 2006 03:28:36 -0000
***************
*** 0 ****
--- 1,267 ----
+ /*
+ + Copyright (C) 2006 John P. Swensen + + This file is part of Octave. + + Octave is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+ + Octave is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ + You should have received a copy of the GNU General Public License
+ along with Octave; see the file COPYING.  If not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ + */ + + #if !defined (octave_threadsafe_h)
+ #define octave_threadsafe_h 1
+ + #include "config.h"
+ #include "octave.h"
+ #include "symtab.h"
+ #include "parse.h"
+ #include "unwind-prot.h"
+ #include "toplev.h"
+ #include "error.h" + #include "quit.h"
+ #include "variables.h"
+ #include "sighandlers.h"
+ #include "sysdep.h"
+ #include "str-vec.h"
+ #include "cmd-hist.h"
+ #include "oct-env.h"
+ + typedef int status_t; + + /**
+  * Enumeration used to identify breakpoint actions
+  */
+ typedef enum bp_action_enum
+ {
+   BP_ACTION_NONE      = 0,
+   BP_ACTION_STEP_INTO = 1,
+   BP_ACTION_STEP_OVER = 2,
+   BP_ACTION_CONTINUE  = 3,
+   BP_ACTION_BREAK     = 4,
+ } bp_action_t;
+ + /**
+  * Structure used to store breakpoint info.
+  *
+  * Notes: used for add, remove, list operations, as well as for the 
BreakpointReached event.
+  */
+ typedef struct bp_info_struct
+ {
+   /**
+    * The full path and filename where the breakpoint resides.
+    */
+ std::string filename; + + /**
+    * The line number where the breakpoint resides.
+    * In the future, -1 can indicate an existing but disabled breakpoint.  This
+    * assumes that no one will ever have an M file longer than 2Million lines.
+    */
+   int line_number;
+ } bp_info_t;
+ + /**
+  * Structure used to store variable information similar to that returned by
+  * the 'whos' function.
+  */
+ typedef struct variable_info_struct variable_info_t;
+ typedef struct variable_info_struct
+ {
+   /**
+    * The name of the variable
+    */
+   std::string variable_name;
+ + /**
+    * The dimensional size of the variable.
+    */
+   std::vector<int> size;
+ + /**
+    * The size of the variable in bytes.
+    */
+   unsigned long long byte_size;
+ + /**
+    * The name of the variable type.
+    */
+   std::string type_name;
+ + friend int operator==(const variable_info_t& left,
+                         const variable_info_t& right)
+   {
+     return (left.variable_name==right.variable_name) &&
+          (left.size==right.size) &&
+          (left.byte_size==right.byte_size) &&
+          (left.type_name==right.type_name);
+   }
+ + } variable_info_t; + + + class octave_server
+ {
+   private:
+     /**
+      * Mutex variable used to protect access to internal class data.
+      */
+     pthread_mutex_t server_mutex;
+ + + /**
+      * Mutex variable used to protect access to octave internals on 
asynchronous requests.
+ * + * Notes: This is necessary for asynchronous requests like detailed variable information + * in a debugger mouse-over, inspection of matrix variables by double-clicking in the + * main window, etc.
+      */
+     pthread_mutex_t octave_lock_mutex;
+ + + /***********************************************************************
+      * DEBUGGING RELATED VARIABLE
+      **********************************************************************/
+     std::vector<bp_info_t> current_breakpoints;
+     std::vector<bp_info_t> breakpoint_reached;
+     std::vector<bp_info_t> added_breakpoints;
+     std::vector<bp_info_t> removed_breakpoint;
+     std::vector<bp_info_t> modify_breakpoints_old;
+     std::vector<bp_info_t> modify_breakpoints_new;
+     bp_action_t          bp_action;
+ + /***********************************************************************
+      * VARIABLE INTERROGATION RELATED VARIABLES
+      **********************************************************************/
+     std::vector<variable_info_t> variable_symtab_list;
+     std::vector<std::string>     variables_request_list;
+ + // NOTE: Create an overloaded operator<< for octave_value to do the
+     // flattening.  This will allow us to append easily to an ostringstream
+     // for output.
+ std::vector<octave_value> requested_variables; + + + int prevHistLen;
+     string_vector      history_list;
+ + public:
+     octave_server( bool startTcpServer = false );
+     ~octave_server();
+ + /**
+      * FUNCTION USED ONLY WHEN THE TCP SERVER IS RUNNING
+      */
+     void process_disconnect();
+     void process_accept();
+     uint8_t* recvMessage();
+     status_t sendMessage( uint8_t* buffer );
+ + static status_t ThreadFunc( octave_server* server ); + + /*****************************************************
+      * FUNCTIONS USED TO ACCESS DATA FROM THE IDE SIDE
+      *****************************************************/
+ + + /***********************************************************************
+      * DEBUGGING RELATED FUNCTIONS
+ **********************************************************************/ + std::vector<bp_info_t> get_breakpoint_list(); + std::vector<bp_info_t> get_breakpoint_reached(); + status_t add_breakpoint( bp_info_t bp_info );
+     status_t             remove_breakpoint( bp_info_t bp_info );
+     status_t             clear_all_breakpoints( void );
+     status_t             modify_breakpoint( bp_info_t old_bp_info, bp_info_t 
new_bp_info );
+     status_t             set_breakpoint_action( bp_action_t action );
+ + /***********************************************************************
+      * VARIABLES RELATED FUNCTIONS
+      **********************************************************************/
+     std::vector<variable_info_t>        get_variable_info_list(void);
+     std::vector<octave_value>           get_requested_variables_values(void);
+     status_t                                          
set_requested_variables_names( std::vector<std::string> variable_names );
+ + /***********************************************************************
+      * HISTORY RELATED FUNCTIONS
+      **********************************************************************/
+     string_vector     get_history_list(void);
+ + /*************************************************************************
+      * FUNCTIONS USED TO ACCESS DATA FROM THE OCTAVE SIDE
+      *
+      * NOTE: THIS IMPLIES THAT THESE ARE ONLY CALLED FROM
+      * OCTAVE DURING A TIME IN WHICH THINGS ARE KNOWN TO
+      * BE "THREAD-SAFE".  PROPOSED LOCATIONS:
+      *     src/toplev.cc - main_loop() at the end of the do...while
+      *     src/pt-bp.h   - MAYBE_DO_BREAKPOINT just prior to the do_keyboard
+      * Most of these will call octave API functions to "pull" the data, rather
+ * than having octave pass in the data. This will help make changes + * exlusive to this class if/when the Octave API changes.
+      
*************************************************************************/
+ + /**
+      * 1) Takes information from the octave_server class and performs the 
necessary actions
+      * in the octave internals
+ * 2) Gets information from the octave internals and places it in the octave_server class + *
+      * Algorithm:
+      *   Acquire lock
+      *   process_breakpoint_add_remove_modify
+      *   set_current_breakpoint
+      *   set_breakpoint_list
+      *   ...
+      *   Get the variable list
+      *   Get the history list
+      *   Get other pertinent information
+      *   Release lock
+      */
+       status_t process_octave_internals_data(void);
+ + /***********************************************************************
+      * DEBUGGING RELATED FUNCTIONS
+ **********************************************************************/ + status_t set_breakpoint_list(void);
+     status_t set_current_breakpoint(std::string filename, int line_number); 
// duplicate of process_breakpoint_action or helper function???
+     status_t process_breakpoint_add_remove_modify(void);
+     status_t process_breakpoint_action(void);
+ + /***********************************************************************
+      * VARIABLES INTERROGATION RELATED FUNCTIONS
+      **********************************************************************/
+     status_t set_variable_info_list(void);
+     status_t process_requested_variables(void);
+ + /***********************************************************************
+      * HISTORY RELATED FUNCTIONS
+ **********************************************************************/ + status_t set_initial_history_list(void);
+     status_t append_history(void);
+ };
+ + + std::vector<variable_info_t> create_var_list(void);
+ string_vector create_history_list(void);
+ + extern octave_server ov_server; + + + #endif + + /*
+ ;;; Local Variables: ***
+ ;;; mode: C++ ***
+ ;;; End: ***
+ */
Index: toplev.cc
===================================================================
RCS file: /cvs/octave/src/toplev.cc,v
retrieving revision 1.187
diff -c -p -r1.187 toplev.cc
*** toplev.cc   9 Oct 2006 19:49:04 -0000       1.187
--- toplev.cc   10 Nov 2006 03:28:36 -0000
*************** Software Foundation, Inc., 51 Franklin S
*** 71,76 ****
--- 71,77 ----
  #include "sighandlers.h"
  #include "sysdep.h"
  #include "syswait.h"
+ #include "threadsafe.h"
  #include "toplev.h"
  #include "unwind-prot.h"
  #include "utils.h"
*************** main_loop (void)
*** 201,207 ****
    octave_catch_interrupts ();
octave_initialized = true; ! // The big loop. int retval = 0;
--- 202,209 ----
    octave_catch_interrupts ();
octave_initialized = true;
!   ov_server.process_octave_internals_data();
! // The big loop. int retval = 0;
*************** main_loop (void)
*** 277,282 ****
--- 279,287 ----
          std::cerr
            << "error: memory exhausted -- trying to return to prompt\n";
        }
+       
+       ov_server.process_octave_internals_data();
+       
      }
    while (retval == 0);



reply via email to

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