Read-write locks are always provided; if no operating system
primitives exist, emulate them using ordinary locks. Also provide a
Windows implementation.
- Spinlocks have been replaced by ordinary locks. Without access to
the underyling scheduler, spinlocks provide no performace benefit
and may even be harmful in case of high contention.
- Synchronization of process creation and exiting has been simplified.
Instead of a spinlock, a barrier and atomic operations we now use
only a single lock protecting the shared process state and a
condition variable for implementing process joins.
- Some locks which were implemented using Lisp objects now directly
use a native mutex.
- Our own mutex implementation has been removed as it is now unused.
The old implementation was not race condition free. If two threads (A
and B) were writing at the same time while one thread (C) was reading,
the following could happen:
1. thread A increases the write pointer (but does not store the
message yet)
2. thread B increases the write pointer, stores the message and
signals thread C
3. thread C tries to read from the location that thread A has not yet
written to
The new implementation is a simple and obvious solution using a common
mutex and two condition variables for reading/writing. We don't bother
with a (complex) interrupt safe implementation.
Replace slow homegrown mutex implementation by standard OS functions.
We try our best to be interrupt safe, however a completely safe
implementation is impossible (unless one completely removes the ability
to interrupt a thread waiting on a mutex). There is always a window
after the OS specific function has returned, but before we can set
the owner, in which interrupts will see an inconsistent state of the
mutex with regards to owner and count.
Condition variables are now based on OS functions as well. Timed
waiting on condition variables has also been implemented.
Otherwise it can happen that a user-defined finalizer for some object
A storing a builtin object B registers another finalizer for A making
B reachable again while B has already been finalized.
We can't impose an ordering for user-defined finalizers in general
since these may include cyclic references. Therefore it is the duty of
the user to write the finalizers in a consistent way which is
independent of the order in which the finalizers are called. This
doesn't work for builtin objects since the user can't influence
the finalizers in this case.
We also fix a bug which lead to the removal of the standard finalizer
if a user-defined finalizer was registered and then removed.
Co-authored-by: Daniel Kochmański <daniel@turtleware.eu>
We have special-cased all immediate objects except ECL_T. Creating such link
leads to a segmentation fault when GC tries to dereference the pointer. Fixes#610.
We can't use the standard functions like cl_list for allocating the
wrapper object for the finalizer since these need a working environment
for disabling interrupts.
Slot definitions are no longer a signature, but they are still needed
to update obsolete instances. Reader function name is also changed to
SI:INSTANCE-SLOTDS. SI:INSTANCE-SIG-SET name does not change, because
it sets both SLOTDS and the STAMP.
We should call make-instances-obsolete from finalize-inheritance if we
want to be conforming, because user may have added their own auxiliary
methods.
This change while being last in a serie of commits was locally the
first change which solved problems. It will enable us to implement the
fast generic dispatch after the release.
Many parts of the source code were bent backward to support builds
without long floats which are always present given we depend expect
c99 compiler.
The corresponding C macros (ECL_LONG_FLOAT) and the *feature*
entry (:long-float) are marked as deprecated in the documentation.
Complex is a macro specified in complex.h for c99 to simplify using
_Complex type. This file also contains functions to work on complex
floats. To avoid conflicts we rename internal name complex to
gencomplex and update all references to it.
This function used writes in the thread local environment while
interrupts where disabled with the env->disable_interrupts
mechanism, which causes problems with the mprotect() mechanism for
fast interrupt dispatch.
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.
When mp_process_interrupt and thread_cleanup are called at the same
time, it is possible that the thread-local environment is deallocated
while ecl_interrupt_process tries to use it. This two methods thus
need to be protected with a lock.
- fix#262 to manage CTRL+c on Win.
- unregistered thread are left registered and enviroment not cleanup.
- manage when a finalizer is invoked before a valid enviroment is available.
Fixes issue #140
- The heap size limit was intended to be 1GB on 32-bit or 4GB on 64-bit
but inconsistency between ECL_FIXNUM_BITS and FIXNUM_BITS in the code
prevented the heap to grow for 64-bit. This now occurs, and a few
other less visible bugs were fixed by restoring consistency to
ECL_FIXNUM_BITS.
Builds without CLOS weren't possible for long time, yet a lot of dead
code for non-clos builds was spread across sources. This commit
removes all ifdefs and dead blocks from codebase.
Signed-off-by: Daniel Kochmański <dkochmanski@turtle-solutions.eu>
- HAVE_GC_SET_START_CALLBACK was defined unconditionally
- there was no AC_DEFINE if system_boehm was false
- there was a typo in one usage site of this macro
see 6b754564f1