[Vm-dev] We need help from VM experts. Re: Freeze after Morph& nbsp; & nbsp; & nbsp; & nbsp; Activity

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Fri Mar 10 08:45:07 UTC 2017


2017-03-10 3:47 GMT+01:00 David T. Lewis <lewis at mail.msen.com>:

>
> On Thu, Mar 09, 2017 at 12:41:44PM -0800, Eliot Miranda wrote:
> >
> > Hi David,
> >
> > On Mon, Mar 6, 2017 at 5:50 PM, David T. Lewis <lewis at mail.msen.com>
> wrote:
> >
> > >
> > > In the VM, the millisecond clock wraps within the 32 bit integer range:
> > >
> > >   #define MillisecondClockMask 0x1FFFFFFF
> > >
> > > In the Cuis image, Delay class>>handleTimerEvent does this:
> > >
> > >   nextTick := nextTick min: SmallInteger maxVal.
> > >
> > > On a 64-bit Spur image, SmallInteger maxVal is 16rFFFFFFFFFFFFFFF, but
> on
> > > a 32-bit image it is 16r3FFFFFFF.
> > >
> > > Could that be it?
> > >
> > > I don't really know how to test in Squeak. As you say, Squeak is now
> > > using the microsecond clock in #handleTimerEvent. I do not see anything
> > > in primitiveSignalAtMilliseconds that would behave any differently on
> > > a 64 bit versus 32 bit image or VM, but I do not know how to test to
> > > be sure.
> > >
> >
> > I bet that the following code from primitiveSignalAtMilliseconds ends up
> > wrapping when given
> >     Delay primSignal: s atMilliseconds: Time primMillisecondClock - 10.
> >
> > deltaMsecs := msecs - (self ioMSecs bitAnd: MillisecondClockMask).
> > deltaMsecs < 0 ifTrue:
> > [deltaMsecs := deltaMsecs + MillisecondClockMask + 1].
> > nextWakeupUsecs := self ioUTCMicroseconds + (deltaMsecs * 1000).
> >
> > and I bet you'll find that the VM will wake up in about 6 days and 5
> hours
> > ;-)
> >
>
> No. The failure is specific to the 64 bit VM. Source code for the primitive
> is the same in either case.
>
>
>
> > I suppose we could fix this, but I'm *much* happier to simply not use
> > primitiveSignalAtMilliseconds and stay with the simpler and
> wrapping-immune
> > primitiveSignalAtUTCMicroseconds
>
> Fair enough, but given that there is a demonstrated bug that affects only
> the 64-bit VM, and given that it expresses itself intermittently and in
> ways
> that affect only someone who is attempting to migrate their existing V3
> image
> to Spur, then I would say that it makes very good sense to take the time
> to fix it if we are able to do so. After all, there may be other people who
> will want to migrate V3 images to Spur, and there is no point in making the
> process needlessly difficult.
>
> I do not have the solution, but maybe someone else can help. So I am asking
> for help here. Can someone with a working 64-bit build environment please
> check and see if what I said in an earlier email might make a difference:
>
>   I see that ioMSecs() is declared as signed long (32 bits), but it is used
>   in expression with a 64 bit usqInt. So maybe it needs a cast, or maybe
>   the variables like msecs and deltaMsecs in primitiveSignalAtMilliseconds
>   should be declared as 32 bit long and unsigned long to match the actual
> usage.
>
> Thanks,
>
> Dave
>
>

Hi David
I just reviewed the generated code for primitiveSignalAtMilliseconds
andhere is what i found:

The primitive will simply fail if fed with a negative integer, thanks to:

        msecs = positive32BitValueOf(msecsObj);

msecs is allways positive, since declared as
    usqInt msecs;

So far, so good.

Then
                        deltaMsecs = msecs - ((ioMSecs()) &
MillisecondClockMask);
                        if (deltaMsecs < 0) {
                                deltaMsecs = (deltaMsecs +
MillisecondClockMask) + 1;
                        }
                        GIV(nextWakeupUsecs) = (ioUTCMicroseconds()) +
(deltaMsecs * 1000);

Due to the 29 bits Mask, the bitAnd: (&) operation will result into a
positive int.
0 <= ((ioMSecs()) & MillisecondClockMask) <= 0x1FFFFFFF

However, when we do the Roll-over thing:
                                deltaMsecs = (deltaMsecs +
MillisecondClockMask) + 1;
Then we create a giant delay (the 6 days mentionned by Eliot) which is
HIGHLY QUESTIONNABLE whatever 32 or 64 bits!

The difference between 32 and 64 bits is in the next line:
                        GIV(nextWakeupUsecs) = (ioUTCMicroseconds()) +
(deltaMsecs * 1000);
Because
    sqInt deltaMsecs;

is 32 bits for a 32bits spur, 64bits for 64bits spur, then (deltaMsecs *
1000) will do two different things:
- in 32 bits it will overflow leading to a negative delay and a
nextWakeupUsecs in the past (but that's invoking Undefined Behavior)
- in 64 bits it won't overflow leading to he 6 days delay

Does that explain?

if (deltaMsecs < 0) I would either fail the primitive or set the deltaMsecs
to zero.
What do you think?

 Nicolas
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20170310/ab256d29/attachment-0001.html>


More information about the Vm-dev mailing list