The teal threads manager is a very thin layer over
pthreads. All thread scheduling decisions are left to
the pthreads scheduler which can result in
non-deterministic (and hence non-reproducable)
behavior. Some examples:
1) If multiple threads are blocked waiting for a locked
mutex, when the mutex becomes unlocked, the thread that
succeeds in acquiring the mutex next may change from
run to run.
2) If multiple threads are blocked waiting on a
condition, when that condition is signalled, the order
in which those threads are woken may change.
3) If multiple threads are unblocked and able to run in
parallel, each thread may be pre-empted at any time.
Not only does this result in non-deterministic
behavior, it can also cause problems for simulators
(such as modelsim) which do not have thread safe
(re-entrant) pli/vpi/dpi interfaces.
I've attached a modified synch.cpp (based off of
version teal_0a.93c) which I believe addresses those
issues by doing the following:
1) For the mutex and condition classes, we track the
order threads blocked in so we can cycle through and
wake them in a deterministic order.
2) Any time a new thread is created, is it immediately
blocked so it can execute at a deterministic time.
3) Added some control to minimize the amount of
parallel thread execution. In general, we try to allow
only a single thread to execute at a time. We wake
threads one at a time and allow them to run until they
block. Only then do we wake the next runnable thread
(if any) and continue this until all threads are
blocked and then we return to verilog.
modified synch.cpp w/ deterministic thread manager