Showing posts with label swig. Show all posts
Showing posts with label swig. Show all posts

Friday, January 16, 2009

About memory ownership in SWIG and Python

Today, a long-standing bug in libyui-bindings was finally fixed.

About libyui and libyui-bindings

libyui-bindings provides SWIG based bindings for Ruby, Python and Perl to access libyui functionality. libyui is the YaST user interface library, allowing to write dialogs in a generic way so they can be displayed in text (ncurses) or graphical (Qt) environments.

Reference counting

The core of the problem is libyui relying on YaST data structures. These data structures implement reference counting, so one doesn't have to release allocated memory explicitly. That all fine, as long as you use YaST's YCP programming language to code dialogs. But coding YCP is not necessarily something a lot of developers are looking forward to.
Thats where libyui-bindings enter stage and remove the YCP restriction. I've blogged about it ealier and Jan-Simon was especially active in providing lot of Python examples.

Competing on memory ownership

Now Python is a nice scripting language but has the bad habit of doing reference counting itself. This makes coding Python extensions in C quite awkward and clashes with libyui. Speaking of bad habits, libyui also has one - claiming ownership of memory passed as pointers to some functions.
Fun starts when freeing memory. libyui and Python enter a nasty fight which Linux ends with a SIGSEGV. Jan-Simon reported this as a bug and provided a nice test case.

Swig typemaps

After some googling and reading the SWIG documentation a couple of times, SWIGs DISOWN typemap was the solution. Documentation for this is sparse and well hidden within the Chicken language chapter. Grrr.
SWIG typemaps apply to function parameters and match the parameter type and name. One cannot specify per-function typemaps, only per-parameter. Fixing the bug required libyui to explicitly name parameters claiming ownership of memory. All such parameters within the libyui API are now ending with _disown.

Solving the case

Applying the typemap is done using the %apply directive:
%apply SWIGTYPE *DISOWN { YItem *item_disown };
%apply SWIGTYPE *DISOWN { YEvent *event_disown };
%apply SWIGTYPE *DISOWN { YTableCell *cell_disown };
%apply SWIGTYPE *DISOWN { YWidgetID *newId_disown };
%apply SWIGTYPE *DISOWN { YTableHeader *header_disown };
%apply SWIGTYPE *DISOWN { YTableHeader *header_disown };
%apply SWIGTYPE *DISOWN { YWidget *parent_disown };
Now Python gives up ownership for structures passed through a _disown parameter to libyui and all libyui Python examples run without coredumps. Case closed.

Tuesday, May 20, 2008

Declaring UI independence

Earlier this year, Stefan announced the availability of the YaST user interface engine separate from YaST itself.
The user interface engine, packaged in yast2-libyui (source code here),provides the abstraction from graphical user interfaces (Qt, Gtk) and text based (ncurses) user interfaces. It now can be used independently of YaST2 for generic (C++) applications.
Now what can you do with it ? First of all, you can use C++ to code YaST-like dialogs which display either in graphical mode (Qt or Gtk style) or text mode. This independence from the output media is a main feature of YaST.
Being separated from YaST, one can use the UI engine for stand-alone programs. A trivial example is a simple window with a text label and an 'Ok' button: HelloWorld.ccHelloWorld.cc Compile with
g++ -I/usr/include/YaST2/yui -lyui HelloWorld.cc -o HelloWorld
and run it via
./HelloWorld
Depending on the DISPLAY environment variable the UI engine automatically determines and loads the right plugin to render the dialog.
A simple unset DISPLAY will give you the ncurses look.

Enter SWIG

Coding dialogs in C++ takes away the highly useful edit-run mode of development which is possible with YaSTs YCP language.
With the help of SWIG, a generator for language bindings, one can now use his favorite programming language for coding dialogs. The initial release of the bindings supports Ruby (libyui-ruby), Python (libyui-python) and Perl (perl-libyui).
Swig can directly translate the C++ classes into e.g. Ruby classes making conversion of the above C++ code to Ruby straightforward: hello_world.rbhello_world.rb Translation to object-oriented Python gives you hello_world.pyhello_world.py Even Perl, although not object-oriented, gives reasonable code. But internals of the Swig-generated bindings are not for the faint-hearted ... hello_world.plhello_world.pl yast2-libyui comes with a couple of more examples.
SelectionBox1.cc shows how to fill a selection list, use buttons and update labels.
(SelectionBox1)
Here's the Ruby version: selection_box1.rbselection_box1.rb Enjoy !