@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