Hi Lou,
On Tue, Mar 5, 2013 at 2:38 PM, Louis LaBrunda Lou@keystone-software.comwrote:
I will bow to your knowledge of Squeak but take a look at the code below from VA Smalltalk.
Pay special attention to #resume: which looks to me like it puts the new process at the top of the queue (there are 7 queues, one for each priority) and puts the current (activeProcess) at the bottom of the same queue and then switches to the highestPriorityProcess. Which can be another process or the new process just put in front of the current process.
thanks, that's interesting, and good to know.
Don't ask my why it works this way. As I said, I added #forkReady which it seems works more like Squeak. Most of the time I think it doesn't matter but sometimes it does.
Lou
fork "Create a new Process which is scheduled by the ProcessScheduler. The new process executes the receiver by sending it the message value. The new process is created with the same prority as the activeProcess. Answer the receiver."
^self newProcess resume
resume "Tell the process scheduler to add the process to the ready to run queue."
self isResumable ifFalse: [^self error: (NlsCatKRN indexedMsg: 2)].
"$NLS$ process cannot be resumed" Processor resume: self. ^ self
resume: aProcess
| state | state := self enableAsyncMessages: false. (aProcess == self activeProcess or: [aProcess isDead]) ifTrue: [ self enableAsyncMessages: state. ^self "Resuming a dead process or the active process is a
nop."].
aProcess isRunable ifTrue: [ (aProcess processState: ##ready) queue addFirst: aProcess]. (self activeProcess processState: ##ready) queue addLast: self
activeProcess. self activeProcess switchTo: self highestPriorityProcess. self enableAsyncMessages: state
On Tue, 5 Mar 2013 13:46:13 -0800, Eliot Miranda eliot.miranda@gmail.com wrote:
On Tue, Mar 5, 2013 at 1:36 PM, Louis LaBrunda <Lou@keystone-software.com wrote:
Hi Eliot,
Thanks for all the very valuable information. I think I didn't ask my question properly but with all the answers I was able to accomplish
exactly
what I wanted.
I do have a question about one thing you said. See below.
Lou
On Thu, Feb 28, 2013 at 2:30 PM, Bert Freudenberg <
bert@freudenbergs.de
wrote:
On 2013-02-28, at 22:38, Louis LaBrunda Lou@Keystone-Software.com
wrote:
If a process is running when an image is saved, is the process
stopped at
any point in particular?
The active process is stopped in the snapshot primitive (a.k.a.
"image
saving") and resumes after it on startup. All other processes are
waiting
on some semaphore anyway.
Nope. No processes are stopped. Processes are simply unable to run
while
in the snapshot. The key to understanding this is understanding the scheduler (the Processor global, an instance of ProcessorSheduler). It maintains an activeProcess and a set of runnable processes,
implemented as
an Array of lists of processes at the same priority. A runnable
process
(one not sent suspend or not waiting on a semaphore) is either the activeProcess or on one of the lists. This state is saved to the
snapshot.
At any time the scheduler's activeProcess is the first highest
priority
process in the set of runnable processes. It will only be deposed as activeProcess when either another higher-priority process becomes
runnable
or it yields or suspends or waits on a semaphore. If it suspends or
waits
on a semaphore it is removed from the set of runnable processes. If it yields it gets sent to the back of its run-queue and the next process
in
that queue becomes the runnable process. If it is the only runnable process at its priority yield is a noop.
On loading the image the VM activates the activeProcess; the
activeProcess
will typically be in a method that has called the snapshot primitive
and
the system will continue, with the snapshot primitive answering true.
All
the other processes in the run queues are runnable but, just as before
the
snapshot, can't be run because the activeProcess is still runnable.
But
as
soon as the activeProcess suspends, waits or yields, one of these
processes
may run.
Several processes are terminated (terminate is suspend + run unwinds)
on
resuming the image. This is done to inform the VM of additional state
to
make these processes run. For example, the Delay process needs to tell
the
VM what the next delay expiry is on start-up. The delay semaphore (the semaphore the VM signals when the current active delay expires) is
saved
in
the image in the specialObjects array, so it persists across a
snapshot,
but the VM doesn't persist the current delay expiry time.
So any long-running process which doesn't need to inform the VM of
anything
special at start-up will just keep truckin' along, and nothing need be done. A snapshot really is like a fermata, a pause. It is not some
kind
of shut-down.
As a side-note what happens if one does
[Semaphore new wait] fork.
Processor activeProcess yield.
?
This creates a new process and adds it to the Processor's run queue.
Once
the process has been sent fork the current process doesn't reference it since it has been popped from the current process's stack, and so the
only
reference to the new process is from one of the Processors' run queues,
but
it isn't running yet because the activeProcess (the one that sent
fork) is
running. When the activeProcess yields the new process gets to run.
Once
it has created the new semaphore it sends wait to it. At this point
it is
removed from the Processor's run-queue and added to the semaphore's
queue.
So now there is a circular reference between the process and the
semaphore
and these are the only references to the process and the semaphore,
and so
both get garbage collected.
I think the forked process gets to run before the processor returns to
the
yield line. This is the way it works in VA Smalltalk and from looking
at
the implementers of #fork, I think it is the way it works in Squeak. I could be wrong, if so please be kind, I have been following the news
group
for a while but I'm new to playing with Squeak.
No. In Smalltalk-80 (VisualWorks, Squeak etc) fork creates a new process with the same priority as the current process and then resumes it (resume is the primitive that adds the process to the run queue). So the new process is effectively behind the activeProcess in the run-queue. e.g.
| who | who := #me. [who := #him. Semaphore new wait] fork. who => #me
| who | who := #me. [who := #him. Semaphore new wait] fork. Processor yield. who => #him
I can't speak for VA, but I doubt you;re right. I expect VA to have the same behaviour as the above.
There were times when I wanted to create a new fork but didn't want it
to
run until the method creating it finished. So, I added #forkReady (and friends) that would create the process but not run it right away.
there's also forkAt: Processor activePriority - 1, or
| gate result | gate := Semaphore new. [gate wait. self doStuff] fork. result := self getResult. gate signal. ^result
If the saved image is started, is there any way the process can
tell?
Not the process itself. But you surely keep the process in a class somewhere, and the class can arrange to get notified on startup by
adding
itself to the startup list. See addToStartUpList:.
exactly. one could also e.g. poll OSProcess to get the process ID of
the
VM
process and see if that changes, but that's a horrible hack, and once
in a
blue moon will fail (cuz process ids are not unique and get reused).
I'm running a process that keeps running for a look time. It loops
with a
delay and in the loop gets the date and time. If the date and time
were
obtained just before the save, they would be old at the time of the
image
restart and need to be refreshed.
Delays get adjusted after resuming from snapshot. So it should just
work.
exactly. the snapshot will look just like a long time on the run-queue whole the process is preempted by higher-priroity processes,
- Bert -
Louis LaBrunda Keystone Software Corp. SkypeMe callto://PhotonDemon mailto:Lou@Keystone-Software.com http://www.Keystone-Software.com
Louis LaBrunda Keystone Software Corp. SkypeMe callto://PhotonDemon mailto:Lou@Keystone-Software.com http://www.Keystone-Software.com