New Octave module loading behaviour

- Use call syntax instead of cmdline to choose global/noglobal load:
  global: 'example;', noglobal: 'example = example;'
- All functions loaded with Octave 'autoload' command; correctly
  loads .oct module and prevents segfault in Octave 3.0.5
- Functions no longer installed as global variables as well,
  so global operator dispatch now only looks for functions
- Octave at-exit function created from string, not function,
  so no dependence on loaded .oct files at cleanup time
- C at-exit function now immediately exits Octave (with correct
  status) to prevent seg-fault due to dodgy memory cleanup
  in some Octave versions
- Documentation string for module loading function

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@13088 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Karl Wette 2012-05-14 09:24:15 +00:00
commit bc2a78fbab
3 changed files with 146 additions and 174 deletions

View file

@ -504,37 +504,9 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own);
rhs.members.clear();
}
void install_global(bool global_load) {
for (member_map::const_iterator it = members.begin(); it != members.end(); ++it) {
bool is_global_op = (it->first.substr(0, strlen(SWIG_op_prefix)) == SWIG_op_prefix);
bool is_func_defined = (it->second.first && it->second.first->method);
if (is_func_defined && (is_global_op || global_load)) {
install_builtin_function(it->second.first->method, it->first,
it->second.first->doc ? it->second.first->doc : std::string());
}
octave_value global_val = is_global_op ? make_fcn_handle(it->first) : it->second.second;
if (global_val.is_defined() && (is_global_op || global_load)) {
#if OCTAVE_API_VERSION_NUMBER<37
link_to_global_variable(curr_sym_tab->lookup(it->first, true));
#else
symbol_table::varref(it->first);
symbol_table::mark_global(it->first);
#endif
set_global_value(it->first, global_val);
#if OCTAVE_API_VERSION_NUMBER<37
octave_swig_type *ost = Swig::swig_value_deref(global_val);
if (ost) {
const char* h = ost->help_text();
if (h) {
symbol_record *sr = global_sym_tab->lookup (it->first, true);
sr->document(h);
}
}
#endif
}
}
}
typedef member_map::const_iterator swig_member_const_iterator;
swig_member_const_iterator swig_members_begin() { return members.begin(); }
swig_member_const_iterator swig_members_end() { return members.end(); }
void *cast(swig_type_info *type, int *_own, int flags) {
if (_own)
@ -835,10 +807,10 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own);
// we assume that SWIG_op_prefix-prefixed functions are installed in global namespace
// (rather than any module namespace).
octave_value fcn = get_global_value(symbol, true);
if (!fcn.is_function() && !fcn.is_function_handle())
octave_function *fcn = is_valid_function(symbol, std::string(), false);
if (!fcn)
return false;
ret = fcn.subsref("(", std::list < octave_value_list > (1, args), 1);
ret = fcn->do_multi_index_op(1, args)(0);
return true;
}

View file

@ -1,11 +1,14 @@
%insert(runtime) %{
#include <iostream>
#include <octave/oct.h>
#include <octave/parse.h>
#include <octave/ov-fcn-handle.h>
#include <octave/Cell.h>
#include <octave/dynamic-ld.h>
#include <octave/oct-env.h>
#include <octave/oct-map.h>
#include <octave/ov-fcn-handle.h>
#include <octave/parse.h>
#include <octave/toplev.h>
#include <octave/unwind-prot.h>
%}
%insert(runtime) "swigrun.swg";
@ -18,9 +21,12 @@
static void SWIG_init_user(octave_swig_type* module_ns);
#if OCTAVE_API_VERSION_NUMBER>=37
octave_value_list SWIG_atexit_func(const octave_value_list &args, int nargout);
#endif
SWIGINTERN void SWIG_Octave_InstallFunction(octave_function *octloadfcn, std::string name) {
octave_value_list args;
args.append(name);
args.append(octloadfcn->fcn_file_name());
feval("autoload", args, 0);
}
static const char *const subclass_usage = "-*- texinfo -*- \n\
@deftypefn {Loadable Function} {} subclass()\n\
@ -114,87 +120,94 @@ DEFUN_DLD( swig_this, args, nargout, swig_this_usage ) {
return octave_value(octave_uint64((unsigned long long) ost->swig_this()));
}
DEFUN_DLD (SWIG_name,args,nargout,SWIG_name_d) {
// determine if module is already loaded
bool already_load;
#if OCTAVE_API_VERSION_NUMBER<37
{
symbol_record *rec = curr_sym_tab->lookup(SWIG_name_d);
already_load = (rec && rec->is_linked_to_global());
}
#else
already_load = symbol_table::is_global(SWIG_name_d);
// workaround to prevent octave seg-faulting on exit: register at-exit
// function which exits octave immediately without trying to cleanup memory.
// definitely affects version 3.2.*, not sure about 3.3.*, seems to be
// fixed in version 3.4.* and above. can be turned on/off with macros.
#ifndef SWIG_OCTAVE_NO_SEGFAULT_HACK
#if 36 < OCTAVE_API_VERSION_NUMBER && OCTAVE_API_VERSION_NUMBER < 45
#define SWIG_OCTAVE_SEGFAULT_HACK
#endif
if (!already_load) {
// parse command line
const char* usage="usage: " SWIG_name_d " [-global|-noglobal] [-globals {<name>|.}]";
bool global_load=SWIG_global_load;
std::string global_name=SWIG_global_name;
for (int j=0;j<args.length();++j)
if (args(j).is_string()) {
if (args(j).string_value()=="-help") {
std::cout << usage << std::endl;
return octave_value_list();
} else if (args(j).string_value()=="-global") {
global_load = true;
} else if (args(j).string_value()=="-noglobal") {
global_load = false;
} else if (args(j).string_value()=="-globals") {
if (j+1<args.length()&&args(j+1).is_string()) {
global_name = args(j+1).string_value();
++j;
} else {
std::cerr << "error: " SWIG_name_d ": option '-globals' requires an argument." << std::endl;
std::cerr << usage << std::endl;
return octave_value_list();
}
} else {
std::cerr << "error: " SWIG_name_d ": unrecognised argument '" << args(j).string_value() << "'." << std::endl;
std::cerr << usage << std::endl;
return octave_value_list();
}
} else {
std::cerr << "error: " SWIG_name_d ": unrecognised non-string argument." << std::endl;
std::cerr << usage << std::endl;
return octave_value_list();
}
if (global_name != "." && !valid_identifier(global_name)) {
std::cerr << "error: " SWIG_name_d ": '" << global_name << "' is not a valid Octave identifier." << std::endl;
return octave_value_list();
}
// load module in base frame
#if OCTAVE_API_VERSION_NUMBER<37
symbol_table *prev_sym_tab = curr_sym_tab;
curr_sym_tab = top_level_sym_tab;
#else
octave_call_stack::goto_base_frame();
#endif
#ifdef SWIG_OCTAVE_SEGFAULT_HACK
#define _SWIG_OCT_SEGF_HACK_ATEXIT_FCN(NAME) SWIG_OCT_SEGF_HACK_ATEXIT_FCN_##NAME
#define SWIG_OCT_SEGF_HACK_ATEXIT_FCN(NAME) _SWIG_OCT_SEGF_HACK_ATEXIT_FCN(NAME)
void SWIG_OCT_SEGF_HACK_ATEXIT_FCN(SWIG_name)(void) {
_exit(exit_status);
}
#endif
static const char *const SWIG_name_usage = "-*- texinfo -*- \n\
@deftypefn {Loadable Module} {} " SWIG_name_d "\n\
Loads the SWIG-generated module `" SWIG_name_d "'.\n\
\n\
To load the module into the global namespace:\n\
@example\n\
" SWIG_name_d ";\n\
@end example\n\
To access the module through a local variable, without loading it globally:\n\
@example\n\
" SWIG_name_d " = " SWIG_name_d ";\n\
@end example\n\
To access the module locally through a variable named, e.g. @var{modl}:\n\
@example\n\
@var{modl} = " SWIG_name_d ";\n\
@end example\n\
@end deftypefn";
DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) {
static octave_swig_type* module_ns = 0;
octave_value_list retval;
// create module on first function call
if (!module_ns) {
#ifdef SWIG_OCTAVE_SEGFAULT_HACK
atexit(SWIG_OCT_SEGF_HACK_ATEXIT_FCN(SWIG_name));
#endif
// workaround bug in octave where installing global variable of custom type and then
// exiting without explicitly clearing the variable causes octave to segfault.
#if OCTAVE_API_VERSION_NUMBER >= 37
octave_value_list eval_args;
eval_args.append("base");
eval_args.append("function __swig_atexit__; "
" if mislocked() "
" clear -all; "
" else "
" mlock(); "
" endif; "
"endfunction; "
"__swig_atexit__; "
"atexit(\"__swig_atexit__\", false); "
"atexit(\"__swig_atexit__\")");
feval("evalin", eval_args, 0);
#endif
octave_swig_ref::register_type();
octave_swig_packed::register_type();
SWIG_InitializeModule(0);
SWIG_PropagateClientData();
install_builtin_function(swig_type,"swig_type",std::string());
install_builtin_function(swig_typequery,"swig_typequery",std::string());
install_builtin_function(swig_this,"swig_this",std::string());
install_builtin_function(subclass,"subclass",std::string());
octave_function *me = octave_call_stack::current();
SWIG_Octave_InstallFunction(me, "swig_type");
SWIG_Octave_InstallFunction(me, "swig_typequery");
SWIG_Octave_InstallFunction(me, "swig_this");
SWIG_Octave_InstallFunction(me, "subclass");
octave_swig_type* cvar_ns=0;
if (global_name != ".") {
if (SWIG_global_name != ".") {
cvar_ns=new octave_swig_type;
for (int j=0;swig_globals[j].name;++j)
if (swig_globals[j].get_method)
cvar_ns->assign(swig_globals[j].name,&swig_globals[j]);
}
octave_swig_type* module_ns=new octave_swig_type(0, 0, 0, true);
if (global_name != ".") {
module_ns->assign(global_name,Swig::swig_value_ref(cvar_ns));
module_ns=new octave_swig_type(0, 0, 0, true);
if (SWIG_global_name != ".") {
module_ns->assign(SWIG_global_name,Swig::swig_value_ref(cvar_ns));
}
else {
for (int j=0;swig_globals[j].name;++j)
@ -204,72 +217,63 @@ DEFUN_DLD (SWIG_name,args,nargout,SWIG_name_d) {
for (int j=0;swig_globals[j].name;++j)
if (swig_globals[j].method)
module_ns->assign(swig_globals[j].name,&swig_globals[j]);
// * need better solution here; swig_type -> octave_class mapping is
// * really n-to-1, in some cases such as template partial spec, etc.
// * need better solution here; swig_type -> octave_class mapping is
// * really n-to-1, in some cases such as template partial spec, etc.
// * see failing tests.
for (int j=0;swig_types[j];++j)
if (swig_types[j]->clientdata) {
swig_octave_class* c=(swig_octave_class*)swig_types[j]->clientdata;
module_ns->assign(c->name,
Swig::swig_value_ref
(new octave_swig_type(0,swig_types[j])));
Swig::swig_value_ref
(new octave_swig_type(0,swig_types[j])));
}
SWIG_init_user(module_ns);
SWIG_InstallOps(octave_swig_ref::static_type_id());
// the incref is necessary so install_global doesn't destroy module_ns,
// as it would if it installed something with the same name as the module.
module_ns->incref();
module_ns->install_global(global_load);
module_ns->decref();
// create global variable containing module
set_global_value(SWIG_name_d,Swig::swig_value_ref(module_ns));
#if OCTAVE_API_VERSION_NUMBER>=37
install_builtin_function(SWIG_atexit_func,"__swig_atexit_" SWIG_name_d "__",std::string());
octave_add_atexit_function("__swig_atexit_" SWIG_name_d "__");
octave_remove_atexit_function("__finish__");
#endif
// return from base frame
#if OCTAVE_API_VERSION_NUMBER<37
curr_sym_tab = prev_sym_tab;
SWIG_init_user(module_ns);
SWIG_InstallOps(octave_swig_ref::static_type_id());
#if OCTAVE_API_VERSION_NUMBER < 37
mlock(me->name());
#else
octave_call_stack::pop();
#endif
#if OCTAVE_API_VERSION_NUMBER>=37
mlock();
#endif
} // !already_load
// link variable to module in current context
#if OCTAVE_API_VERSION_NUMBER<37
link_to_global_variable(curr_sym_tab->lookup(SWIG_name_d,true));
#else
symbol_table::varref(SWIG_name_d);
symbol_table::mark_global(SWIG_name_d);
#endif
}
return octave_value_list();
}
// return module if asked for
if (args.length() == 0 && nargout == 1) {
retval = octave_value(module_ns->as_value());
}
// if call with not output arguments, load globally
else if (args.length() == 0 && nargout == 0) {
octave_function *me = octave_call_stack::current();
octave_swig_type::swig_member_const_iterator mb;
for (mb = module_ns->swig_members_begin(); mb != module_ns->swig_members_end(); ++mb) {
if (mb->second.first && mb->second.first->method) {
SWIG_Octave_InstallFunction(me, mb->first);
}
else if (mb->second.second.is_defined()) {
SWIG_Octave_SetGlobalValue(mb->first, mb->second.second);
SWIG_Octave_LinkGlobalValue(mb->first);
}
}
SWIG_Octave_SetGlobalValue(SWIG_name_d, module_ns->as_value());
SWIG_Octave_LinkGlobalValue(SWIG_name_d);
}
// otherwise print usage
else {
print_usage();
}
return retval;
// workaround bug in octave where installing global variable of custom type and then
// exiting without explicitly clearing the variable causes octave to segfault.
#if OCTAVE_API_VERSION_NUMBER>=37
octave_value_list SWIG_atexit_func(const octave_value_list &args, int nargout) {
string_vector vars = symbol_table::global_variable_names();
for (int i = 0; i < vars.length(); i++)
symbol_table::clear_global(vars[i]);
symbol_table::clear_functions();
return octave_value();
}
#endif
%}

View file

@ -15,16 +15,13 @@ char cvsroot_octave_cxx[] = "$Id$";
#include "swigmod.h"
static bool global_load = true;
static String *global_name = 0;
static String *op_prefix = 0;
static const char *usage = (char *) "\
Octave Options (available with -octave)\n\
-global - Load all symbols into the global namespace [default]\n\
-globals <name> - Set <name> used to access C global variables [default: 'cvar']\n\
- Use '.' to load C global variables into module namespace\n\
-noglobal - Do not load all symbols into the global namespace\n\
Use '.' to load C global variables into module namespace\n\
-opprefix <str> - Prefix <str> for global operator functions [default: 'op_']\n\
\n";
@ -83,12 +80,13 @@ public:
if (argv[i]) {
if (strcmp(argv[i], "-help") == 0) {
fputs(usage, stdout);
} else if (strcmp(argv[i], "-global") == 0) {
global_load = true;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-noglobal") == 0) {
global_load = false;
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-global") == 0 ||
strcmp(argv[i], "-noglobal") == 0) {
Printv(stderr,
"*** -global/-noglobal are no longer supported\n"
"*** global load behaviour is now determined at module load\n"
"*** see the Perl section in the manual for details.\n", NIL);
SWIG_exit(EXIT_FAILURE);
} else if (strcmp(argv[i], "-globals") == 0) {
if (argv[i + 1]) {
global_name = NewString(argv[i + 1]);
@ -179,10 +177,8 @@ public:
Printf(f_runtime, "#define SWIG_name %s\n", module);
Printf(f_runtime, "\n");
Printf(f_runtime, "#define SWIG_global_load %s\n", global_load ? "true" : "false");
Printf(f_runtime, "#define SWIG_global_name \"%s\"\n", global_name);
Printf(f_runtime, "#define SWIG_op_prefix \"%s\"\n", op_prefix);
Printf(f_runtime, "#define SWIG_atexit_func swig_atexit_%s\n", module);
if (directorsEnabled()) {
Printf(f_runtime, "#define SWIG_DIRECTORS\n");
@ -383,7 +379,7 @@ public:
virtual int importDirective(Node *n) {
String *modname = Getattr(n, "module");
if (modname)
Printf(f_init, "feval(\"%s\",octave_value_list(),0);\n", modname);
Printf(f_init, "feval(\"%s\",octave_value_list(),1);\n", modname);
return Language::importDirective(n);
}