[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: thread design
> We should definitely look at the LISPM stack group stuff before we commit
> to anything.
I think Allegro's (which I've used) and Lucid's came from the LISPM
abstractions. The Allegro manual is online. To access it, type
/afs/cs/user/toad/bin/clman-browser (all systypes) which will start up a
browser and initially prompt you for a string. Try "stack" or "process"
(topics produced below which see). Commands are
M-x clman-apropos and
M-x clman
From these window "m" will take you to another entry (prompting with
default & completion), and "a" will do apropos again, making it easy to
jump around the manual.
> An interesting feature of the LISPM stuff that I just
> remembered is that when you wait on a lock or hold a lock, you can say
> "why" you want the lock with some descriptive string.
Stack-groups, processes, and locks all have a name slot; these *are* useful.
Here's the stack-group level functions in Allegro:
mp:make-stack-group name [:preset-function fun] [:preset-arguments list]
mp:process-stack-group process
mp:stack-group-resume stack-group value
- switch to a stack-group
mp:stack-group-funcall stack-group value
- switch to a stack group and set the resumer slot
mp:stack-group-name stack-group
mp:stack-group-preset stack-group function [args]*
- reset a stack group and set its initial function and arguments
mp:stack-group-resumer stack-group
- get the value of the resumer slot of a stack group
mp:stack-group-return value
- resume the resumer of a stack group
mp:stack-group-state stack-group
- get the state of a stack group
mp:symeval-in-stack-group symbol stack-group
sys:*current-stack-group*
sys:*current-stack-group-resumer*
Process-locks occur at a higher level. Process-run-function is the
function I most often use; make-process-lock() creates a lock, and
with-process-lock((lock) &body) is what you usually do with them.
Here's the full list of functions:
mp:*current-process* mp:process-resume-hook
mp:make-process mp:process-revoke-arrest-reason
mp:make-process-lock mp:process-revoke-run-reason
mp:process-active-p mp:process-run-function
mp:process-add-arrest-reason mp:process-runnable-p
mp:process-add-run-reason mp:process-run-reasons
mp:process-allow-schedule mp:process-run-restartable-function
mp:process-arrest-reasons mp:process-sleep
mp:process-disable mp:process-stack-group
mp:process-flush mp:process-unlock
mp:process-initial-form mp:process-wait
mp:process-initial-bindings mp:process-wait-args
mp:process-kill mp:process-wait-function
mp:process-lock mp:process-whostate
mp:process-lock-locker mp:process-interrupt
mp:process-name mp:with-process-lock
mp:process-preset mp:*all-processes*
mp:process-priority mp:process-wait-with-timeout
mp:process-property-list mp:process-enable
mp:process-quantum mp:process-suspend-hook
mp:process-reset
The entry ``about-the-scheduler'' describes in more detail the relationship
between processes and stack-groups: the scheduler process is always
running, and is responsible for resuming the stack-groups of user processes
The user interface:
top-level commands :processes (lists processes), :kill, and when
a keyboard interrupt is generated, the processes are listed and you select
which you want to interrupt (lisp listener is a separate process).
There are also some example programs in the manual, as well as introductory
sections (called about-multiprocessing or about-*); M-x clman<cr> followed
by "about?" will list them.
Scott says:
> The document needs to say explicitly what happens with Lispy environment
> stuff when threads get switched. I guess special variables is the only
> thing we need to worry about. A lot of Lisps, when they go in heavily for
> stack-groups, switch over to deep binding for specials, but we'll probably
> want to stick with shallow binding and do the wind-unwind when stack-groups
> are switched. Even if we have an "exit this thread and don't do
> unwind-protects" option, we still need to restore the specials.
mp:process-run-function can take an :initial-bindings argument, which is an
alist of symbols and values. Note the special
excl:*cl-default-special-bindings*, which is the default values to pass on.
By getting the thread of a process you can examine a a special, or use
process-interrupt to interrupt a process to run a function (which also
allows you to set it).
Another place to think about where these fit is with select() and signals.
I guess binding a function as a handler for a signal would be sufficient.
For fd's, it's very useful to be able to put a process into a wait state
until there is input available (this is how CLX does it; see
implementations of buffer-input-wait-default in dependent.cl.
You can also see the definitions of wait-for-input-from-server in
/afs/cs.cmu.edu/project/cmt/src/clm2.0/lisp/{lucid,excl}.lisp as an example
of how these two handle it (idomatically). They both reference internal
undocumented functions, which you have to worm out of the companies
(``How can I do this?'' ``Oh, well, there's this function called...'').
I think this functionality (descended from the lispm) is sufficient for
just about everything that I can think of, and sticking close to this
design will allow people familiar with other lisps to transfer their skills
(and programs) easily.
If using mach cthreads makes it easy to implement the same functionality
for lisp, great. (Note that the other lisps don't assume this; probably use
timers & alarms). From looking at threads.txt, it seems to me that all of
the above can be written in terms of the thread functions (except maybe
thread pre-empting; having this allows access to the local specials too).
I'd even be willing to write a compatibility package using this..
er, sometime the summer.
-todd
As for changing conditions to events, you've still left on-condition in...
Maybe another place too.