December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #19 from Dmitry Olshansky <dmitry.olsh@gmail.com> 2012-12-26 06:01:41 PST ---
Reduced a tiny bit further and there 2 versions that work fine: OK and OK2. Both are seemingly unrelated to the test.


void popFront(A)(ref A[] a)
{
    a = a[1 .. $];
}

private struct MapResult(alias fun, Range)
{
    alias Range R;
    R _input;

    this(R input)
    {
        _input = input;
    }

    @property bool empty()
    {
        return _input.length == 0;
    }

    void popFront()
    {
        version(OK)
            _input = _input[1 .. $];
        else
            _input.popFront();
        //
    }

    @property auto ref front()
    {
        return fun(_input[0]);
    }

    @property auto length()
    {
        return _input.length;
    }

    alias length opDollar;
}

int sliceBefore;

void corrupt( immutable int numberOfThreads ) {
    immutable n = 1000000000 ;
    immutable sliceSize = n / numberOfThreads ;
    sliceBefore = sliceSize;
    auto threads = MapResult!( ( int i ) {
        auto closedPartialSum() {
            version(OK2){} //omit ii and it works
            else
            {
                immutable ii = i ;
            }
            return delegate ( ) {
                assert(sliceSize == sliceBefore);
            };
        }
        return closedPartialSum();
    }, int[]) ( [0] );

    //create array of delegates and copy them using range-based foreach
    auto dgs = new void delegate()[threads.length];
    size_t i=0;
    foreach(dg; threads) //empty-front-popFront
        dgs[i++] = dg;

    foreach(dg; dgs)
        dg();
}

void main(){
  corrupt(1);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #20 from Maxim Fomin <maxim@maxim-fomin.ru> 2012-12-26 06:41:40 PST ---
(In reply to comment #19)
> Reduced a tiny bit further and there 2 versions that work fine: OK and OK2. Both are seemingly unrelated to the test.
> 
> <skipped>

Note, valgrind still complains with -version=OK (use of uninitialized value in
dgliteral2). Try insert writeln("") in MapResult.popFront and you will get
assert error.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #21 from Russel Winder <russel@winder.org.uk> 2012-12-26 07:11:49 PST ---
OK I can accept that map delivers an iterable but not a sequence, so to create
a sequence application of array is needed. This would imply though that 2.059 →
2.060 introduces an undocumented breaking change – albeit a good one correcting
a bug.

Having i work and ii not work implies the whole closure capture mechanism in 2.059 → 2.060 underwent breaking change. The question then is which closure semantics are correct, indeed whether delegates are required to create closures.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #22 from Russel Winder <russel@winder.org.uk> 2012-12-26 07:19:03 PST ---
Using LDC2, the ii → i change is not needed, just adding the .array to the result of the map expression to turn the iterable into a data structure is sufficient.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #23 from Russel Winder <russel@winder.org.uk> 2012-12-26 07:22:55 PST ---
ii → i not needed for DMD 2.060 either.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #24 from Russel Winder <russel@winder.org.uk> 2012-12-26 07:28:10 PST ---
Interesting, or not, pi_d_threadsGlobalState_array_iterative.d works fine with LDC2 and causes a segmentation violation with DMD. Separate issue coming up shortly.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #25 from Dmitry Olshansky <dmitry.olsh@gmail.com> 2012-12-26 12:41:47 PST ---
(In reply to comment #12)
> Well, we probably should make sure that by the time Thread.start() returns, the
> thread is joinable (waiting for the thread to start in Thread.join() would
> probably be undesirable).
> 
> In any case, it probably isn't a bug, but a very reasonable enhancement request - I know I'd expect it to behave like that.

I see no reason to believe it's not the case right now. Basically after
t.start() was called join should always succeed (and wait on the thread to
terminate, potentially blocking indefinetely).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 26, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #26 from Dmitry Olshansky <dmitry.olsh@gmail.com> 2012-12-26 14:22:48 PST ---
(In reply to comment #21)
> OK I can accept that map delivers an iterable but not a sequence, so to create a sequence application of array is needed.

It's not exactly  an iterable or sequence, it's a lazy computation represented as a range. The key point is that it doesn't even attempt to store results somewhere nor avoid recomputation on demand.

> This would imply though that 2.059 →
> 2.060 introduces an undocumented breaking change – albeit a good one correcting
> a bug.
> 

The only case I think it might have worked previously is the following chain of
"events":
1. map used to cache the first entry (and maybe the last) (AFAIK it was in
2.057 or earlier)
2. then 1 thread out of pack is indeed the one that can be joined, the others
are these that are newely created and not started. (if both front & back - then
2 threads)
3. the join somehow worked on not yet started threads.
4. the join then waited on only one thread (or maybe 2).
5. by sheer luck to the moment of printing stuff all threads arrive completed
(since printing takes some time and is interlocked there is plenty of chance
for other threads to finish the work)

So... can you print the addresses of threads (in both start & join loops) in 2.059 where it used to work. It's intriguing to see if this guess is on spot and what forces are at work there.

> Having i work and ii not work implies the whole closure capture mechanism in 2.059 → 2.060 underwent breaking change. The question then is which closure semantics are correct, indeed whether delegates are required to create closures.

No, I suspect you are confusing these 2 cases:
foreach(i; x..y)
{
   threads ~= delegate (){
       //use i here
   }
}

vs

threads = map!( (int i){ use i here ... })(...);

Note that in second case 'i' is a parameter passed to a delegate that is in turn passed by alias to map. Thus 'i' is unique for every stack frame (or call) of the said delegate.

In the first case 'i' is tied to the same variable on the stack frame for each delegate create.

Semantically there are 2 rules:
- context capture happens on delegate creation
- during context capture everything in the current function scope is captured
by ref (behind the scenes rather the whole is captured by a single ref to a
stack frame)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 27, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #27 from Walter Bright <bugzilla@digitalmars.com> 2012-12-26 18:17:14 PST ---
(In reply to comment #19)
> Reduced a tiny bit further and there 2 versions that work fine: OK and OK2. Both are seemingly unrelated to the test.

This example seg faults on 2.058, 59, and 60 as well as 61.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 27, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=8774



--- Comment #28 from Walter Bright <bugzilla@digitalmars.com> 2012-12-26 21:30:55 PST ---
A further reduced test case:

-----------------
void popFront()
{
    int[20] abc;        // smash stack
}

struct MapResult(alias fun)
{
    void delegate() front()
    {
        return fun(1);
    }
}

void main() {

    int sliceSize = 100;

    void delegate() foo( int i )
    {
        void delegate() closedPartialSum()
        {
            int ii = i ;
            void bar()
            {   assert(sliceSize == 100);
            }
            return &bar;
        }
        return closedPartialSum();
    }

    auto threads = MapResult!foo();

    auto dg = threads.front();
    popFront();

    dg();
}
-----------------

Most of the oddities in the original were there to "smash" the stack, which we do here with a simple array initialization. Apparently, there are out-of-scope dangling references into the stack which cause the seg fault.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------