Leon Matthes uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.threaded-LM.3353.mcz
==================== Summary ====================
Name: VMMaker.threaded-LM.3353 Author: LM Time: 21 December 2023, 4:24:17.659525 pm UUID: c431b328-cc1f-49b9-8427-ebfc50b37d7e Ancestors: VMMaker.threaded-LM.3352
Do not make primitives pin themselves, rather check for pinned arguments as a condition for disowning.
Also: Increase size of VM Owner Log to 100Ki entries. TODO: Make VMOwnerLog optional for release builds.
=============== Diff against VMMaker.threaded-LM.3352 ===============
Item was changed: ----- Method: CoInterpreterMT>>loadInitialContext (in category 'initialization') ----- loadInitialContext | activeProc threadAffinity | super loadInitialContext. activeProc := self activeProcess. threadAffinity := self threadAffinityOfProcess: activeProc. + + self assert: (threadAffinity = 0 or: [threadAffinity = 1]). + self cCode: [] inSmalltalk: [self flag: #todoMT "Ensure we cannot save an image, where the 'activeProc' is affined to another thread!!"]. + + activeProcessAffined := threadAffinity ~= 0! - self assert: (threadAffinity = 0 or: [threadAffinity = 1]). "TODO: Ensure we cannot save an image, where the 'activeProc' is affined to another thread!!" - activeProcessAffined := (self threadAffinityOfProcess: activeProc) ~= 0!
Item was changed: ----- Method: CogThreadManager class>>initialize (in category 'class initialization') ----- initialize "CogThreadManager initialize" CTMUninitialized := 0. CTMInitializing := 1. CTMUnavailable := 2. "off doing its own thing and not available to run the VM, e.g. calling-out." CTMAssignableOrInVM := 3. "either owning the VM or blocked on its osSemaphore available for VM work" CTMWantingOwnership := 4. "with something specific to do in the VM (e.g. return a result from a call-out, make a call-back)" CTMUnknownOwner := -1.
"Define the size of the stack of processes at time of disown/own." AWOLProcessesIncrement := 4. + OwnerLogSize := 100 * 1024.! - OwnerLogSize := 1024.!
Item was changed: ----- Method: CogThreadManager>>copyLogTo: (in category 'logging') ----- copyLogTo: aPointer | bufferPointer bytesCopied index startIndex bytesToCopy | <var: #aPointer type: #'char *'> <var: #bufferPointer type: #'char *'> bufferPointer := aPointer. index := self atomic_load: (self addressOf: ownerLogIndex). bytesCopied := 0.
+ "NOTE: The ownerLogWrapped isn't synchronized atomically. Therefore, if this primitive is called exactly when we start wrapping the very first time, we'll read the wrong value here. + However, as this is very unlikely, don't bother fixing this (yet)." + ownerLogWrapped ifTrue: [ |entriesToSpare| + "NOTE: The owner log is still written to whilst this primitive is running. + Therefore copy only 90% of the log, such that the remaining 10% can be spared + to still be written." + entriesToSpare := OwnerLogSize / 10. + startIndex := index + entriesToSpare min: (OwnerLogSize - 1). - However, as this is very unlikely, don't bother fixing this yet." - ownerLogWrapped ifTrue: [ - "If we've reached the limit of our Ringbuffer, deliberately don't copy the last 100 entries, - so that new log entries don't overwrite during the memcpy." - startIndex := index + 100 min: (OwnerLogSize - 1). bytesToCopy := (OwnerLogSize - startIndex) * (self sizeof: CogVMOwnerLog). self memcpy: bufferPointer _: ownerLog + startIndex _: bytesToCopy. bytesCopied := bytesCopied + bytesToCopy].
bytesToCopy := index * (self sizeof: CogVMOwnerLog). self memcpy: bufferPointer + bytesCopied _: ownerLog _: bytesToCopy. bytesCopied := bytesCopied + bytesToCopy. ^ bytesCopied !
Item was changed: ----- Method: FilePlugin>>primitiveFileReadPinningAndDisowning (in category 'file primitives') ----- primitiveFileReadPinningAndDisowning "This version of primitiveFileRead is for garbage collectors that support pinning + and the multi-threaded VM. It actually does the own/disown dance if the bytearray is pinned." + | count startIndex array file slotSize elementSize bytesRead vmHandle | - and the multi-threaded VM. It actually does the own/disown dance." - | count startIndex array file slotSize elementSize bytesRead vmHandle wasPinned | <inline: true> <var: 'file' type: #'SQFile *'> <var: 'count' type: #'size_t'> <var: 'startIndex' type: #'size_t'> <var: 'slotSize' type: #'size_t'> <var: 'elementSize' type: #'size_t'> count := interpreterProxy positiveMachineIntegerValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positiveMachineIntegerValueOf: (interpreterProxy stackValue: 1). array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3). + vmHandle := nil.
(interpreterProxy failed "buffer can be any indexable words or bytes object except CompiledMethod" or: [(interpreterProxy isWordsOrBytes: array) not]) ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
slotSize := interpreterProxy slotSizeOf: array. (startIndex >= 1 and: [startIndex + count - 1 <= slotSize]) ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex]. + (interpreterProxy isPinned: array) ifTrue: + [vmHandle := interpreterProxy disownVM: DisownVMForThreading]. - (wasPinned := interpreterProxy isPinned: array) ifFalse: - [array := interpreterProxy pinObject: array]. - vmHandle := interpreterProxy disownVM: DisownVMForThreading. "Note: adjust startIndex for zero-origin byte indexing" elementSize := slotSize = 0 ifTrue: [1] ifFalse: [(interpreterProxy byteSizeOf: array) // slotSize]. bytesRead := self sqFile: file Read: count * elementSize Into: (interpreterProxy cCoerce: (interpreterProxy firstIndexableField: array) to: #'char *') At: startIndex - 1 * elementSize. + vmHandle ifNotNil: + [interpreterProxy ownVM: vmHandle]. + - interpreterProxy ownVM: vmHandle. - wasPinned ifFalse: - [interpreterProxy unpinObject: array]. interpreterProxy failed ifFalse: [interpreterProxy methodReturnInteger: bytesRead // elementSize] "answer # of elements read"!
Item was changed: ----- Method: SocketPlugin>>primitiveSocketCloseConnection: (in category 'primitives') ----- primitiveSocketCloseConnection: socket
| s | <var: #s type: 'SocketPtr '> self primitive: 'primitiveSocketCloseConnection' parameters: #(Oop). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [ + self sqSocketCloseConnection: s isPinned: (interpreterProxy isPinned: socket)]! - self sqSocketCloseConnection: s]!
Item was added: + ----- Method: SocketPluginSimulator>>sqSocketCloseConnection:isPinned: (in category 'simulation') ----- + sqSocketCloseConnection: socketHandleCArray isPinned: isPinned + + |result handle| + isPinned ifTrue: [handle := interpreterProxy disownVM: DisownVMForThreading]. + result := [Socket basicNew + primSocketCloseConnection: ((self hostSocketHandleFromSimSocketHandle: socketHandleCArray) ifNil: [^false])] + on: SocketPrimitiveFailed + do: [:ex| + interpreterProxy primitiveFail. + false]. + isPinned ifTrue: [interpreterProxy ownVM: handle]. + ^ result!
Item was changed: ----- Method: SqueakSSLPlugin>>primitiveConnect (in category 'primitives') ----- primitiveConnect "Primitive. Starts or continues a client handshake using the provided data. Will eventually produce output to be sent to the server. Requires the host name to be set for the session. Returns: > 0 - Number of bytes to be sent to the server 0 - Success. The connection is established. -1 - More input is required. < -1 - Other errors. " + | start srcLen dstLen srcOop dstOop handle srcPtr dstPtr result vmHandle canDisown | - | start srcLen dstLen srcOop dstOop handle srcPtr dstPtr result wasSrcPinned wasDestPinned vmHandle | <var: #srcPtr type: #'char *'> <var: #dstPtr type: #'char *'> <export: true> interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. dstOop := interpreterProxy stackValue: 0. srcLen := interpreterProxy stackIntegerValue: 1. start := interpreterProxy stackIntegerValue: 2. srcOop := interpreterProxy stackValue: 3. handle := interpreterProxy stackIntegerValue: 4. interpreterProxy failed ifTrue:[^nil]. ((start > 0 and:[srcLen >= 0]) and:[(interpreterProxy isBytes: srcOop) and:[(interpreterProxy isBytes: dstOop) and:[(interpreterProxy byteSizeOf: srcOop) >= (start + srcLen - 1)]]]) ifFalse:[^interpreterProxy primitiveFail]. - "Careful!! The object may move when being pinned!!" - (wasSrcPinned := interpreterProxy isPinned: srcOop) - ifFalse: [srcOop := interpreterProxy pinObject: srcOop]. - (wasDestPinned := interpreterProxy isPinned: dstOop) - ifFalse: [dstOop := interpreterProxy pinObject: dstOop]. - - "Pinning may fail (only if we're out of memory)" - (srcOop isNil or: [dstOop isNil]) - ifTrue: [^ interpreterProxy primitiveFail]. - srcPtr := interpreterProxy firstIndexableField: srcOop. dstPtr := interpreterProxy firstIndexableField: dstOop. srcPtr := srcPtr + start - 1. dstLen := interpreterProxy byteSizeOf: dstOop. + canDisown := (interpreterProxy isPinned: srcOop) and: [interpreterProxy isPinned: dstOop]. + canDisown ifTrue: [vmHandle := interpreterProxy disownVM: DisownVMForThreading]. - "vmHandle := interpreterProxy disownVM: DisownVMForThreading." result := self cCode: 'sqConnectSSL(handle, srcPtr, srcLen, dstPtr, dstLen)' inSmalltalk:[handle. srcPtr. srcLen. dstPtr. dstLen. -2]. + + canDisown ifTrue: [interpreterProxy ownVM: vmHandle]. - "interpreterProxy ownVM: vmHandle." - wasSrcPinned ifFalse: [interpreterProxy unpinObject: srcOop]. - wasDestPinned ifFalse: [interpreterProxy unpinObject: dstOop]. - interpreterProxy failed ifTrue:[^nil]. interpreterProxy pop: interpreterProxy methodArgumentCount+1. interpreterProxy pushInteger: result.!
vm-dev@lists.squeakfoundation.org