JoeDog / siege

Siege is an http load tester and benchmarking utility
GNU General Public License v3.0
5.95k stars 387 forks source link

fix: deadlocks caused by unsafe thread termination #180

Closed midchildan closed 2 years ago

midchildan commented 4 years ago

Threads in siege are currently configured so that it can be terminated at any time, with the exception of AIX and SunOS. However, benchmarking threads can't be arbitrarily terminated in a safe manner because async-cancel-unsafe library functions are used throughout each iteration of the benchmarking loop, with malloc() and free() being the most notable examples.

This becomes problematic with glibc's implementation of malloc because it uses locking to protect concurrent access to the heap allocator. When a thread in the middle of a malloc call gets terminated abruptly, it dies while holding a lock to the heap. This causes further calls to malloc to deadlock, thus freezing the whole program. I haven't checked if it's also the case outside of Linux / glibc, but other platforms are likely affected as well.

The deadlocking problem becomes more apparent with timed benchmarks with a high number of concurrent threads, because threads are cancelled externally via calls to pthread_cancel(). Tested locally with -c 255, this happened in almost every single instance, freezing siege before it could output the benchmark results.

This change solves this problem by configuring threads so that it can only be terminated when functions usable as cancellation points are called. Since there seems to be more than enough cancellation points in each iteration of the benchmarking loop, I assume this will only have a negligible impact on the benchmark results, as long as the benchmark duration isn't set too short.

midchildan commented 2 years ago

Closing because it was fixed in 4.1.5.