[ClusterLabs Developers] libqb 1.0.2 / loop_timerlist.c:67: make_job_from_tmo: Assertion failed
Miranda, Russel
russel.miranda at lmco.com
Mon Jan 25 05:29:30 UTC 2021
Hello ClusterLabs Developers,
I'm a developer working on an application that is using libqb (1.0.2) for its main event loop, and after running for a few hours, I'm encountering this assertion failure:
loop_timerlist.c:67: make_job_from_tmo: Assertion `t->state == QB_POLL_ENTRY_ACTIVE' failed.
The assertion causes a SIGABRT, and generates a core file. The stack trace is at the point of the failure is:
#0 0x00007ff3c76dd207 in raise () from /lib64/libc.so.6
#1 0x00007ff3c76de8f8 in abort () from /lib64/libc.so.6
#2 0x00007ff3c76d6026 in __assert_fail_base () from /lib64/libc.so.6
#3 0x00007ff3c76d60d2 in __assert_fail () from /lib64/libc.so.6
#4 0x00007ff3ca1c828d in make_job_from_tmo (data=0x5460250) at loop_timerlist.c:67
#5 0x00007ff3ca1c815b in timerlist_expire (timerlist=0x5dffe98) at ../include/tlist.h:210
#6 expire_the_timers (s=0x5dffe80, ms_timeout=<optimized out>) at loop_timerlist.c:78
#7 0x00007ff3ca1c6acc in qb_loop_run (lp=<optimized out>) at loop.c:175 ...
Going back up to the point of the assertion (make_job_from_tmo), here is what the "data" parameter looks like:
(gdb) p *((struct qb_loop_timer*)data)
$1 = {item = {list = {next = 0x5460250, prev = 0x5460250}, source = 0x5dffe80, user_data = 0x7ff3c9144f60 <sessions+6240>, type = QB_LOOP_FD},
dispatch_fn = 0xac8b00 <sessionTimeoutHandler(void*)>, p = QB_LOOP_MED, timerlist_handle = 0x0, state = QB_POLL_ENTRY_EMPTY, check = 978999470, install_pos = 11}
Indeed, as the assertion indicates, t->state is QB_POLL_ENTRY_EMPTY when the assertion fails.
The timer that appears to have expired was added a few seconds earlier at the point when a message was sent (via socket) to an external entity. Typically, when that entity responds, the timer is stopped (via qb_loop_timer_del) to prevent expiration. If timer expiration occurs before the response is received, the registered dispatch function is called to handle failure of the external entity to respond.
That this timer would expire and call the dispatch_fn (sessionTimeoutHandler(void*)) passing in the value of user_data (0x7ff3c9144f60) at this point in the operation of the program is entirely plausible / expected, and I have validated that user_data points to a valid object of the appropriate type as well - so all of the caller-settable data looks correct to me in the timer entry. While I cannot completely exclude the possibility that something stepped on the t->state value, it seems unlikely that it would have affected only that one object property in the timer entry.
It appears to me that the timer has expired, but the timer list entry has the wrong state. I'm confused to how that might occur. I've been searching through the API documentation and online through forums, and I can't find anyone else reporting this particular assertion failure within "make_job_from_tmo", or even suggesting what we might be doing wrong to cause it. Has anyone seen this before?
Some additional notes:
* There is another thread active that can call qb_loop_timer_add to add a timer to the main event loop (it is not the timer that has expired here), but it could have been adding a timer at the same time this timer expired.
My understanding is that (excluding the IPC calls), libqb is thread-safe, so it should be safe to call the qb_loop_timer_add() API from another thread. qb_loop_timer_add() is the only libqb API called from the other thread.
* In some cases we are adding timers that expire immediately (that is, with a delay as short as 0ns). That is not the case with this particular timer, it has a delay that is several seconds long.
The qb_loop_timer_add() API doesn't indicate a minimum for the delay, so I am not aware of this being an incorrect usage - though we could probably switch to calling the qb_loop_job_add API instead if that is an incorrect use of the API.
None of the libqb releases since 1.0.2 appear to have any changes introduced specifically to address a problem like this - though I do see there were some minor updates made to the loop_timerlist.c code to silence warnings. If there is a known problem in this area in 1.0.2, I will try see how hard it is going to be to step up to the newer version.
I'm hoping someone has seen this problem before, or can suggest something that we might be doing wrong in the use of the API that could lead to this state.
Sincere thanks for any suggestions,
Russ
More information about the Developers
mailing list