Threading in Plasma applets

Richard Dale richard.j.dale at gmail.com
Tue Apr 8 13:00:15 CEST 2008


2008/4/8 Aaron J. Seigo <aseigo at kde.org>:

> On Monday 07 April 2008, Richard Dale wrote:
> > I've just commited a fix based on the SWIG macros and it all works very
> > well now - phew!
>
> wow..that's a bit crazy.
>
> does this impact both the kross ScriptEngine as well as your "no, it's
> really
> a c++ plugin ;)" code? or just one or the other?

 Yes I think it will affect kross because the state of the stack when kross
is loaded might be different from when the plasma runtime make callbacks to
it. In the case of he QtRuby based applet the stack base when loading was
above the stackbase when running (ie there were more C++ calls involved in
loading the applet, than there were when running it).

Currently it is possible that there are less C++ stack activations involved
in loading kross than there are when invoking callbacks, and it might be ok.
But maybe one day you add some extra nested C++ calls on loading, and all of
a sudden, boom!, kross would start throwing exceptions. I would run the
debugging code I added to the ruby gc.c source to see what the ruby stack
looks like when running kross.

This is the macro code I added to QtRuby (see
qtruby/src/marshall_types.cpp):

// This is based on the SWIG SWIG_INIT_STACK and SWIG_RELEASE_STACK macros.
// If RUBY_INIT_STACK is only called when an embedded extension such as, a
// Ruby Plasma plugin is loaded, then later the C++ stack can drop below
where the
// Ruby runtime thinks the stack should start (ie the stack position when
the
// plugin was loaded), and result in sys stackerror exceptions
//
// TODO: While constructing the main class of a plugin when it is being
loaded,
// there could be a problem when a custom virtual method is called or a slot
is
// invoked, because RUBY_INIT_STACK will have aleady have been called from
within
// the krubypluginfactory code, and it shouldn't be called again.

#ifdef RUBY_EMBEDDED
#  define QTRUBY_INIT_STACK                            \
      if ( nested_callback_count == 0 ) { RUBY_INIT_STACK } \
      nested_callback_count++;
#  define QTRUBY_RELEASE_STACK nested_callback_count--;

static unsigned int nested_callback_count = 0;

#else  /* normal non-embedded extension */

#  define QTRUBY_INIT_STACK
#  define QTRUBY_RELEASE_STACK
#endif  /* RUBY_EMBEDDED */

#ifdef RUBY_EMBEDDED

static VALUE funcall2_protect_id = Qnil;
static int funcall2_protect_argc = 0;
static VALUE * funcall2_protect_args = 0;

static VALUE
funcall2_protect(VALUE obj)
{
    VALUE result = Qnil;
    result = rb_funcall2(obj, funcall2_protect_id, funcall2_protect_argc,
funcall2_protect_args);
    return result;
}

#  define QTRUBY_FUNCALL2(result, obj, id, argc, args) \
      int state = 0; \
      funcall2_protect_id = id; \
      funcall2_protect_argc = argc; \
      funcall2_protect_args = args; \
      result = rb_protect(funcall2_protect, obj, &state); \
      if (state != 0) { \
          rb_backtrace(); \
          result = Qnil; \
      }

#else

#  define QTRUBY_FUNCALL2(result, obj, id, argc, args) \
      result = rb_funcall2(obj, id, argc, args);

#endif

If QtRuby is built with a '-DRUBY_EMBEDDED' option (as for plasma), then
rb_protect() is used to ensure that any ruby exceptions are caught and the
process isn't terminated. Otherwise, funcall2() is called directly with no
use of RUBY_INIT_STACK. Example usage:

    VALUE result;
    QTRUBY_INIT_STACK
    QTRUBY_FUNCALL2(result, _obj, _slotname, _items - 1, _sp)
    QTRUBY_RELEASE_STACK

-- Richard
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.kde.org/pipermail/panel-devel/attachments/20080408/33eaa287/attachment.html 


More information about the Panel-devel mailing list