SharpDevelop Community

Get your problems solved!
Welcome to SharpDevelop Community Sign in | Join | Help
in Search

Laputa

This is a mirror of http://laputa.sharpdevelop.net/, the core team's central news blog.

January 2008 - Posts

  • IClass Immutability

    In SharpDevelop 1.1, the IClass interface had a property that was used in several places in the code:
    Once added to a project content, it was immutable. This was not enforced, not even documented. It just happened that no one changed IClass objects except for the code constructing them. After being added to a project content, a class could be removed or replaced by a new version, but if some code still held a reference to an old instance, it could safely access the members without worrying that an update to the class on another thread changed something.

    IClass objects are accessed without locks all over the place on the main thread during code completion, and updates on the parser thread should not interfere with that.

    However, because I didn't understand this, I broke it in SharpDevelop 2.0. My implementation of partial classes works as following: each file (compilation unit) contributes a part of the class as IClass object representing that part of the class.
    Once multiple files register a part of the class in the project content, the project content creates a compound class. This compound class combines the members of all the parts. When updating a part, only the IClass for that part was recreated, and the existing CompoundClass was updated.

    The CompoundClass, which could be in use by multiple threads, changed values. To quote Wes Dyer: "Mutation often seems to just cause problems."

    Now, that happened to work correctly for quite some time. Most code iterating through a class' members did this with
    foreach (IMethod method in c.Methods) {
    }

    where c is an IClass (possibly a CompoundClass). An update of the compound class happened to recreate the List<IMethod> behind the c.Methods property, so this code continued to work as expected.

    However, in the quick class browser (the two combo boxes above the code window), there was code similar to this:
    list.AddRange(c.Methods);
    list.Sort();
    list.AddRange(c.Properties);
    list.Sort(c.Methods.Count, c.Properties.Count); // sort the properties without mixing them up with the methods

    Suddenly, due to the addition of partial classes, this became a race condition waiting to happen. But it was found in time for the SharpDevelop 2.0 release, and I fixed the crash.
    But I didn't know much about immutability back then, so what I did was the worst fix possible:
    lock (c) { ... }
    And in CompoundClass, during update of the parts: lock (this) { ... }

    Now, this is not only bad because it's fixing the symptom instead of the problem and it leaves the possibility for similar problems elsewhere in the code - though it might have been the only instance of the problem, since no other crashes due to this have been found while SharpDevelop was using the fix (all 2.x releases use it, including the current stable release, SharpDevelop 2.2.1).

    But multi-threading (without immutability) is not hard, it's really, really hard. So it's not really surprising that some day, I found this code to deadlock.

    So where's the deadlock?
    First I must tell you the other lock we're colliding with: every project content has a lock that it uses to ensure that GetClass() calls are not happening concurrently when the list of classes is updated. So the parser thread acquires the project content lock and then the CompoundClass lock to update the CompoundClass.

    But why would the AddRange / Sort code deadlock with this? The comparer used for list.Sort() sorts the members alphabetically using their language-specific conversion to string. In the case of methods, this includes the parameter list, including the parameter types.

    What you need to know here is that type references (IReturnType objects) are not immutable - they need to always reference the newest version of the class, as we cannot afford rebuilding all IReturnType objects from all classes in the solution whenever any class changes. Now remember that C# allows code like "using Alias = System.String; class Test { void Method(Alias parameter) {} }".

    In this case, the quick class browser correctly resolves the alias and reports "Method(string parameter)". This means that our Sort() call actually sometimes needs to resolve types! And resolving types works using IProjectContent.SearchType, which locks on the project contents' class list lock. And that's our deadlock.

    I think it's near impossible to find this kind of deadlock until it occurs and you can see the call stacks of the two blocked threads.
    Remember that the actual Method->string conversion and the type resolving is language-specific; it may or may not happen to take a lock for other language binding AddIns.

    I fixed the deadlock on trunk (SharpDevelop 3.0) a few months ago by removing the lock on CompoundClass and instead doing this:
    list.AddRange(c.Methods);
    list.Sort();
    int count = list.Count;
    list.AddRange(c.Properties);
    list.Sort(count, list.Count - count);

    It's still a hack, but this doesn't have any side effects (like taking a lock). And it works correctly under our (new) rule (undocumented rule, aka. assumption) that multiple c.get_Methods calls may return different collections, but the collection's contents don't change.

    "foreach (IMethod method in c.Methods) { ... }" is safe, but "for (int i = 0; i < c.Methods.Count; i++) { IMethod method = c.Methods[i]; ... }" can crash.

    But that's quite a difficult rule compared to "IClass never changes". So after reading Erip Lippert's series on immutability, I finally decided to make IClass immutable again.

    It's "popsicle immutability", that means IClass instances are mutable, but when the Freeze() method is called, they become immutable. And this time, immutability is enforced, trying to change a property of a frozen IClass will cause an exception. Adding an IClass to a project content will cause it to freeze if it isn’t already frozen, so it's guaranteed that IClass objects returned by GetClass or by some type reference are immutable.

    Posted Jan 27 2008, 12:30 AM by Laputa
    Filed under:
  • NDoc Replaced With Sandcastle Help File Builder (SHFB)

    A change that happened rather early in the development process of SharpDevelop 3.0 (revision 2658, 8/13/2007) was that we replaced NDoc (a stalled open source project) with Sandcastle Help File Builder (SHFB). SHFB looks and feels similar to NDoc, however, it builds on top of Sandcastle, a documentation generation tool by Microsoft.

    Our build server (revision 2913 and higher) contains SHFB 1.6.0.4, which itself builds on top of the January 2008 release of Sandcastle (both are at the moment the latest releases of their respective projects). SharpDevelop 3.0 setup ships with SHFB, however, Sandcastle itself does not and must be installed separately! (this might change in the future once the final license of Sandcastle is known)

    Because of the regular releases of Sandcastle and SHFB, the distribution of SharpDevelop 3.0 might ship with older versions of SHFB than currently available for download. Thanks to Eric Woodruff, the maintainer of SHFB, this is not a big deal - he is offering a download specific for SharpDevelop:

    All you have to do is first delete the contents of the following installation directory (including subdirectories):

    Then simply unzip the SHFB distribution archive into this folder and presto - you are now using the latest version of SHFB from inside SharpDevelop!

    Posted Jan 23 2008, 09:40 AM by Laputa
    Filed under:
  • Did Development of SharpDevelop 2.2 Stop?

    This question came up for example in the thread SharpDev 2.2.x on BuilderServer (this thread was started because we ceased to automatically build v2.2 on 1/11/2008).

    The answer is Yes. Development of SharpDevelop 2.2 stopped with revision 2675 (8/28/2007), which is three revisions higher than the officially shipping version of SharpDevelop 2.2 (Download, 8/8/2007). The three non-shipping commits are:

    • 2673: Improved CSharpCodeCompletion sample: add tool tip support, show only one entry for overloaded methods
    • 2674: Fixed some off-by-one bugs in the CSharpCodeCompletion example (caused by the different line counting in the parser and the text editor).
    • 2675: CSharpCodeCompletionSample: show xml documentation

    All three were (of course) merged into Montferrer (SharpDevelop 3.0), this merge happened in revision 2679. However, those commits did not merit a release of a new setup because those were all changes to a sample shipping only in the source download.

    Since releasing v2.2.1 all work stopped on the 2.x series of SharpDevelop. Our efforts went (and still go) into SharpDevelop 3.

    Posted Jan 15 2008, 11:37 AM by Laputa
    Filed under:
  • Code Coverage Addin Uses PartCover 2.2 Instead of NCover in SharpDevelop 3

    In continuing to list changes to SharpDevelop 3, we are going to talk about the code coverage addin in SharpDevelop 3 "Montferrer" in this blog post.

    Previously, the addin used NCover for calculating code coverage (this is a metric you gain by writing unit tests). However, recently NCover was turned into a commercial product. Because we only include / support tools that are free to use for anyone (commercial or open source / hobby development), we switched to a different tool - PartCover.

    This change happened in rev 2744 on 19th of November last year. The addin has retained its original functionality, however, for end users there is an important change: you no longer need to download and install a separate package (as it was the case with NCover), PartCover is part of the SharpDevelop setup. You are good to go right after installation!

    Posted Jan 11 2008, 12:02 PM by Laputa
    Filed under:
  • McAfee and \Src\Main\StartUp

    An issue that initially came up in 2006 (Unable to compile #develop: access denied) "resurfaced" on our contributors mailing list because one of our developers ran into this very problem that McAfee blocks access to our Main\StartUp folder:

    The problem and a workaround is described in McAfee VirusScan and the Startup folder. However, this developer doesn't have the administrative rights to change this setting of McAfee, so he asked whether we are going to rename the folder.

    My take on this issue is that this is a bug in McAfee's software, because willy-nilly disabling anything that resides in a random folder called StartUp isn't a security feature.

    Posted Jan 10 2008, 06:43 PM by Laputa
    Filed under:
  • SharpDevelop 3: Where Did Mono and NAnt Support Go?

    Over the past months we made a couple of feature changes in SharpDevelop 3 (currently alpha status). One major change is that we moved NAnt and Mono support from the binary distribution (aka "setup") to the source code distribution. You can find the addins ready to build in the \samples directory:

    What was the reasoning behind this decision? For NAnt, we had taken this decision a long time ago because SharpDevelop itself no longer uses NAnt as the primary build solution, and as such, the addin wasn't actively enhanced and tested. But it still is a great tool as well as a good sample for building addins with SharpDevelop.

    The decision to "relegate" Mono from production to sample status has been based on multiple factors. For one, we only support basic compilation for Mono, no debugger nor any kind of visual designers (like GTK#). We got lots of support questions regarding these, and the honest answer had to be "we won't support that, sorry". Then in December Miguel announced that MonoDevelop will come to Windows (MonoDevelop is a fork of SharpDevelop), which meant that an IDE would come to Windows that fully supports all the things in Mono we don't have.

    That's why we decided to make Mono an addin for people who know how to deal with source code, all the features are still there. And now that it is separate, it also makes a great sample addin because of the deepness of integration with low-level features of SharpDevelop.

    To sum it up - we didn't remove anything, we just trimmed the setup to include features that are targeted at the Microsoft .NET platform.

    Posted Jan 02 2008, 09:15 AM by Laputa
    Filed under:
Powered by Community Server (Commercial Edition), by Telligent Systems
Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.