Leon Matthes uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.threaded-LM.3347.mcz
==================== Summary ====================
Name: VMMaker.threaded-LM.3347 Author: LM Time: 21 November 2023, 7:55:00.548716 pm UUID: 164c9256-6fc6-4fbe-b07b-4931fecaddff Ancestors: VMMaker.threaded-LM.3346
Add argument to ownVM to provide custom flags.
Required for FFI callout flag when an exception occurs.
=============== Diff against VMMaker.threaded-LM.3346 ===============
Item was changed: ----- Method: CoInterpreterMT>>ownVM: (in category 'vm scheduling') ----- ownVM: vmThreadHandle <public> <inline: false> <var: #vmThreadHandle type: #'void *'> + ^ self ownVM: vmThreadHandle withFlags: 0! - <var: #vmThread type: #'CogVMThread *'> - "This is the entry-point for plugins and primitives that wish to reacquire the VM after having - released it via disownVM or callbacks that want to acquire it without knowing their ownership - status. This call will block until the VM is owned by the current thread or an error occurs. - The argument should be the value answered by disownVM, or 0 for callbacks that don't know - if they have disowned or not. This is both an optimization to avoid having to query thread- - local storage for the current thread's index (since it can easily keep it in some local variable), - and a record of when an unbound process becomes affined to a thread for the dynamic - extent of some operation. - - Answer 0 if the current thread is known to the VM (and on return owns the VM). - Answer 1 if the current thread is unknown to the VM and takes ownership. - Answer -1 if the current thread is unknown to the VM and fails to take ownership." - | flags vmThread | - vmThread := self cCoerce: vmThreadHandle to: #'CogVMThread *'. - vmThread ifNil: - [^self ownVMFromUnidentifiedThread]. - - self assert: vmThread = (cogThreadManager vmThreadAt: vmThread index). - - flags := vmThread disownFlags. - - (flags anyMask: DisownVMForProcessorRelinquish) ifTrue: - ["Presumably we have nothing to do; this primitive is typically called from the - background process. So we should /not/ try and activate any threads in the - pool; they will waste cycles finding there is no runnable process, and will - cause a VM abort if no runnable process is found. But we /do/ want to allow - FFI calls that have completed, or callbacks a chance to get into the VM; they - do have something to do. DisownVMForProcessorRelinquish indicates this." - relinquishing := false. - self sqLowLevelMFence]. - - vmThread := cogThreadManager acquireVMFor: vmThread. - disownCount := disownCount - 1. - - disowningVMThread ifNotNil: - [vmThread = disowningVMThread ifTrue: - [self assert: (vmThread cFramePointer isNil - or: [CFramePointer = vmThread cFramePointer and: [CStackPointer = vmThread cStackPointer]]). - self assert: self successful. - self assert: (objectMemory fetchPointer: MyListIndex ofObject: self activeProcess) = objectMemory nilObject. - disowningVMThread := nil. - cogit recordEventTrace ifTrue: - [self recordTrace: TraceOwnVM thing: ConstOne source: 0]. - ^0]. "if not preempted we're done." - self preemptDisowningThread]. - - "We've been preempted; we must restore state and update the threadId - in our process, and may have to put the active process to sleep." - self restoreVMStateFor: vmThread andFlags: flags. - - cogit recordEventTrace ifTrue: - [self recordTrace: TraceOwnVM thing: ConstTwo source: 0]. - ^flags bitAnd: OwnVMForeignThreadFlag!
Item was added: + ----- Method: CoInterpreterMT>>ownVM:withFlags: (in category 'vm scheduling') ----- + ownVM: vmThreadHandle withFlags: additionalFlags + <public> + <inline: false> + <var: #vmThreadHandle type: #'void *'> + <var: #vmThread type: #'CogVMThread *'> + "This is the entry-point for plugins and primitives that wish to reacquire the VM after having + released it via disownVM or callbacks that want to acquire it without knowing their ownership + status. This call will block until the VM is owned by the current thread or an error occurs. + The argument should be the value answered by disownVM, or 0 for callbacks that don't know + if they have disowned or not. This is both an optimization to avoid having to query thread- + local storage for the current thread's index (since it can easily keep it in some local variable), + and a record of when an unbound process becomes affined to a thread for the dynamic + extent of some operation. + + Answer 0 if the current thread is known to the VM (and on return owns the VM). + Answer 1 if the current thread is unknown to the VM and takes ownership. + Answer -1 if the current thread is unknown to the VM and fails to take ownership." + | flags vmThread | + vmThread := self cCoerce: vmThreadHandle to: #'CogVMThread *'. + vmThread ifNil: + [^self ownVMFromUnidentifiedThread]. + + self assert: vmThread = (cogThreadManager vmThreadAt: vmThread index). + + flags := vmThread disownFlags bitOr: additionalFlags. + + (flags anyMask: DisownVMForProcessorRelinquish) ifTrue: + ["Presumably we have nothing to do; this primitive is typically called from the + background process. So we should /not/ try and activate any threads in the + pool; they will waste cycles finding there is no runnable process, and will + cause a VM abort if no runnable process is found. But we /do/ want to allow + FFI calls that have completed, or callbacks a chance to get into the VM; they + do have something to do. DisownVMForProcessorRelinquish indicates this." + relinquishing := false. + self sqLowLevelMFence]. + + vmThread := cogThreadManager acquireVMFor: vmThread. + disownCount := disownCount - 1. + + disowningVMThread ifNotNil: + [vmThread = disowningVMThread ifTrue: + [self assert: (vmThread cFramePointer isNil + or: [CFramePointer = vmThread cFramePointer and: [CStackPointer = vmThread cStackPointer]]). + self assert: self successful. + self assert: (objectMemory fetchPointer: MyListIndex ofObject: self activeProcess) = objectMemory nilObject. + disowningVMThread := nil. + cogit recordEventTrace ifTrue: + [self recordTrace: TraceOwnVM thing: ConstOne source: 0]. + ^0]. "if not preempted we're done." + self preemptDisowningThread]. + + "We've been preempted; we must restore state and update the threadId + in our process, and may have to put the active process to sleep." + self restoreVMStateFor: vmThread andFlags: flags. + + cogit recordEventTrace ifTrue: + [self recordTrace: TraceOwnVM thing: ConstTwo source: 0]. + ^flags bitAnd: OwnVMForeignThreadFlag!
Item was changed: ----- Method: InterpreterPrimitives>>primitiveFailForFFIException:at: (in category 'primitive support') ----- primitiveFailForFFIException: exceptionCode at: pc <var: 'exceptionCode' type: #usqLong> <var: 'pc' type: #usqInt> "Set PrimErrFFIException primitive failure and associated exceptionCode (a.k.a. secondaryErrorCode) and exceptionPC. Under control of the ffiExceptionResponse flag, if in a primitive with an error code and the inFFIFlags indicate we're in an FFI call, then fail the primitive. ffiExceptionResponse < 0 never fail ffiExceptionResponse = 0 fail if method has a primitive error code (default) ffiExceptionResponse > 0 always fail" <public> ((inFFIFlags noMask: DisownVMForFFICall) "i.e. not in an FFI call" or: [ffiExceptionResponse < 0]) ifTrue: "i.e. never fail" [^self]. secondaryErrorCode := self cCoerceSimple: exceptionCode to: #sqLong. exceptionPC := pc. primFailCode := PrimErrFFIException. (ffiExceptionResponse > 0 "always fail..." or: [(objectMemory isOopCompiledMethod: newMethod) and: [self methodUsesPrimitiveErrorCode: newMethod]]) ifTrue: + [self ownVM: nil withFlags: DisownVMForFFICall. "To take ownership but importantly to reset inFFIFlags" - [self ownVM: DisownVMForFFICall. "To take ownership but importantly to reset inFFIFlags" self activateFailingPrimitiveMethod]!
Item was changed: ----- Method: StackInterpreter>>ownVM: (in category 'vm scheduling') ----- ownVM: threadIndexAndFlags <public> <inline: false> + ^ self ownVM: threadIndexAndFlags withFlags: 0! - "This is the entry-point for plugins and primitives that wish to reacquire the VM after having - released it via disownVM or callbacks that want to acquire it without knowing their ownership - status. While this exists for the threaded FFI VM we use it to reset newMethod and the - argumentCount after a callback. - - Answer -1 if the current thread is unknown to the VM and fails to take ownership." - <var: 'amInVMThread' declareC: 'extern sqInt amInVMThread(void)'> - self cppIf: COGMTVM - ifTrue: - [self amInVMThread ifFalse: - [^-1]]. - - self assert: ((objectMemory isOopCompiledMethod: newMethod) - and: [(self argumentCountOf: newMethod) = argumentCount]). - - "Hack encodings of client state. We use non-immediates (bottom three bits clear) - for FFI/Plugin doing - save := self disownVM: FLAGS. ... callout ... self ownVM: save. - We use immediate integer (bottom bit 1) for callbacks doing - save := self ownVM: 0. ... callback ... self disownVM: save. return to C" - - "If DisownVMForFFICall this is from the FFI plugin and we're returning from a callout." - (threadIndexAndFlags anyMask: DisownVMForFFICall) ifTrue: - [inFFIFlags := 0. - ^threadIndexAndFlags]. - - "Otherwise this is a callback; stash newMethod on the stack and encode - argumentCount in the flags retrieved when the calback calls disownVM:." - self assert: primFailCode = 0. - self push: newMethod. - ^objectMemory integerObjectOf: argumentCount!
Item was added: + ----- Method: StackInterpreter>>ownVM:withFlags: (in category 'vm scheduling') ----- + ownVM: threadIndexAndFlags withFlags: additionalFlags + <public> + <inline: false> + "This is the entry-point for plugins and primitives that wish to reacquire the VM after having + released it via disownVM or callbacks that want to acquire it without knowing their ownership + status. While this exists for the threaded FFI VM we use it to reset newMethod and the + argumentCount after a callback. + + Answer -1 if the current thread is unknown to the VM and fails to take ownership." + <var: 'amInVMThread' declareC: 'extern sqInt amInVMThread(void)'> + | flags | + flags := threadIndexAndFlags bitOr: additionalFlags. + self cppIf: COGMTVM + ifTrue: + [self amInVMThread ifFalse: + [^-1]]. + + self assert: ((objectMemory isOopCompiledMethod: newMethod) + and: [(self argumentCountOf: newMethod) = argumentCount]). + + "Hack encodings of client state. We use non-immediates (bottom three bits clear) + for FFI/Plugin doing + save := self disownVM: FLAGS. ... callout ... self ownVM: save. + We use immediate integer (bottom bit 1) for callbacks doing + save := self ownVM: 0. ... callback ... self disownVM: save. return to C" + + "If DisownVMForFFICall this is from the FFI plugin and we're returning from a callout." + (flags anyMask: DisownVMForFFICall) ifTrue: + [inFFIFlags := 0. + ^flags]. + + "Otherwise this is a callback; stash newMethod on the stack and encode + argumentCount in the flags retrieved when the calback calls disownVM:." + self assert: primFailCode = 0. + self push: newMethod. + ^objectMemory integerObjectOf: argumentCount!
vm-dev@lists.squeakfoundation.org