Monday, May 7, 2007

Spring cleaning

After a brief hiatus helping out with the winforms bug count, I've spent the last few weeks shaking out bugs in Gtk#. The win32 instability issues with trunk seem to have been smoothed out. For the last week, I chased a bunch of ref management and object dispose/destroy issues down in MD and Stetic. Things seem pretty stable now with trunk, but as always, please report any trouble you run into.

I'd like to encourage anyone who has an interest in 2.10 to try out current svn trunk with your applications. It is possible you may see issues since we are getting closer to accurate object finalization now. Many of the issues I worked through in Stetic, for example, were related to using objects after they were already disposed, or marked for finalization by the GC through the circular ref handling capabilities of the GC. If you are doing any object destruction in Dispose overrides, for example, that can cause trouble. If you are invoking base.Dispose in a GLib.Object subclass, it should always be called after you do the additional work. When objects are leaking stuff like this doesn't bite you, but it just might now.

We would like to pull together a release in the near future, and I think things are stable enough at this point for more people to kick the tires. I've revised the Gtk# Plan wiki page to describe the recent changes in the tree and the planned feature additions.

And on a completely unrelated and personal note, I ran my first 5K race over the weekend and survived to hack another day.

Tuesday, March 6, 2007

Exceptional Delegates

I committed some rework to the GObject signal system in Gtk# today. The signal system relies heavily on native to managed callback delegates for all the unmanaged widget signals we bind. Paolo and Lluis pointed out a gap in our previous implementation, where we neglected to take into account the interaction of this code with managed exception handling.

When an exception is thrown in a managed event handler, we need to ensure that the stack is not unrolled across native-to-managed boundaries in the call stack. When that happens, you tend to get unpredictable behavior with stack corruption and segfaults. Today's fixes add try/catch blocks to the signal and virtual method delegate marshallers to ensure the stack only unrolls to the boundary.

The catch blocks raise static events on a new GLib.ExceptionManager class. If you want to "catch" events happening in managed signal handlers, you can attach to the UnhandledException event. The UnhandledExceptionArgs passed to your delegate expose an IsTerminating property (from its System.UnhandledExceptionEventArgs base class) to indicate if the exception is recoverable and an additional ExitApplication property to request program termination if desired after the event propogation is complete.

Lluis, always the bearer of interesting insight, pointed out we need similar code for Idle and Timeout handlers, which made me realize that all the Callback parameters like foreach method callbacks and DestroyNotify handlers are also vulnerable to the problem.

I'll be fixing this bug for a while, but feel free to try out the new signal stuff on trunk in the meantime and report any warts you run across.

Thursday, February 22, 2007

Dogfooding MD

Good progress lately on Gtk#. Got the toggle ref updates into svn, in addition to the Gtk.Object destruction rework. I did a lot of testing on the patch in MonoDevelop, Banshee, F-spot, and some toy apps of mine to feel more confident about such a fundamental change to ref management in the binding.

Having gone through the exercise of building bleeding edge versions of all those apps to test them against bleeding edge Gtk#, I decided it would be good to continue dogfooding like this regularly. I plan to pull the trunk sources of MD, Banshee, and F-spot once a week and run them against Gtk# trunk from now on.

Dogfooding Banshee and F-spot is a simple thing, since I use both applications regularly. MonoDevelop has been something I've only goofed around with every now and then, though. To create a nice dogfooding opportunity I decided to convert my little fitness log application to a MonoDevelop project so I can hack on it in MonoDevelop for an hour or two each week. I wrote a wiki page on my experience of converting the subversion-based autotools project to an MD project. It required surprisingly little manual effort thanks to the nice toys Lluis and folks have been building into MD lately.

Friday, February 9, 2007

Leaky Documents

Making slow but steady progress on the documentation and auditing for the 2.10 API. Hopefully I'll finish up the Printing API next week. I've been refining some of the tools we use to add boilerplate-ish documentation for things like default signal handler virtual methods, and some of the semi-internal API the binding has to expose for binding purposes.

Since writing documentation doesn't make me feel sexy, I've been mixing in some bugfixing and new development along the way. Today I spent some time hacking toggle ref support into GLib.Object. Toggle refs are a new ref type added in glib-2.8. They are a special ref type which provides notification when transitioning from sole-ownership to shared-ownership of an object.

It's important to account for this with managed subclasses because we have to hold a strong reference to the managed object as long as native-owned refs exist. If Gtk# is the sole owner of a native object, we can allow the managed reference handling to drive garbage collection. However, when any native code takes a native ref on a managed subclass, we need to artificially maintain a managed ref to the object until the native code releases its ref.

Since we maintain a GObject* keyed hashtable of outstanding GLib.Object instances, we can use the toggle ref notification to switch between weak and strong references in the hash. While we have shared ownership, the hash will contain a normal object ref, avoiding garbage collection. When we transition to sole ownership, we'll hold a WeakReference to the object in the hash.

My first pass at toggle ref implementation seems to work well for plain GLib.Object subclasses. Now I just have to make it work within the context of GtkObject destruction and so on. I won't be committing anything until I've done a considerable amount of testing, since ref management changes have historically been a source of pain.

Wednesday, January 31, 2007

Good enough

This morning, I committed the ilContrast tool I blogged about on Sunday. It is in the mono-tools product in svn trunk. The tool can compare two individual assemblies which you can provide either by cmdline argument or interactively using the FileChooser.

Some potential features remain for bored hackers and artists to implement:
  • It needs a super-sexy icon. I just copied MonoIcon.png.
  • It could probably use some persistence mechanism to recall the last "project".
  • Multiple assembly comparisons. The mono-api-info tool looks like it can do it, just needs hooking up.
  • Maybe a tabbed view for displaying multiple comparisons.
  • The About dialog could use translation to 67 different languages.
  • It has a hard dependency on Gecko#. A fallback to GtkHtml like monodoc provides might be useful.
After finishing the standalone tool, it occurred to me that this might have made a nice MonoDevelop plugin instead. But the tool is handy as is, and will probably work its way into my Gtk# hacking.

Update:

In case anyone was actually considering the GtkHtml fallback hack, don't bother. As Miguel pointed out to me, the javascript requirement makes that a non-starter. A more likely hack in that area would be to remove the Gecko# dep by directly rendering the mono-api-diff output with Gtk# itself, perhaps using a TreeView.

Sunday, January 28, 2007

ilContrast

After helping Miguel with a corcompare run on IRC Friday afternoon, we decided it would be nice to have a GUI tool that would hook it all up for you. Running the three cmdline tools in the current manner is not the most user-friendly experience.

I threw a few hours at the problem this weekend and have a little Gecko# frontend sort of working. It has a few warts, but it's at least to the point of rendering recognizable information. Look for it to hit the mono-tools module some time this week, hopefully.

Friday, January 26, 2007

Hang on

Delegate persistence is an interesting challenge in a pinvoke binding like Gtk#. Hang on to delegates too long and you tie up the delegate instance memory and keep objects alive which are providing the delegate's invocation target. Release the delegate too soon and you get crashes when the native code tries to invoke it posthumously.

Most of the callback parameters in Gtk+ are destroy notified, taking away the guesswork of when to release the delegate. We have supported notified delegate release for a while now.

Of the non-notified callbacks, most only need to persist for the duration of the method to which they are passed. Foreach methods are a common user of this style of delegate scope. I refer to this as "call" scope. You may have noticed warnings for method parameters defaulted to call scope. The generator treats all callback parameters as call scope if the method signature doesn't contain destroy notification and a scope attribute isn't explicitly provided via metadata.

The challenge appears when a callback parameter doesn't fit into either of these paradigms. There are callbacks which persist until removed by another method. Some of these luckily also provide destroy notification, but not all of them. There is also another class of callbacks that I will call "async" since they are typically provided to allow non-blocking implementations of functionality. The task is queued up by the method call and control returns before the task is actually completed.

Often these async methods take a delegate parameter that is invoked at the completion of the operation to notify the caller the operation is finished. I ran across an example of this method type while documenting the new Gtk printing API from 2.10. Since I was bored of writing documentation, I decided to take a crack at implementing async scope callbacks in the generator.

If you have any async callback delegates in your bindings, you can now add the scope="async" attribute to the parameter with metadata to automatically handle the persistence for this new scope.