[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Processes



    Date: Tue, 1 Oct 1991 01:08 EDT
    From: kddlab!atr-la.atr.co.jp!myers@uunet.UU.NET (John K. Myers)

    This is 1) a request for information, and 2) a general flame on the
    state of the documentation on processes.

We already got (2).

    It's time to play with processes.  There are only a handful of basic
    operations that need to be supported:
    1.  Fork off a process and never look at it (provided by process-run-function);
    2.  Make a process and return a pointer to it (make-process)

PROCESS-RUN-FUNCTION returns the process as well.  You use MAKE-PROCESS
when you want finer control over starting the process.

    3.  Have a process decide to go to sleep by itself and then wake up
	a specified time later, without consuming resources (sleep)
    4.  Have a process decide to block itself and not consume significant
	resources until it is unblocked.
    5.  Have a separate process order a specific process to block and
	not consume resources until it is unblocked.
    6.  Have a separate process order a specific blocked process to unblock.
    7.  Have a separate process order a specific process to kill itself
	permanently.

    4 appears to be implemented by (process:block-process "Blocked" T),
    which gives a verify-function of T.  Apparently, if the verify-function
    is NIL, even if the process is unblocked, the process will not start.

You mean #'TRUE and #'FALSE, not T and NIL; the second argument to
PROCESS:BLOCK-PROCESS is a function.

The Genera use of the term "blocked" is almost identical to its general
use in the OS programming industry.  A process goes blocked in order to
wait for some external event, such as a peripheral being ready, or
another process doing something.  When that event occurs, the OS or
other process sends the process a wakeup.

The purpose of the verify-function is to determine whether you were
woken up due to the occurrence of the event that you were actually
waiting for.

A good analogy would be a telephone, with receival of a wakeup
corresponding to ringing of the phone.  If you're supposed to pick
someone up at the train station, you might agree to have him call you
when he arrives.  However, you wouldn't just leave for the train station
as soon as you hear the phone ring; first you answer it, to make sure
it's him.  This last part corresponds to the verify-function.

    4 could also be implemented by (process:wait-forever), the difference
    is unclear.

No, PROCESS:WAIT-FOREVER never returns; it's equivalent to
(process:block-process <whostate> #'false).  In the above analogy, this
is equivalent to taking your phone off the hook.

Actually, it *can* return if the wakeup is sent with
PROCESS:FORCE-WAKEUP (see below).  This is analogous to an operator
breakin.

      5 appears to be implemented by (process:disable other-process).

Not really.  PROCESS:DISABLE doesn't block a process, it stops it, by
removing all its run reasons.

The distinction is that blocking is something a process does itself, to
wait for something to happen.  Stopping is something that another
process does to a process, just to prevent it from running.

Another way to think of it is that blocking and waiting are used for
interprocess *communication*, whereas enabling and disabling are used for
process control.

If you're familiar with Unix, PROCESS:DISABLE is similar to typing
control-Z on Unix.  To continue the above analogy, this is like the
phone company disconnecting you.  Actually, it's more like putting you
in jail, since a stopped process can't do anything.

The way to force a process to block itself is with PROCESS:INTERRUPT:

(process:interrupt <process> #'(lambda () (process:block-process ...)))

      6 appears to be implemented by (process:enable other-process) as the
    best choice.  It is unclear whether this is guaranteed to get the
    process running, or whether other conditions must be fulfilled.
    6 also appears to be implemented by process:wakeup, process:force-wakeup,
    and process:wakeup-without-test.  The difference between these is
    quite unclear, although, given a choice, I'd guess process:force-wakeup
    sounds like what I want.  process:wakeup is described as, "Evaluates
    the verify function of process."  Presumably this has some side-effect,
    such as changing the processor's state into RUNNABLE if the function
    evaluates to non-NIL; it is hard to see why I would want the value of
    a function in a master process, and why a function evaluation function
    would be called "wakeup".  The side-effect is not described.
    "wakeup-without-test" amazingly "wakes the process up" without testing
    the function, and then tests the function, possibly without waking
    the process up (if the function tests negative).  Ah, the Zen of
    Symbolics programming.  And yet, this is the clearest description of
    the three.  Apparently the function is not tested in the calling process,
    but it is tested in the subject process.  How this differs from
    "wakeup" is unclear.  "force-wakeup" "wakes up Process".  What happens
    to the verify function?  Is it ignored?  Since the other wakeups were
    so worried about the verify function, is "force-wakeup" only the first
    half, and I have to call "wakeup" to evaluate the function in order
    to get the process to run?  What happens if the verify function is negative?

If you stopped the process with PROCESS:DISABLE, you undo that with
PROCESS:ENABLE.  If the process called PROCESS:BLOCK-PROCESS to wait for
something to happen, you use one of the wakeup functions to indicate
that it has.  In most cases you would use PROCESS:WAKEUP.

The descriptions on p.31 for the wakeup functions is not very good.  P.8
is a better place to look.  Here's my descriptions:

    PROCESS:WAKEUP: Call the verify-function of <process>, and unblock the
    process it it returns true.  If the process was in a call to
    PROCESS:BLOCK-PROCESS, it will also call the verify-function itself at
    this point, and block itself again if it returns NIL.
    
    PROCESS:WAKEUP-WITHOUT-TEST: Unblock the process.  The process will then
    call its verify-function, and block itself again if it returns NIL.
    
    PROCESS:FORCE-WAKEUP: Unblock the process unconditionally.  The
    verify-function is completely ignored.

You might call PROCESS:WAKEUP-WITHOUT-TEST if you believe the
verify-function is expensive, so it shouldn't be executed twice
unnecessarily.  It could also be useful if the verify-function depends
on dynamic state of the blocked process.  This is only reasonable in
constrained situations, where you control all the processes that might
try to wake up the process; if some random system process sends it a
wakeup, though, it will use PROCESS:WAKEUP and violate this protocol.

      7 appears to be implemented by either process:abort (the weak version),
    or process:kill (the strong version).  It is unclear how to ensure that
    a process stays dead and does not come back from the grave, since 
    process:kill warns that Reset (process:reset?) will still work...

PROCESS:ABORT is equivalent to hitting control-Abort (or
control-meta-Abort if you specify :ALL T); the process will only go away
if it doesn't have a handler for the SYS:ABORT condition.

PROCESS:KILL aborts the process and then makes it dead.  You can't
prevent it from coming back from the grave; why do you care, though?

      5 also appears to be implemented by process:flush, which "forces a
    process to be blocked", without changing the state of its computation.
    This smells like a lose, though, with a name like "flush".  Unclear
    how to unflush a process, or difference between flushing and blocking,
    aborting, or killing.  Apparently flushing is like blocking except
    flush requires a process:reset in order to keep running (which DOES
    change the state of its computation--a reset loses all local variables).

PROCESS:FLUSH is roughly equivalent to

(process:interrupt <process> #'process:wait-forever "Flushed")

Contradictory to the documentation, a flushed process can be restarted
with any of PROCESS:RESET, PROCESS:INTERRUPT, or PROCESS:FORCE-WAKEUP.
Only the first causes the local state to be lost.

    2,5, and 6 also apparently can be implemented by something like:
    (defvar SLAVE-RUNNING T)
    ;Make process
    (setq slave (process:make-process :initial-function my-slave-function
				      :run-reasons '(SLAVE-RUNNING) ))
    ;Process starts out running automatically
    ..
    ;Block the process from outside
    (setq SLAVE-RUNNING nil)
    ..
    ;Restart the process from outside
    (setq SLAVE-RUNNING T)
    ;Is a process:wakeup necessary here?

    although I have no confidence that I've gotten the idiom right.

No, that's not at all equivalent.  The objects on the run reason list
aren't evaluated.  If the run reason list is non-null and the arrest
reason list is nil, the process is runnable.

PROCESS:DISABLE is basically just

	(setf (process:process-run-reasons <process>) nil)

and PROCESS:ENABLE is just

	(setf (process:process-run-reasons <process>) (list :enable)
	      (process:process-arrest-reasons <process>) nil)

    Question:  Can Those Who Know verify that process:disable, 
    process:enable, and process:kill are generally the right things to do?

It depends on what you are trying to do.  If you're implementing a
master process that needs to start and stop a bunch of subordinate
processes, they probably are.

    Flame can be found in following message.

It was the preceding message when it got here.

                                                barmar