A new version of System was added to project The Inbox:
http://source.squeak.org/inbox/System-mt.1161.mcz ==================== Summary ==================== Name: System-mt.1161 Author: mt Time: 26 May 2020, 5:28:43.825729 pm UUID: 5a830b9f-86d0-194c-b3a5-165e915ff666 Ancestors: System-mt.1160 Propose SystemPlatform and mechanism to detect platform changes at image startup. Implementation is based on Monty's FFIExternalSharedPoolPlatform from the FFI-Pools package. WHY? Can be used to manage platform-specific caches such as FFI's external structures or specifics in other VM plugins. =============== Diff against System-mt.1160 =============== Item was added: + ----- Method: ClassDescription>>systemPlatformChanged (in category '*System-Support') ----- + systemPlatformChanged + "Access the current platform via SystemPlatform class >> #current."! Item was added: + ----- Method: ClassDescription>>systemPlatformChangedFrom: (in category '*System-Support') ----- + systemPlatformChangedFrom: lastPlatform + "Access the current platform via SystemPlatform class >> #current." + + self systemPlatformChanged.! Item was added: + ----- Method: ClassDescription>>systemPlatformChangedFrom:to: (in category '*System-Support') ----- + systemPlatformChangedFrom: lastPlatform to: currentPlatform + + self systemPlatformChangedFrom: currentPlatform.! Item was added: + Object subclass: #SystemPlatform + instanceVariableNames: 'name osVersion subtype wordSize' + classVariableNames: 'LastPlatform' + poolDictionaries: '' + category: 'System-Support'! + + !SystemPlatform commentStamp: 'mt 5/26/2020 16:30' prior: 0! + This class stores the host platform information to support testing instances for platform compatibility and specificity. + + At image startup time, a change of platform will result in a call back so that interested classes can recalibrate external dependencies.! Item was added: + ----- Method: SystemPlatform class>>current (in category 'accessing') ----- + current + ^ LastPlatform ifNil: [LastPlatform := self newCurrent]! Item was added: + ----- Method: SystemPlatform class>>initialize (in category 'class initialization') ----- + initialize + "Make sure to detect a platform change as soon as possible on startup." + + Smalltalk addToStartUpList: self after: DateAndTime.! Item was added: + ----- Method: SystemPlatform class>>name: (in category 'instance creation') ----- + name: aName + ^ self new name: aName! Item was added: + ----- Method: SystemPlatform class>>name:osVersion: (in category 'instance creation') ----- + name: aName osVersion: anOSVersionString + ^ self new + name: aName; + osVersion: anOSVersionString! Item was added: + ----- Method: SystemPlatform class>>name:osVersion:subtype: (in category 'instance creation') ----- + name: aName osVersion: anOSVersionString subtype: aSubtypeString + ^ self new + name: aName; + osVersion: anOSVersionString; + subtype: aSubtypeString! Item was added: + ----- Method: SystemPlatform class>>name:osVersion:subtype:wordSize: (in category 'instance creation') ----- + name: aName osVersion: anOSVersionString subtype: aSubtypeString wordSize: aWordSize + ^ self new + name: aName; + osVersion: anOSVersionString; + subtype: aSubtypeString; + wordSize: aWordSize! Item was added: + ----- Method: SystemPlatform class>>name:wordSize: (in category 'instance creation') ----- + name: aName wordSize: aWordSize + ^ self new + name: aName; + wordSize: aWordSize! Item was added: + ----- Method: SystemPlatform class>>newCurrent (in category 'instance creation') ----- + newCurrent + + ^ self + name: Smalltalk os platformName + osVersion: Smalltalk osVersion + subtype: Smalltalk os platformSubtype + wordSize: Smalltalk wordSize! Item was added: + ----- Method: SystemPlatform class>>startUp: (in category 'system startup') ----- + startUp: resuming + "Notify all classes about platform changes." + + resuming ifTrue: [ + LastPlatform in: [:lastPlatform | self newCurrent in: [:currentPlatform | + lastPlatform = currentPlatform ifFalse: [ + LastPlatform := currentPlatform. + Object withAllSubclassesDo: [:cls | + cls systemPlatformChangedFrom: lastPlatform to: currentPlatform]]]]].! Item was added: + ----- Method: SystemPlatform>>= (in category 'comparing') ----- + = anObject + self == anObject + ifTrue: [^ true]. + + self species == anObject species + ifFalse: [^ false]. + + ^ self name = anObject name + and: [self osVersion = anObject osVersion + and: [self subtype = anObject subtype + and: [self wordSize = anObject wordSize]]].! Item was added: + ----- Method: SystemPlatform>>hasName (in category 'testing') ----- + hasName + ^ self name notEmpty! Item was added: + ----- Method: SystemPlatform>>hasOSVersion (in category 'testing') ----- + hasOSVersion + ^ self osVersion notEmpty! Item was added: + ----- Method: SystemPlatform>>hasSubtype (in category 'testing') ----- + hasSubtype + ^ self subtype notEmpty! Item was added: + ----- Method: SystemPlatform>>hasWordSize (in category 'testing') ----- + hasWordSize + ^ self wordSize notNil! Item was added: + ----- Method: SystemPlatform>>hash (in category 'comparing') ----- + hash + ^ (((self species hash bitXor: + self name hash) bitXor: + self osVersion hash) bitXor: + self subtype hash) bitXor: + self wordSize hash! Item was added: + ----- Method: SystemPlatform>>isARM (in category 'testing') ----- + isARM + "E.g., Raspberry PI" + + ^ self subtype asLowercase beginsWith: 'arm'! Item was added: + ----- Method: SystemPlatform>>isCompatibleWith: (in category 'testing - compatibility') ----- + isCompatibleWith: aPlatform + self == aPlatform + ifTrue: [^ true]. + + (self name = aPlatform name + or: [self hasName not + or: [aPlatform hasName not]]) + ifFalse: [^ false]. + + (self osVersion = aPlatform osVersion + or: [self hasOSVersion not + or: [aPlatform hasOSVersion not]]) + ifFalse: [^ false]. + + (self subtype = aPlatform subtype + or: [self hasSubtype not + or: [aPlatform hasSubtype not]]) + ifFalse: [^ false]. + + (self wordSize = aPlatform wordSize + or: [self hasWordSize not + or: [aPlatform hasWordSize not]]) + ifFalse: [^ false]. + + ^ true.! Item was added: + ----- Method: SystemPlatform>>isMacOS (in category 'testing') ----- + isMacOS + + ^ self name asLowercase beginsWith: 'mac'! Item was added: + ----- Method: SystemPlatform>>isMoreSpecificThan: (in category 'testing - compatibility') ----- + isMoreSpecificThan: aPlatform + self == aPlatform + ifTrue: [^ false]. + + (self hasName + and: [aPlatform hasName not]) + ifTrue: [^ true]. + + (self hasOSVersion + and: [aPlatform hasOSVersion not]) + ifTrue: [^ true]. + + (self hasSubtype + and: [aPlatform hasSubtype not]) + ifTrue: [^ true]. + + (self hasWordSize + and: [aPlatform hasWordSize not]) + ifTrue: [^ true]. + + ^ false.! Item was added: + ----- Method: SystemPlatform>>isRiscOS (in category 'testing') ----- + isRiscOS + + ^ self name asLowercase beginsWith: 'risc'! Item was added: + ----- Method: SystemPlatform>>isUnix (in category 'testing') ----- + isUnix + + ^ self name asLowercase beginsWith: 'unix'! Item was added: + ----- Method: SystemPlatform>>isWeb (in category 'testing') ----- + isWeb + "SqueakJS" + + ^ self name asLowercase beginsWith: 'web'! Item was added: + ----- Method: SystemPlatform>>isWindows (in category 'testing') ----- + isWindows + + ^ self name asLowercase beginsWith: 'win'! Item was added: + ----- Method: SystemPlatform>>name (in category 'accessing') ----- + name + ^ name ifNil: [name := '']! Item was added: + ----- Method: SystemPlatform>>name: (in category 'accessing') ----- + name: aName + name := aName! Item was added: + ----- Method: SystemPlatform>>osVersion (in category 'accessing') ----- + osVersion + ^ osVersion ifNil: [osVersion := '']! Item was added: + ----- Method: SystemPlatform>>osVersion: (in category 'accessing') ----- + osVersion: anOSVersionString + osVersion := anOSVersionString! Item was added: + ----- Method: SystemPlatform>>printOn: (in category 'printing') ----- + printOn: aStream + self storeOn: aStream! Item was added: + ----- Method: SystemPlatform>>storeOn: (in category 'printing') ----- + storeOn: aStream + aStream + nextPut: $(; + nextPutAll: self class name asString; + nextPutAll: ' name: '; + print: self name; + nextPutAll: ' osVersion: '; + print: self osVersion; + nextPutAll: ' subtype: '; + print: self subtype; + nextPutAll: ' wordSize: '; + print: self wordSize; + nextPut: $).! Item was added: + ----- Method: SystemPlatform>>subtype (in category 'accessing') ----- + subtype + ^ subtype ifNil: [subtype := '']! Item was added: + ----- Method: SystemPlatform>>subtype: (in category 'accessing') ----- + subtype: aSubtypeString + subtype := aSubtypeString! Item was added: + ----- Method: SystemPlatform>>wordSize (in category 'accessing') ----- + wordSize + ^ wordSize! Item was added: + ----- Method: SystemPlatform>>wordSize: (in category 'accessing') ----- + wordSize: aWordSize + wordSize := aWordSize! |
1) Is "SystemPlatform" a fitting name? Alternatives: ExternalPlatform, HostPlatform, ... 2) Is it useful to document the known platform shorthands via #isWindows, #isARM, etc.? 3) Is it necessary to access the last platform and the current platform in that #systemPlatformChangedFrom:to: callback? Would #systemPlatformChanged be sufficient? 4) What are your thoughts on #isCompatibleWith: and #isMoreSpecificThan:? 5) Is it too specific to FFI to be in the "System" package? Can you think of VM plugins that would benefit from such a detection? Not sure about FileDirectory ... because those instances become invalid after startup anyway. Best, Marcel
|
6) Is it viable to assume that all kinds of platform-specific caches would and could synchronize with such a central mechanism? Or do we need a class-specific "lastPlatform" solution? Compare FFIExternalSharedPool (class-side inst-var) with ExternalStructure (class-var). Best, Marcel
|
In reply to this post by marcel.taeumel
On 26/05/20 9:13 pm, Marcel Taeumel wrote:
> 1) Is "SystemPlatform" a fitting name? Alternatives: ExternalPlatform, > HostPlatform, ... HostPlatform gets my vote. System is a much abused word :-). > 2) Is it useful to document the known platform shorthands via > #isWindows, #isARM, etc.? I prefer HostPlatform to be an abstract class with UnixHostPlatform or MacHostPlatform subclasses like in OSProcess. Having such concrete classes also makes it easy to create OS-specific code without having to use statements like 'name asLowercase ....' all over the image. > 3) Is it necessary to access the last platform and the current platform > in that #systemPlatformChangedFrom:to: callback? Would > #systemPlatformChanged be sufficient? The host platform changes only during cold start. why not name it coldStartOn: and pass the concrete class as an argument? Checking for platform change across every snapshot would be an overkill. > > 4) What are your thoughts on #isCompatibleWith: and #isMoreSpecificThan:? Not sure if they are really needed at this time. > 5) Is it too specific to FFI to be in the "System" package? Can you > think of VM plugins that would benefit from such a detection? Not sure > about FileDirectory ... because those instances become invalid after > startup anyway. No. Being able to reflect on host platform's properties will help platform-specific code degrade gracefully on unsupported hosts. While multiplatform capability is a good feature during development, I suppose most apps would run on the same host for years together. Regards .. Subbu |
Please have a look at Pharo's OSPlatform class Marcel. If some if its interface and purpose fit, we should make it easier to port code. K K Subbu <[hidden email]> schrieb am Di., 26. Mai 2020, 19:31: On 26/05/20 9:13 pm, Marcel Taeumel wrote: |
> Please have a look at Pharo's OSPlatform class Marcel.
I will. Current goal is to refactor FFIExternalSharedPoolPlatform from FFI-Pools. One step at a time. :-) > HostPlatform gets my vote. System is a much abused word :-) Think about HostWindowPlugin, this might work. Eliot suggested FFIPlatformDescription; and to keep it in the FFI package for now, I suppose. See: http://forum.world.st/FFI-FFIExternalSharedPoolPlatform-ExternalPlatform-or-FFIPlatform-or-tp5117240p5117255.html > Checking for platform change across every snapshot would be an overkill. This inbox submission does only inform about platform changes on such "cold starts", which is reflected in the "resuming" (somtimes called "afresh") argument in #startUp:. > I prefer HostPlatform to be an abstract class with UnixHostPlatform or MacHostPlatform subclasses like in OSProcess. Hmm.... -1 :-) This would encourage to put more stuff into those subclasses. I think that a simple #isUnix etc. check should suffice in most cases. From there, you can employ any host-platform specific class that you application (or framework or library) has prepared for such a domain. No need to put it too much bloat in such a lightweight mechanism for the base system. Best, Marcel
|
Hi Jacob, I just briefly looked at OSPlatform (and subclasses) in Pharo 7. I think those classes try to hold too much information from too many domains, which is sparkling a need for those platform subclasses. Take #defaultMaximumPathLength as an example, which is implemented in MacOSPlatform, UnixPlatform, and WinPlatform. Personally, I think that such an information should be encoded in the module that represents the file-bridge from the host-platform to the image. In that bridge, you can either configure the maximum path length, or you have a platform-specific file-bridge classes anyway, which would then be in the correct domain and can then hold the #defaultMaximumPathLength. Not a generic OSPlatform object, or a still to generic subclass of it. Having domain-specific bridge classes fosters division of labor. People don't have to touch (correct or extend) the same (e.g. OSPlatform) classes while working on different concerns (e.g. files, sockets, FFI-Kernel, ...). See that "divergent change" code smell from the Refactoring Catalogue (Martin Fowler, Kent Beck). Best, Marcel
|
Hey Marcel,
* Marcel Taeumel <[hidden email]> [200527 08:37]: > Hi Jacob, > > I just briefly looked at OSPlatform (and subclasses) in Pharo 7. I think those classes try to hold too much information from too many domains, which is sparkling a need for those platform subclasses. If I may chime in, I did a port of Pharo to OpenBSD once, got it barely running with all its ancient deps at the time... But what has bitten me a lot in the FFI interface has been the assumption that 'unix' means linux and there has been no easy way to further distinguish the subtle differences. Such as the architecture name for the 64bit platform, which is 'amd64' for OpenBSD as an easy example. That has lead to ugly code which would have been resolvable with more refactoring and fiddling apart the unix class into more subclasses but I was a beginning smalltalker and fiddling with an integral part of the Pharo image seemed daunting. So I guess my summary is: If you settle for something called 'unix' don't make assumptions that it's linux like, instead make it easy to subclass it further. Thanks! Christian -- May you be peaceful, may you live in safety, may you be free from suffering, and may you live with ease. |
Hi Christian. Thanks for the info! :-) I suppose that the platform name 'unix' can only be a starting point for any platform-specific code. There is already #platformSubtype. You are right. If bridge classes tend to duplicate such specialization logic, it makes sense to move it back to a generic platform object for other bridge classes to re-use. At best, one can generalize any subtlety to something that can be answered for all operating systems. Then, the question of subclassing vs. (state) composition is just a matter of taste. Thinking about which layer moves faster than another, I prefer looking for #wordSize etc. over looking for #isUnix etc. If operating systems follow some standards (such as POSIX), this approach might lead to cleaner in-image code. :-) Not sure. Best, Marcel
|
* Marcel Taeumel <[hidden email]> [200527 11:07]:
> Thinking about which layer moves faster than another, I prefer looking for #wordSize etc. over looking for #isUnix etc. If operating systems follow some standards (such as POSIX), this approach might lead to cleaner in-image code. :-) Not sure. Agreed, testing for needed features rather than assuming features hidden behind labels is the better approach. Although tons of software out there walks down the other route. -- May you be peaceful, may you live in safety, may you be free from suffering, and may you live with ease. |
In reply to this post by marcel.taeumel
On 27/05/20 11:55 am, Marcel Taeumel wrote:
>> I prefer HostPlatform to be an abstract class with UnixHostPlatform or > MacHostPlatform subclasses like in OSProcess. > > Hmm.... -1 :-) This would encourage to put more stuff into those > subclasses. I think that a simple #isUnix etc. check should suffice in > most cases. From there, you can employ any host-platform specific class > that you application (or framework or library) has prepared for such a > domain. No need to put it too much bloat in such a lightweight mechanism > for the base system. Yes, we need to watch out for code bloat. I only wanted to point out the risk of conflation between platform (user/kernel interface), system (kernel/hardware interface), data model (ILP32, ILP64, LP64, LLP64 etc.) and ISA (x86, amd64, arm, arm64..). #isUnix is too broad a check. Perhaps a separate thread may be needed to explore conflation risk. Regards .. Subbu |
Free forum by Nabble | Edit this page |