389 lines
11 KiB
Text
389 lines
11 KiB
Text
@node Processes (native threads)
|
||
@subsection Processes (native threads)
|
||
|
||
Process is a primitive representing native thread.
|
||
|
||
@node Processes dictionary
|
||
@subsection Processes dictionary
|
||
|
||
@cppindex mp_all_processes
|
||
@lspindex mp:all-processes
|
||
|
||
@deftypefun cl_object mp_all_processes ()
|
||
@end deftypefun
|
||
|
||
@defun mp:all-processes
|
||
|
||
Returns the list of processes associated to running tasks. The list is a
|
||
fresh new one and can be destructively modified. However, it may happen
|
||
that the output list is not up to date, because some of the tasks have
|
||
expired before this copy is returned.
|
||
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_exit_process
|
||
@lspindex mp:exit-process
|
||
|
||
@deftypefun cl_object mp_exit_process () ecl_attr_noreturn
|
||
@end deftypefun
|
||
|
||
@defun mp:exit-process
|
||
|
||
When called from a running task, this function immediately causes the
|
||
task to finish. When invoked from the main thread, it is equivalent to
|
||
invoking @code{ext:quit} with exit code 0.
|
||
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_interrupt_process
|
||
@lspindex mp:interrupt-process
|
||
|
||
@deftypefun cl_object mp_interrupt_process (cl_object process, cl_object function)
|
||
@end deftypefun
|
||
|
||
@defun mp:interrupt-process process function
|
||
|
||
Interrupt a task. This @code{function} sends a signal to a running
|
||
@code{process}. When the task is free to process that signal, it will
|
||
stop whatever it is doing and execute the given function.
|
||
|
||
@strong{WARNING:} Use with care! Interrupts can happen anywhere,
|
||
except in code regions explicitely protected with
|
||
@code{mp:without-interrupts}. This can lead to dangerous situations
|
||
when interrupting functions which are not thread safe. In particular,
|
||
one has to consider:
|
||
@itemize
|
||
@item Reentrancy: Functions, which usually are not called recursively can be re-entered during execution of the interrupt.
|
||
@item Stack unwinding: Non-local jumps like @code{throw} or @code{return-from} in the interrupting code will handle @code{unwind-protect} forms like usual. However, the cleanup forms of an @code{unwind-protect} can still be interrupted. In that case the execution flow will jump to the next @code{unwind-protect}.
|
||
@end itemize
|
||
|
||
@exindex Process interruption
|
||
Example:
|
||
|
||
Kill a task that is doing nothing (See @code{mp:process-kill}).
|
||
|
||
@lisp
|
||
(flet ((task-to-be-killed ()
|
||
;; Infinite loop
|
||
(loop (sleep 1))))
|
||
(let ((task (mp:process-run-function 'background #'task-to-be-killed)))
|
||
(sleep 10)
|
||
(mp:interrupt-process task 'mp:exit-process)))
|
||
@end lisp
|
||
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_make_process
|
||
@lspindex mp:make-process
|
||
|
||
@deftypefun cl_object mp_make_process (cl_narg narg, ...)
|
||
@end deftypefun
|
||
|
||
@defun mp:make-process &key name initial-bindings
|
||
|
||
Create a new thread. This function creates a separate task with a name
|
||
set to @code{name} and no function to run. See also
|
||
@code{mp:process-run-function}. Returns newly created process.
|
||
|
||
If @code{initial-bindings} is false, the new process inherits local
|
||
bindings to special variables (i.e. binding a special variable with
|
||
@code{let} or @code{let*}) from the current thread, otherwise the new
|
||
thread possesses no local bindings.
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_active_p
|
||
@lspindex mp:process-active-p
|
||
|
||
@deftypefun cl_object mp_process_active_p (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-active-p process
|
||
|
||
Returns @code{t} when @code{process} is active, @code{nil}
|
||
otherwise. Signals an error if @code{process} doesn't designate a valid
|
||
process.
|
||
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_enable
|
||
@lspindex mp:process-enable
|
||
|
||
@deftypefun cl_object mp_process_enable (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-enable process
|
||
|
||
The argument to this function should be a process created by
|
||
@code{mp:make-process}, which has a function associated as per
|
||
@code{mp:process-preset} but which is not yet running. After invoking
|
||
this function a new thread will be created in which the associated
|
||
function will be executed. Returns @code{process} if the thread
|
||
creation was successful and @code{nil} otherwise.
|
||
|
||
@exindex Possible implementation of @code{mp:process-run-function}:
|
||
|
||
@lisp
|
||
(defun process-run-function (process-name process-function &rest args)
|
||
(let ((process (mp:make-process name)))
|
||
(apply #'mp:process-preset process function args)
|
||
(mp:process-enable process)))
|
||
@end lisp
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_yield
|
||
@lspindex mp:process-yield
|
||
|
||
@deftypefun cl_object mp_process_yield ()
|
||
@end deftypefun
|
||
|
||
@defun mp:process-yield
|
||
Yield the processor to other threads.
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process-join
|
||
@lspindex mp:process-join
|
||
|
||
@deftypefun cl_object mp_process_join (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-join process
|
||
Suspend current thread until @code{process} exits. Return the result
|
||
values of the @code{process} function.
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_kill
|
||
@lspindex mp:process-kill
|
||
|
||
@deftypefun cl_object mp_process_kill (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-kill process
|
||
Try to stop a running task. Killing a process may fail if the task has
|
||
disabled interrupts.
|
||
|
||
@exindex Killing process
|
||
Example:
|
||
|
||
Kill a task that is doing nothing
|
||
@lisp
|
||
(flet ((task-to-be-killed ()
|
||
;; Infinite loop
|
||
(loop (sleep 1))))
|
||
(let ((task (mp:process-run-function 'background #'task-to-be-killed)))
|
||
(sleep 10)
|
||
(mp:process-kill task)))
|
||
@end lisp
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_suspend
|
||
@lspindex mp:process-suspend
|
||
|
||
@deftypefun cl_object mp_process_suspend (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-suspend process
|
||
Suspend a running @code{process}. May be resumed with
|
||
@code{mp:process-resume}.
|
||
|
||
@exindex Suspend and resume process
|
||
Example:
|
||
|
||
@lisp
|
||
(flet ((ticking-task ()
|
||
;; Infinite loop
|
||
(loop
|
||
(sleep 1)
|
||
(print :tick))))
|
||
(print "Running task (one tick per second)")
|
||
(let ((task (mp:process-run-function 'background #'ticking-task)))
|
||
(sleep 5)
|
||
(print "Suspending task for 5 seconds")
|
||
(mp:process-suspend task)
|
||
(sleep 5)
|
||
(print "Resuming task for 5 seconds")
|
||
(mp:process-resume task)
|
||
(sleep 5)
|
||
(print "Killing task")
|
||
(mp:process-kill task)))
|
||
@end lisp
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_resume
|
||
@lspindex mp:process-resume
|
||
|
||
@deftypefun cl_object mp_process_resume (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-resume process
|
||
Resumes a suspended @code{process}. See example in
|
||
@code{mp:process-suspend}.
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_name
|
||
@lspindex mp:process-name
|
||
|
||
@deftypefun cl_object mp_process_name (cl_object process)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-name process
|
||
Returns the name of a @code{process} (if any).
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_preset
|
||
@lspindex mp:process-preset
|
||
|
||
@deftypefun cl_object mp_process_preset (cl_narg narg, cl_object process, cl_object function, ...)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-preset process function &rest function-args
|
||
|
||
Associates a @code{function} to call with the arguments
|
||
@code{function-args}, with a stopped @code{process}. The function will
|
||
be the entry point when the task is enabled in the future.
|
||
|
||
See @code{mp:enable-process} and @code{mp:process-run-function}.
|
||
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_process_run_function
|
||
@lspindex mp:process-run-function
|
||
|
||
@deftypefun cl_object mp_process_run_function (cl_narg narg, cl_object name, cl_object function, ...)
|
||
@end deftypefun
|
||
|
||
@defun mp:process-run-function name function &rest function-args
|
||
Create a new process using @code{mp:make-process}, associate a function
|
||
to it and start it using @code{mp:process-preset}.
|
||
|
||
@exindex mp:process-run-function usage
|
||
Example:
|
||
|
||
@lisp
|
||
(flet ((count-numbers (end-number)
|
||
(dotimes (i end-number)
|
||
(format t "~%;;; Counting: ~i" i)
|
||
(terpri)
|
||
(sleep 1))))
|
||
(mp:process-run-function 'counter #'count-numbers 10))
|
||
@end lisp
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_current_process
|
||
@lspindex mp:*current-process*
|
||
|
||
@deftypefun cl_object mp_current_process ()
|
||
@end deftypefun
|
||
|
||
@defvr Variable {mp:*current-process*}
|
||
Returns/holds the current process of a caller.
|
||
@end defvr
|
||
|
||
|
||
@cppindex mp_block_signals
|
||
@lspindex mp:block-signals
|
||
|
||
@deftypefun cl_object mp_block_signals ()
|
||
@end deftypefun
|
||
|
||
@defun mp:block-signals
|
||
Blocks process for interrupts and returns the previous sigmask.
|
||
|
||
See @code{mp:interrupt-process}.
|
||
@end defun
|
||
|
||
|
||
@cppindex mp_restore_signals
|
||
@lspindex mp:restore-signals
|
||
|
||
@deftypefun cl_object mp_restore_signals (cl_object sigmask)
|
||
@end deftypefun
|
||
|
||
@defun mp:restore-signals sigmask
|
||
Enables the interrupts from @code{sigmask}.
|
||
|
||
See @code{mp:interrupt-process}.
|
||
@end defun
|
||
|
||
|
||
@lspindex mp:without-interrupts
|
||
@lspindex allow-with-interrupts
|
||
@lspindex with-local-interrupts
|
||
@lspindex with-restored-interrupts
|
||
|
||
@defmac mp:without-interrupts &body body
|
||
|
||
Executes @code{body} with all deferrable interrupts disabled. Deferrable
|
||
interrupts arriving during execution of the @code{body} take effect
|
||
after @code{body} has been executed.
|
||
|
||
Deferrable interrupts include most blockable POSIX signals, and
|
||
@code{mp:interrupt-process}. Does not interfere with garbage collection,
|
||
and unlike in many traditional Lisps using userspace threads, in ECL
|
||
@code{mp:without-interrupts} does not inhibit scheduling of other
|
||
threads.
|
||
|
||
Binds @code{allow-with-interrupts}, @code{with-local-interrupts} and
|
||
@code{with-restored-interrupts} as a local macros.
|
||
|
||
@code{with-restored-interrupts} executes the body with interrupts enabled if
|
||
and only if the @code{without-interrupts} was in an environment in which
|
||
interrupts were allowed.
|
||
|
||
@code{allow-with-interrupts} allows the @code{with-interrupts} to take
|
||
effect during the dynamic scope of its body, unless there is an outer
|
||
@code{without-interrupts} without a corresponding
|
||
@code{allow-with-interrupts}.
|
||
|
||
@code{with-local-interrupts} executes its body with interrupts enabled
|
||
provided that there is an @code{allow-with-interrupts} for every
|
||
@code{without-interrupts} surrounding the current
|
||
one. @code{with-local-interrupts} is equivalent to:
|
||
|
||
@lisp
|
||
(allow-with-interrupts (with-interrupts ...))
|
||
@end lisp
|
||
|
||
Care must be taken not to let either @code{allow-with-interrupts} or
|
||
@code{with-local-interrupts} appear in a function that escapes from
|
||
inside the @code{without-interrupts} in:
|
||
|
||
@lisp
|
||
(without-interrupts
|
||
;; The body of the lambda would be executed with WITH-INTERRUPTS allowed
|
||
;; regardless of the interrupt policy in effect when it is called.
|
||
(lambda () (allow-with-interrupts ...)))
|
||
|
||
(without-interrupts
|
||
;; The body of the lambda would be executed with interrupts enabled
|
||
;; regardless of the interrupt policy in effect when it is called.
|
||
(lambda () (with-local-interrupts ...)))
|
||
@end lisp
|
||
@end defmac
|
||
|
||
|
||
@lspindex mp:with-interrupts
|
||
@defmac mp:with-interrupts &body body
|
||
Executes @code{body} with deferrable interrupts conditionally
|
||
enabled. If there are pending interrupts they take effect prior to
|
||
executing @code{body}.
|
||
|
||
As interrupts are normally allowed @code{with-interrupts} only makes
|
||
sense if there is an outer @code{without-interrupts} with a
|
||
corresponding @code{allow-with-interrupts}: interrupts are not enabled
|
||
if any outer @code{without-interrupts} is not accompanied by
|
||
@code{allow-with-interrupts}.
|
||
@end defmac
|