Add this option, so that the z3 library can be used in programs that do
signal handling on their own.
Signed-off-by: Mikulas Patocka <mikulas@twibright.com>
scoped_timer::finalize is called from fork. However, it may race with
other threads creating or freeing timer threads.
This patch reworks scoped_timer::finalize so that it runs only once
(there is no need to repeat it). We remove the assignments "num_workers =
0" and "available_workers.clear();" - they were done without any locks,
thus they were subjects to race condition.
The variable num_workers is deleted because it is not needed.
There was another bug in scoped_timer::finalize - if some workers were
busy, the function would spin-wait for them to terminate. This patch
changes it so that busy workers are ignored.
Signed-off-by: Mikulas Patocka <mikulas@twibright.com>
There is this possible call trace:
SIGINT signal
on_sigint
a->m_cancel_eh()
cancel_eh::operator()
m_obj.inc_cancel
reslimit::inc_cancel
lock_guard lock(*g_rlimit_mux);
Here we take a mutex from a signal - this is subject to deadlock (if the
signal interrupted another piece of code where the mutex is already
held).
To fix this race, we remove g_rlimit_mux and replace it with
signal_lock() and signal_unlock(). signal_lock and signal_unlock block
the signal before grabbing the mutex, so the signal can't interrupt a
piece of code where the mutex is held and the deadlock won't happen.
We change std::mutex to std::recursive_mutex, so that the mutex can be
grabbed multiple times by the same thread.
Signed-off-by: Mikulas Patocka <mikulas@twibright.com>
In class cancel_eh, the operator () may be called concurrently by the
timer code and the Ctrl-C code, but the operator () accesses class'
members without any locking.
Fix this race condition by using the functions signal_lock() and
signal_unlock() that were introduced in a previous patch. Note that if
caller_id is CTRL_C_EH_CALLER, signal_lock was already called by the
caller.
Note that we must use signal_lock/signal_unlock and we must not grab any
other mutex, because the SIGINT signal could interrupt the code while the
mutex is held and cause deadlock.
Signed-off-by: Mikulas Patocka <mikulas@twibright.com>
The Ctrl-C handling is not thread safe, there's a global variable g_obj
that is being accessed without any locking. The signal handlers are
per-process, not per-thread, so that different threads step over each
other's handlers. It is unpredictable in which thread the signal handler
runs, so the handler may race with the scoped_ctrl_c destructor.
Fix this by introducing the functions signal_lock and signal_unlock.
signal_lock blocks the SIGINT signal and then takes a mutex (so that the
signal handler can't be called while the mutex is held). signal_unlock
drops the mutex and restores the signal mask.
We protect all the global variables with signal_lock and signal_unlock.
Note that on Windows, the SIGINT handler is being run in a separate
thread (and there is no way how to block it), so we can use a simple
mutex to synchronize the signal handler with the other threads.
Signed-off-by: Mikulas Patocka <mikulas@twibright.com>
* Check that Z3_get_numeral_small is given non-null out params
Analogous to other Z3_get_numeral_* functions with out params.
* Note that Z3_get_numeral_small is essentially redundant
The error behavior of Z3_get_numeral_small does not follow the pattern of
the other functions. The functions that have out params and return a bool
indicating success (such as Z3_get_numeral_rational_int64) return false
rather than signaling an error when given an unsupported expression
argument (such as a rounding mode value). The functions that do not have out
params signal an error in such cases. Z3_get_numeral_small is the odd one
out in that it signals errors and returns a status bool.
This error handling is the only difference between Z3_get_numeral_small and
Z3_get_numeral_rational_int64, so this patch adds a comment to the
documentation.