The Inbox: Kernel-jar.1377.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Kernel-jar.1377.mcz

commits-2
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-jar.1377.mcz

==================== Summary ====================

Name: Kernel-jar.1377
Author: jar
Time: 3 March 2021, 11:06:44.192499 pm
UUID: b99e562a-887b-7e4e-9c11-6818ca1acaeb
Ancestors: Kernel-nice.1376

Fix inconsistent bahavior in #isTerminated and #isSuspended

=============== Diff against Kernel-nice.1376 ===============

Item was changed:
  ----- Method: Process>>isSuspended (in category 'testing') -----
  isSuspended
+ "A process is suspended if it has non-nil suspendedContext (e.g. new or
+ previously suspended with the suspend primitive) and is not terminated or
+ waiting in a scheduler or a semaphore queue (i.e. is not runnable or blocked)."
+
+ ^myList isNil
+ and: [suspendedContext notNil]
+ and: [self isTerminated not]!
- "A process is suspended if it has been suspended with the suspend primitive.
- It is distinguishable from the active process and a terminated process by
- having a non-nil suspendedContext that is either not the bottom context
- or has not reached its endPC."
- ^nil == myList
-  and: [nil ~~ suspendedContext
-  and: [suspendedContext isBottomContext
- ifTrue: [suspendedContext closure
- ifNil: [suspendedContext methodClass ~~ Process
- or: [suspendedContext selector ~~ #terminate]]
- ifNotNil: [suspendedContext pc < suspendedContext closure endPC]]
- ifFalse: [true]]]!

Item was changed:
  ----- Method: Process>>isTerminated (in category 'testing') -----
  isTerminated
+ "Answer if the receiver is terminated, or at least terminating, i.e. if one
+ of the following conditions is satisfied:
+ (1) the receiver is a defunct process (suspendedContext = nil or pc = nil)
+ (2) we catch the active process termination by adding a first temporary
+ in Process>>terminate called terminationStatus and having Process>>
+ terminate assign #terminated to it when termination is essentially complete
+ (3) the suspendedContext is the bottomContext and the pc is at the endPC"
+
+ self isActiveProcess ifTrue: [^false].
- "Answer if the receiver is terminated, or at least terminating."
- self isActiveProcess ifTrue: [^ false].
  ^suspendedContext isNil
+ or: [suspendedContext isDead]
+ or: [suspendedContext methodClass == Process
+ and: [suspendedContext selector == #terminate]
+ and: [(suspendedContext tempAt: 1) == #terminated]]
+ or: [suspendedContext isBottomContext and: [suspendedContext atEnd]]!
-  or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess.
-   If so, and the pc is at the endPC, the block has already sent and returned
-   from value and there is nothing more to do."
- suspendedContext isBottomContext
- and: [suspendedContext closure
- ifNil: [suspendedContext methodClass == Process
- and: [suspendedContext selector == #terminate]]
- ifNotNil: [suspendedContext pc >= suspendedContext closure endPC]]]!

Item was changed:
  ----- Method: Process>>terminate (in category 'changing process state') -----
  terminate
  "Stop the process that the receiver represents forever.
  Unwind to execute pending ensure:/ifCurtailed: blocks before terminating.
  If the process is in the middle of a critical: critical section, release it properly."
 
+ | terminationStatus ctxt unwindBlock oldList |
- | ctxt unwindBlock oldList |
  self isActiveProcess ifTrue:
  [ctxt := thisContext.
  [ctxt := ctxt findNextUnwindContextUpTo: nil.
   ctxt ~~ nil] whileTrue:
  [(ctxt tempAt: 2) ifNil:
  ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to true."
  unwindBlock := ctxt tempAt: 1.
  thisContext terminateTo: ctxt.
  unwindBlock value]].
  thisContext terminateTo: nil.
+ terminationStatus := #terminated.
  self suspend.
  "If the process is resumed this will provoke a cannotReturn: error.
  Would self debug: thisContext title: 'Resuming a terminated process' be better?"
  ^self].
 
  "Always suspend the process first so it doesn't accidentally get woken up.
  N.B. If oldList is a LinkedList then the process is runnable. If it is a Semaphore/Mutex et al
  then the process is blocked, and if it is nil then the process is already suspended."
  oldList := self suspend.
  suspendedContext ifNotNil:
  ["Release any method marked with the <criticalSection> pragma.
   The argument is whether the process is runnable."
  self releaseCriticalSection: (oldList isNil or: [oldList class == LinkedList]).
 
  "If terminating a process halfways through an unwind, try to complete that unwind block first."
  (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil:
  [:outer|
  (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt: 1)]) ifNotNil:
  [:inner| "This is an unwind block currently under evaluation"
  suspendedContext runUntilErrorOrReturnFrom: inner]].
 
  ctxt := self popTo: suspendedContext bottomContext.
  ctxt == suspendedContext bottomContext ifFalse:
  [self debug: ctxt title: 'Unwind error during termination'].
  "Set the context to its endPC for the benefit of isTerminated."
  ctxt pc: ctxt endPC]!


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-jar.1377.mcz

Jaromir Matas
Fix inconsistent bahavior in #isTerminated and #isSuspended


Following up on a discussion with Eliot (
http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html
<http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html>  ) I'm
proposing changes to #isTerminated, #isSuspended and Eliot's hack to
#terminate to remove inconsistency in reporting the termination status in
some rare cases.


A suggestion: When a process is terminated and later resumed it raises a
cannotReturn: error. Is raising an error/debugger desirable? Looping the
resumed process back to terminate would do no harm and raise no error...

terminate
        "Stop the process that the receiver represents forever.
         Unwind to execute pending ensure:/ifCurtailed: blocks before terminating.
         If the process is in the middle of a critical: critical section, release
it properly."

        | terminationStatus ctxt unwindBlock oldList |
        self isActiveProcess ifTrue:
                [ctxt := thisContext.
                 [ctxt := ctxt findNextUnwindContextUpTo: nil.
                  ctxt ~~ nil] whileTrue:
                        [(ctxt tempAt: 2) ifNil:
                                ["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to
true."
                                 unwindBlock := ctxt tempAt: 1.
                                 thisContext terminateTo: ctxt.
                                 unwindBlock value]].
                thisContext terminateTo: nil.
                terminationStatus := #terminated.
                self suspend.
>>>        thisContext restart].  "add this and remove ^self below"

                "If the process is resumed this will provoke a cannotReturn: error.
                 Would self debug: thisContext title: 'Resuming a terminated process' be
better?"
                ^self].

                "..."


And finally: Is there a reason why processes created directly via Process
forContext:priority: are not subject to tests? Like e.g.:

        "These processes should be terminated, not suspended."
        self deny: (Process forContext: [Processor activeProcess suspend] priority:
Processor activePriority + 1) resume isSuspended.
        self assert: (Process forContext: [Processor activeProcess suspend]
priority: Processor activePriority + 1) resume isTerminated.

If not, I could add some...

regards,



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir