mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-13 21:02:47 -08:00
* Symbol SI:*INTERRUPT-DISABLE* changes name to SI:*INTERRUPTS-DISABLED*.
* Implement WITHOUT-INTERRUPTS similarly to SBCL. * Implement WITH-LOCK disabling interrupts in the lock release phase.
This commit is contained in:
parent
c4cf6ad491
commit
88f663ddb6
4 changed files with 93 additions and 17 deletions
|
|
@ -44,6 +44,13 @@ ECL 9.9.1:
|
|||
(ext:weak-pointer-value weak-pointer) => value
|
||||
and it defines a new built-in type, EXT:WEAK-POINTER
|
||||
|
||||
- ECL now implements WITHOUT-INTERRUPTS similarly to SBCL. It creates three
|
||||
local macros, ALLOW-WITH-INTERRUPTS and WITH-LOCAL-INTERRUPTS, and an
|
||||
additional one WITH-RESTORED-INTERRUPTS, which executes the forms with
|
||||
the value of interrupts of the forms that surround WITHOUT-INTERRUPTS.
|
||||
|
||||
- Symbol SI:*INTERRUPT-DISABLE* changes name to SI:*INTERRUPTS-DISABLED*.
|
||||
|
||||
* Bugs fixed:
|
||||
|
||||
- WITH-LOCK might run into a race condition when the lock acquisition process
|
||||
|
|
@ -51,6 +58,8 @@ ECL 9.9.1:
|
|||
|
||||
- The following functions are now interrupt safe: MP:MAKE-LOCK.
|
||||
|
||||
- The use of GIVEUP-LOCK in WITH-LOCK is now protected against interrupts.
|
||||
|
||||
;;; Local Variables: ***
|
||||
;;; mode:text ***
|
||||
;;; fill-column:79 ***
|
||||
|
|
|
|||
|
|
@ -1053,7 +1053,7 @@ cl_symbols[] = {
|
|||
{SYS_ "*IGNORE-EOF-ON-TERMINAL-IO*", SI_SPECIAL, NULL, -1, Cnil},
|
||||
{SYS_ "*INDENT-FORMATTED-OUTPUT*", SI_SPECIAL, NULL, -1, Cnil},
|
||||
{SYS_ "*INIT-FUNCTION-PREFIX*", SI_SPECIAL, NULL, -1, Cnil},
|
||||
{SYS_ "*INTERRUPT-ENABLE*", SI_SPECIAL, NULL, 1, Ct},
|
||||
{SYS_ "*INTERRUPTS-ENABLED*", SI_SPECIAL, NULL, 1, Ct},
|
||||
{SYS_ "*KEEP-DEFINITIONS*", SI_SPECIAL, NULL, -1, Ct},
|
||||
{SYS_ "*LOAD-HOOKS*", SI_SPECIAL, NULL, -1, OBJNULL},
|
||||
{SYS_ "*LOAD-SEARCH-LIST*", SI_SPECIAL, NULL, -1, Cnil},
|
||||
|
|
@ -1808,5 +1808,7 @@ cl_symbols[] = {
|
|||
{EXT_ "MAKE-WEAK-POINTER", EXT_ORDINARY, si_make_weak_pointer, 1, OBJNULL},
|
||||
{EXT_ "WEAK-POINTER-VALUE", EXT_ORDINARY, si_weak_pointer_value, 1, OBJNULL},
|
||||
|
||||
{SYS_ "*ALLOW-WITH-INTERRUPTS*", SI_ORDINARY, NULL, -1, Ct},
|
||||
|
||||
/* Tag for end of list */
|
||||
{NULL, CL_ORDINARY, NULL, -1, OBJNULL}};
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ static bool
|
|||
interrupts_disabled_by_lisp(cl_env_ptr the_env)
|
||||
{
|
||||
return (ecl_get_option(ECL_OPT_BOOTED) &&
|
||||
ecl_symbol_value(@'si::*interrupt-enable*') == Cnil);
|
||||
ecl_symbol_value(@'si::*interrupts-enabled*') == Cnil);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -661,7 +661,7 @@ init_unixint(int pass)
|
|||
cl_core.system_package);
|
||||
si_Xmake_constant(name, MAKE_FIXNUM(known_signals[i].code));
|
||||
}
|
||||
ECL_SET(@'si::*interrupt-enable*', Ct);
|
||||
ECL_SET(@'si::*interrupts-enabled*', Ct);
|
||||
#ifdef SIGFPE
|
||||
if (ecl_get_option(ECL_OPT_TRAP_SIGFPE)) {
|
||||
mysignal(SIGFPE, non_evil_signal_handler);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,71 @@
|
|||
|
||||
(in-package "MP")
|
||||
|
||||
(defmacro without-interrupts (&body body)
|
||||
#!+sb-doc
|
||||
"Executes BODY with all deferrable interrupts disabled. Deferrable
|
||||
interrupts arriving during execution of the BODY take effect after BODY has
|
||||
been executed.
|
||||
|
||||
Deferrable interrupts include most blockable POSIX signals, and
|
||||
SB-THREAD:INTERRUPT-THREAD. Does not interfere with garbage collection, and
|
||||
unlike in many traditional Lisps using userspace threads, in SBCL
|
||||
WITHOUT-INTERRUPTS does not inhibit scheduling of other threads.
|
||||
|
||||
Binds ALLOW-WITH-INTERRUPTS, WITH-LOCAL-INTERRUPTS and WITH-RESTORED-INTERRUPTS
|
||||
as a local macros.
|
||||
|
||||
WITH-RESTORED-INTERRUPTS executes the body with interrupts enabled if and only
|
||||
if the WITHOUT-INTERRUPTS was in an environment in which interrupts were allowed.
|
||||
|
||||
ALLOW-WITH-INTERRUPTS allows the WITH-INTERRUPTS to take effect during the
|
||||
dynamic scope of its body, unless there is an outer WITHOUT-INTERRUPTS without
|
||||
a corresponding ALLOW-WITH-INTERRUPTS.
|
||||
|
||||
WITH-LOCAL-INTERRUPTS executes its body with interrupts enabled provided that
|
||||
for there is an ALLOW-WITH-INTERRUPTS for every WITHOUT-INTERRUPTS surrounding
|
||||
the current one. WITH-LOCAL-INTERRUPTS is equivalent to:
|
||||
|
||||
(allow-with-interrupts (with-interrupts ...))
|
||||
|
||||
Care must be taken not to let either ALLOW-WITH-INTERRUPTS or
|
||||
WITH-LOCAL-INTERRUPTS appear in a function that escapes from inside the
|
||||
WITHOUT-INTERRUPTS in:
|
||||
|
||||
(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 ...)))
|
||||
"
|
||||
(with-unique-names (outer-allow-with-interrupts outer-interrupts-enabled)
|
||||
`(multiple-value-prog1
|
||||
(macrolet ((allow-with-interrupts (&body allow-forms)
|
||||
`(let ((*allow-with-interrupts* ,',outer-allow-with-interrupts))
|
||||
,@allow-forms))
|
||||
(with-restored-interrupts (&body with-forms)
|
||||
`(let ((*interrupts-enabled* ,',outer-interrupts-enabled))
|
||||
,@with-forms))
|
||||
(with-local-interrupts (&body with-forms)
|
||||
`(let* ((*allow-with-interrupts* ,',outer-allow-with-interrupts)
|
||||
(*interrupts-enabled* ,',outer-allow-with-interrupts))
|
||||
(when ,',outer-allow-with-interrupts
|
||||
(si::check-pending-interrupts))
|
||||
(locally ,@with-forms))))
|
||||
(let* ((,outer-interrupts-enabled *allow-with-interrupts*)
|
||||
(*interrupts-enabled* nil)
|
||||
(,outer-allow-with-interrupts *allow-with-interrupts*)
|
||||
(*allow-with-interrupts* nil))
|
||||
(declare (ignorable ,outer-allow-with-interrupts
|
||||
,outer-interrupts-enabled))
|
||||
,@body))
|
||||
(when *interrupts-enabled*
|
||||
(si::check-pending-interrupts)))))
|
||||
|
||||
(defmacro with-lock ((lock) &body body)
|
||||
#-threads
|
||||
`(progn ,@body)
|
||||
|
|
@ -26,18 +91,18 @@
|
|||
;; the function. That means we lose the information and ignore that
|
||||
;; the lock was actually acquired. Furthermore, a lock can be recursive
|
||||
;; and mp:lock-holder is also not reliable.
|
||||
;;
|
||||
;; Next notice how we need to disable interrupts around the body and
|
||||
;; the get-lock statement, to ensure that the unlocking is done with
|
||||
;; interrupts disabled.
|
||||
#+threads
|
||||
`(let* ((%the-lock ,lock)
|
||||
(%count (mp:lock-count %the-lock)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(mp::get-lock %the-lock)
|
||||
,@body)
|
||||
(when (> (mp:lock-count %the-lock) %count)
|
||||
(mp::giveup-lock %the-lock)))))
|
||||
|
||||
(defmacro without-interrupts (&body body)
|
||||
`(let ((si:*interrupt-enable* nil))
|
||||
(multiple-value-prog1
|
||||
(progn ,@body)
|
||||
(si::check-pending-interrupts))))
|
||||
(with-unique-names (lock count interrupts)
|
||||
`(let* ((,lock ,lock)
|
||||
(,count (mp:lock-count ,lock)))
|
||||
(without-interrupts
|
||||
(unwind-protect
|
||||
(with-restored-interrupts
|
||||
(mp::get-lock ,lock)
|
||||
(locally ,@body))
|
||||
(when (> (mp:lock-count ,lock) ,count)
|
||||
(mp::giveup-lock ,lock)))))))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue