ecl/src/doc/manual/extensions/mp_ref_process.txi
2019-01-03 19:14:28 +01:00

389 lines
11 KiB
Text
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@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