On 08 Jan 2016, at 4:25 , Ben Coman <btc@openInWorld.com> wrote:


On Fri, Jan 8, 2016 at 9:39 PM, Ben Coman <btc@openinworld.com> wrote:
On Fri, Jan 8, 2016 at 5:42 PM, stephane ducasse
<stephane.ducasse@gmail.com> wrote:

I have a (stupid) question.
Is the code running without the primitives?
Are the code below the primitives correct?
I asked that because we can have 100 eyes and brains on the smalltalk level and far less on the VM primitive level.

Because:
1. Concurrency bugs can be subtle and the *exact* conditions can be
hard to reproduce for debugging.  For example, the solution to a
couple of problems with Delay [1] [2] were solved by moving away from
Semaphore>>critical: to use signalling.

2. The in-image atomicity of determining whether a signal was actually
consumed or not during process suspension/termination is awkward.  Its
seems hard to *really* know for sure it right (but I haven't looked in
depth into Denis' latest proposals.)

3. The existing in-image implementation of Semaphore>>critical messes
around in  Process>>terminate in a *special* way that is not easy for
those 100 eyes to understand. For example, I personally am not
comfortable with understanding how the special Semaphore handling in
Process>>terminate works, but I can easily follow how
primitiveEnterCriticalSection just looking at the code [3].

Points 2 & 3 might possibly be addressed by having new primitiveWaitReturned
*always* return true, so if the process is terminated while waiting,
the assignment to signalConsumed doesn't occur...

 critical: mutuallyExcludedBlock
   signalConsumed := false.
   [
       signalConsumed := self primitiveWaitReturned.
       blockValue := mutuallyExcludedBlock value
   ] ensure: [ signalConsumed ifTrue: [self signal] ].
   ^blockValue

where primitiveWait (https://git.io/vuDjd) is copied
and (just guessing) the marked line added...

 primitiveWaitReturned
     | sema excessSignals activeProc inInterpreter |
     sema := self stackTop. "rcvr"
"==>>" self pop: argumentCount + 1 thenPush: objectMemory trueObject. "<<=="
    excessSignals := self fetchInteger: ExcessSignalsIndex ofObject: sema.
     excessSignals > 0
         ifTrue:
           [self storeInteger: ExcessSignalsIndex
                       ofObject: sema
                       withValue: excessSignals - 1]
         ifFalse:
           inInterpreter := instructionPointer >= objectMemory startOfMemory.
           activeProc := self activeProcess.
           self addLastLink: activeProc toList: sema.
           self transferTo: self wakeHighestPriority from: CSWait.
           self
forProcessPrimitiveReturnToExecutivePostContextSwitch: inInterpreter]

which I guess could be added quickly if Esteban could compile the
latest pharo-spur-vm ;)

cheers -ben

Won't work, there's no guarantee thread has actually ran and signalConsumed been assigned the primitive result after Semaphore resumed the waiting thread, before  a higher priority thread runs and terminates it. (which is exactly the case handled by special code in #terminate)

Cheers,
Henry