Thread overview
[Issue 649] New: format() hangs in thread
Dec 04, 2006
d-bugmail
Dec 06, 2006
Nick
Dec 06, 2006
Sean Kelly
[Issue 649] concatenation hangs in threaded program
Nov 12, 2008
d-bugmail
Nov 12, 2008
d-bugmail
Nov 12, 2008
Sean Kelly
December 04, 2006
http://d.puremagic.com/issues/show_bug.cgi?id=649

           Summary: format() hangs in thread
           Product: D
           Version: 0.176
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Phobos
        AssignedTo: bugzilla@digitalmars.com
        ReportedBy: korslund@gmail.com


The following thread program hangs upon calling format() from a thread. The
call to sleep() is to make sure that 't' is deleted before the thread exits.

import std.thread;
import std.string;

extern(C) uint sleep(uint secs);

class Test
{
  Thread thr;

  int printStats()
    {
      sleep(1);
      format(1); // Program hangs at this point
      return 0;
    }

  this()
    {
      thr = new Thread(&printStats);
      thr.start();
    }

  ~this()
    {
      thr.wait();
    }
}

void main()
{
  Test t = new Test();
  delete t;
}

The following things will prevent the bug from occuring:
- remove the call to format()
- make the thread finish before 't' is deleted
- remove the call to thr.wait() from the destructor, or call it from
  somewhere else

Nick


-- 

December 06, 2006
After some digging it turns out that the problem is actually in string concatination. So a simpler example is to exchange the call

format(1);

with

char[] r;
r ~= "a";

Nick
December 06, 2006
Nick wrote:
> After some digging it turns out that the problem is actually in string
> concatination. So a simpler example is to exchange the call
> 
> format(1);
> 
> with
> 
> char[] r;
> r ~= "a";

What's happening is this:

The compiler runtime relies on gc_free to finalize t, which in turn waits on the child thread.  At the same time, the child thread attempts to allocate memory for the string concatenation and is forced to wait for the gc_free call to finish.  This is a classic deadlock situation.

I think the best fix for this would be for the compiler runtime code (gc.d: _d_delclass) to explicitly call the object's finalizer and for gc_free to simply free memory.  So the GC would only be responsible for finalizing objects whose lifetime ends during a collection, not for those destroyed as the result of a delete operation.  The consequence of this would be that a call to gc_free for an arbitrary block of memory will not call the finalizer for that block, even if one is known to exist, but this seems a clear separation of responsibilities IMO.  If the user really wants the finalizer called he can cast the pointer to Object and delete it.

A possible compromise would be for _d_delclass to explicitly finalize the object and then set a flag indicating that gc_free should not finalize the block, and for gc_free to finalize so long as the 'finalize' flag is still set.  This may be a bit slower depending on how it's implemented, but it would allow gc_free to finalize tagged blocks when appropriate.  But again, I think it is probably more appropriate for the GC to only finalize on collections, and assume that if gc_free is called at other times, then the user does not intend for finalization to occur.


Sean
November 12, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=649





------- Comment #4 from gide@nwawudu.com  2008-11-12 06:39 -------
Tried the code on DMD 1.033 and it doesn't hang. Has this bug been resolved?


-- 

November 12, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=649





------- Comment #5 from korslund@gmail.com  2008-11-12 07:07 -------
Still hangs on my end, DMD 1.036 on Ubuntu Linux. Possibly OS-dependent?


-- 

November 12, 2008
d-bugmail@puremagic.com wrote:
> http://d.puremagic.com/issues/show_bug.cgi?id=649
> 
> ------- Comment #5 from korslund@gmail.com  2008-11-12 07:07 -------
> Still hangs on my end, DMD 1.036 on Ubuntu Linux. Possibly OS-dependent?

I'd just like to note that this should be fixed in D 2.020, as druntime handles this situation differently.


Sean