Notifying `mCondition` without taking the lock causes a race condition
in ::process() between checking `mTerminate` and waiting for the
`mCondition`, which causes a dead lock. This commit moves writing to
`mTerminate` and notifying `mCondition` under the lock to eliminate race
condition and dead lock.
This is not theoretical. It has caused zmu to hang at exit on a
Raspberry Pi 4, exhuasting PHP-FPM process pool. The stacks below are
captured when running ZoneMinder 1.36.12-focal1 on Ubuntu 20.04:
(gdb) thread apply all bt
Thread 2 (Thread 0xffff80c1c880 (LWP 259988)):
#0 futex_wait_cancelable (private=0, expected=0, futex_word=0xaaaae0584e80 <dbQueue+176>) at ../sysdeps/nptl/futex-internal.h:183
#1 __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0xaaaae0584e28 <dbQueue+88>, cond=0xaaaae0584e58 <dbQueue+136>) at pthread_cond_wait.c:508
#2 __pthread_cond_wait (cond=0xaaaae0584e58 <dbQueue+136>, mutex=0xaaaae0584e28 <dbQueue+88>) at pthread_cond_wait.c:638
#3 0x0000ffff8700d670 in std::condition_variable::wait(std::unique_lock<std::mutex>&) () from /lib/aarch64-linux-gnu/libstdc++.so.6
#4 0x0000aaaae0438f08 in zmDbQueue::process (this=0xaaaae0584dd0 <dbQueue>) at ./src/zm_db.cpp:250
#5 0x0000ffff87013fac in ?? () from /lib/aarch64-linux-gnu/libstdc++.so.6
#6 0x0000ffff891264fc in start_thread (arg=0xffffe60d84bf) at pthread_create.c:477
#7 0x0000ffff86dd767c in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
Thread 1 (Thread 0xffff80c23010 (LWP 259987)):
#0 __pthread_clockjoin_ex (threadid=281472841926784, thread_return=0x0, clockid=0, abstime=<optimized out>, block=<optimized out>) at pthread_join_common.c:145
#1 0x0000ffff87014240 in std:🧵:join() () from /lib/aarch64-linux-gnu/libstdc++.so.6
#2 0x0000aaaae04314d0 in exit_zmu (exit_code=0) at ./src/zmu.cpp:200
#3 0x0000aaaae042f4c8 in main (argc=<optimized out>, argv=<optimized out>) at ./src/zmu.cpp:797
This possibly fixes the issue where changing the filter for an event
view via the filter button would produce invalid SQL and SQL errors.
web_php[43835].ERR [1.2.3.4] [SQL-ERR 'SQLSTATE[HY000]: General error: 4078 Illegal parameter data types int and row for operation '='', statement was 'SELECT E.*, M.Name AS Monitor FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE ( ( E.StartDateTime >= '2022-02-14 00:47:41'
and E.StartDateTime <= '2022-02-14 11:47:41' )
and E.MonitorId = ('1','3')
) ORDER BY E.StartDateTime DESC' params:] at /usr/share/zoneminder/www/includes/database.php line 161
When in the events view, clicking the filterBtn sends us to the filter view with this query term (url-decoded):
&filter[Query][terms][2][attr]=MonitorId&filter[Query][terms][2][op]=IN&filter[Query][terms][2][val]=1,3&filter[Query][sort_asc]=0
but the filter view displays this as "equals", not "in set", because it doesn't know IN from opTypes, only =[].