We should not signal an error if we don't find a dispatch macro
character and *read-suppress* is true. The following example from
the CLHS documentation on *read-suppress* wrongly signaled an
error:
(let ((*read-suppress* t)) (read-from-string "#\garbage"))
Fixes#431.
The current behaviour may technically be ANSI compliant, but it
differs from the behaviour of the native compiler and from many
other Common Lisp implementations (sbcl, ccl, clisp, abcl and cmucl).
The following statement:
(eval-when (:compile-toplevel :load-toplevel :execute)
(print "test"))
resulted in an error, since the compiler would expand the print
statement in a FFI:C-INLINE form, which can't be evaluated at
compile time.
defclass calls indirectly ensure-class-using-class from builtin module which
calls make-instance on metaclass (which could be a forward-referenced
class). That triggers validate-superclass on
(validate-superclass #<forward-ref-class> #<standard-class standard-object>)
which failed. This commit mitigates this situation. Problem was masked
because of *clos-boot* never been set to T (recently fixed).
When we have called something like this
(ext:run-program "true" nil :wait nil :output *standard-output*)
pipe-stream were running in a loop until someone has called
external-process-wait (or external-process-status). This was a hogging the
processor without a reason. Right now unless some other wait is already called
checks for the process status (and magically removes zombies).
Also always call sleep (not thread-yield), because this loop eats a lot of cpu
otherwise.
Some versions of makeinfo are quite strict about input files and
don't allow whitespace between @macros and braces or nodes which
are not referenced in some menu.
:UCS-4LE was not in the list of basic encodings and the keywords
for other encodings were mistakenly interned in lower
case. Reported and fixed by Robert Dodier. Fixes#435.
Avoids redefinition of __ecl_frs_push_result if e.g. two tagbodies
follow each other in the same C block. This redefinition is an
error in C and compilers will not accept the generated code.
Letting the gmp library use uncollectable allocations leads to
leaks, if the bignums are not freed with mpz_clear. Since this
can't be done without a finalizer, we have to use the standard
allocation mechanism. Fixes#433.
Local variables were not declared volatile, so they could be
changed by the setjmp call in ECL_UNWIND_PROTECT_BEGIN. This could
lead to execution of the cleanup statements even though the thread
creation was successfull and thus to segmentation faults.
Thread handles were never closed. Also fixed the ugly hack in
process->thread, where a pthread_t object was used on windows instead
of the correct HANDLE object.
ecl_unlist_process is called in thread_cleanup after interrupts have
been disabled, however it uses unwind-protect, which will disenable and
then reenable interrupts. Since on windows, we don't have an equivalent
of sigmask, we can't use unwind-protect and instead rely on disabled
interrupts to make sure, that the spinlock is always released.
ecl_check_pending_interrupts is used in ecl_enable_interrupts_env,
which may not always be in a place where we can handle signals without
safety measures. _ecl_w32_exception_filter needs to be protected too. Here,
the switch statement could also fall through to EXCEPTION_INT_DIVIDE_BY_ZERO,
leading to wrong errors being displayed.
The garbage collector can call stacks_scanner in a thread before
pthread_setspecific, leading to a wrong error message. The
solution is simply not to mark the environment, if
pthread_setspecific has not yet been called.
If a thread is interrupted after a call to fill_spec_vector, but
before it can call ecl_search_cache, the cache may change during
the interrupt, leading to crashes. We can't use
env->disable_interrupts since fill_spec_vector calls methods which
write in the thread-local environment. Disabling interrupts in
ecl_search_cache and clear_list_from_cache is now redundant and
has been removed.
The pending interrupts list may be modified after we have checked
whether it is nil, but before we aquire the spinlock, leading to
segmentation faults.
If we don't do this, execution of the cleanup forms may be
interrupted or they may not be executed at all. This behaviour
would probably be acceptable for external code, however the
unwind-protect mechanism is also used internally to protect
against deadlocks (e.g. in ECL_WITH_(SPIN)LOCK).
We can't use ecl_disable_interrupts, because often writes in the
thread local environment happen while we hold the locks (e.g.
env->packages_to_be_created is written in find_pending_package
while the lock is held in ecl_make_package). Therefore we use the
lisp interrupt blocking mechanism. For this, the order of
operations in cl_boot has to be modified a bit.
Checking process.phase without holding the start_stop_spinlock
looks dangerous, the thread may exit after the check but before we
interrupt it. Also, we can't call mp_process_kill while interrupts
are disabled, so we have to use the lower level ecl_interrupt_process.
Previously, the dummy tag was written behind the stack
boundary. Also added race condition protection to non-inlined
ecl_bds_bind/push. The memory barriers have been reworked,
too. AO_store_full has been replaced by AO_full_nop. This is
sufficient to insert the required memory barrier instructions and
is implemented in a simpler way by libatomic_ops in some cases.
Due to the use of mprotect() for fast interrupt dispatch it is
not possible to write in the thread local environment when
interrupts are disabled. We need to use sigprocmask to block
interrupts in this case.
In both bytecmp and c compiler we use si:function-boundary and
si:unwind-protect-boundary where appropriate. Previously bytecmp used an ad-hoc
special variable for function-boundary and didn't mark unwind-protect at all.
Remove recently-introduced ECI package (maybe we will reintroduce it later when
we'll have a common frontend for compilers).
If ecl_unwind is interrupted with another call to ecl_unwind
before it has decremented env->frs_top, the second call of
ecl_unwind may stop too early with its unwinding, leading to
potential segfaults.