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 mailto: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:
- 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.
- 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.)
- 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 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