<tt><font size=2>Eric Blake <eblake@redhat.com> wrote on 03/22/2012
06:54:31 PM:<br>
<br>
</font></tt>
<br><tt><font size=2>> <br>
> On 03/22/2012 04:49 PM, David Stevens wrote:<br>
> > Stefan Berger/Watson/IBM wrote on 03/22/2012 03:04:53 PM:<br>
> > <br>
> >><br>
> >> I have some concerns about the cancelation of the thread.
It can <br>
> >> hold the snoop lock and get cancelled while holding it. Next
time <br>
> >> that lock is grabbed we will get a deadlock...<br>
> >><br>
> > <br>
> > The snoop lock is acquired in virNWFilterDHCPSnoopEnd(), which<br>
> > is where the pthread_cancel() directly (for valid leases) or
the<br>
> > freeReq()/pthread_cancel() is done. So, the canceler has the
lock<br>
> > and the canceling thread can't have it, then.<br>
> > <br>
> > The only other case I see is when the config goes invalid and<br>
> > we exit the snooper loop; he frees the snoop_lock() before removing<br>
> > his own hash entry,  which will cancel the same thread doing<br>
> > the remove. Again, it can't have the snoop lock when canceled.<br>
> > <br>
> > Is there some other case you think I'm missing?<br>
> <br>
> pthread_cancel() tends to imply that you are properly managing signal<br>
> blocking across threads; we haven't used it anywhere else in libvirt,<br>
> and I'm extremely wary of pulling it in now, as there's probably a
lot<br>
> of subtle bugs that it would expose.  Are you sure you can't
do this in<br>
> some other manner without dragging in pthread_cancel()?</font></tt>
<br>
<br><tt><font size=2>From the patch:</font></tt>
<br>
<br><tt><font size=2>+    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,
&tmp) < 0)<br>
+        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
"pthread_setcanceltype "<br>
+                    
          "failed; ifname \"%s\"",
req->ifname ?<br>
+                    
          req->ifname : "<NULL>");</font></tt>
<br>
<br><tt><font size=2>from the man page of above function:</font></tt>
<br>
<br><tt><font size=2>      PTHREAD_CANCEL_ASYNCHRONOUS</font></tt>
<br><tt><font size=2>              The
 thread can be canceled at any time.  (Typically, it will be</font></tt>
<br><tt><font size=2>              canceled
immediately upon receiving a cancellation request,  but</font></tt>
<br><tt><font size=2>              the
system doesn't guarantee this.)</font></tt>
<br>
<br><tt><font size=2>It seems implementation dependent on when the thread
actually die...</font></tt>
<br><tt><font size=2>So I can construct a scenario where the canceller
holds the lock and the thread doesn't, the thread gets cancelled but not
immediately and can still grab the lock and then dies.  This is what
I concluded to have seen from below stack trace when the snooping thread
was running and in rapid succession I was shooting two SIGHUPs at libvirt:</font></tt>
<br>
<br><tt><font size=2>Thread 11 (Thread 0x7f3c29ce8700 (LWP 12800)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 10 (Thread 0x7f3c294e7700 (LWP 12801)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>---Type <return> to continue, or q <return>
to quit---</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 9 (Thread 0x7f3c28ce6700 (LWP 12802)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 8 (Thread 0x7f3c284e5700 (LWP 12803)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>---Type <return> to continue, or q <return>
to quit---</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 7 (Thread 0x7f3c27ce4700 (LWP 12804)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 6 (Thread 0x7f3c274e3700 (LWP 12805)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>---Type <return> to continue, or q <return>
to quit---</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 5 (Thread 0x7f3c26ce2700 (LWP 12806)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 4 (Thread 0x7f3c264e1700 (LWP 12807)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>---Type <return> to continue, or q <return>
to quit---</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 3 (Thread 0x7f3c25ce0700 (LWP 12808)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 2 (Thread 0x7f3c254df700 (LWP 12809)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60b3b4 in pthread_cond_wait@@GLIBC_2.3.2
()</font></tt>
<br><tt><font size=2>   from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00007f3c2fe2229a in virCondWait (c=<value
optimized out>, </font></tt>
<br><tt><font size=2>    m=<value optimized out>) at util/threads-pthread.c:117</font></tt>
<br><tt><font size=2>#2  0x00007f3c2fe2295b in virThreadPoolWorker
(opaque=<value optimized out>)</font></tt>
<br><tt><font size=2>---Type <return> to continue, or q <return>
to quit---</font></tt>
<br><tt><font size=2>    at util/threadpool.c:103</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe21f36 in virThreadHelper (data=<value
optimized out>)</font></tt>
<br><tt><font size=2>    at util/threads-pthread.c:161</font></tt>
<br><tt><font size=2>#4  0x00000038ec606ccb in start_thread () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#5  0x00000038ec2e0c2d in clone () from /lib64/libc.so.6</font></tt>
<br>
<br><tt><font size=2>Thread 1 (Thread 0x7f3c2fda2820 (LWP 12799)):</font></tt>
<br><tt><font size=2>#0  0x00000038ec60dc9c in __lll_lock_wait ()
from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#1  0x00000038ec609125 in _L_lock_880 () from
/lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#2  0x00000038ec609008 in pthread_mutex_lock
() from /lib64/libpthread.so.0</font></tt>
<br><tt><font size=2>#3  0x00007f3c2fe73818 in virNWFilterObjFindByUUID
(nwfilters=0x7f3c1c015008, </font></tt>
<br><tt><font size=2>    uuid=<value optimized out>) at
conf/nwfilter_conf.c:2662</font></tt>
<br><tt><font size=2>#4  0x00007f3c2fe738ad in virNWFilterObjAssignDef
(conn=0x2055190, </font></tt>
<br><tt><font size=2>    nwfilters=0x7f3c1c015008, def=0x201ad60)
at conf/nwfilter_conf.c:2947</font></tt>
<br><tt><font size=2>#5  0x00007f3c2fe73d6f in virNWFilterObjLoad
(conn=0x2055190, </font></tt>
<br><tt><font size=2>    nwfilters=0x7f3c1c015008, configDir=0x7f3c1c089460
"/etc/libvirt/nwfilter")</font></tt>
<br><tt><font size=2>    at conf/nwfilter_conf.c:3045</font></tt>
<br><tt><font size=2>#6  virNWFilterLoadAllConfigs (conn=0x2055190,
nwfilters=0x7f3c1c015008, </font></tt>
<br><tt><font size=2>    configDir=0x7f3c1c089460 "/etc/libvirt/nwfilter")</font></tt>
<br><tt><font size=2>    at conf/nwfilter_conf.c:3092</font></tt>
<br><tt><font size=2>#7  0x00000000004e9084 in nwfilterDriverReload
()</font></tt>
<br><tt><font size=2>    at nwfilter/nwfilter_driver.c:163</font></tt>
<br><tt><font size=2>#8  0x00007f3c2fea2c8f in virStateReload () at
libvirt.c:891</font></tt>
<br><tt><font size=2>---Type <return> to continue, or q <return>
to quit---</font></tt>
<br><tt><font size=2>#9  0x0000000000420572 in daemonReloadHandler
(srv=<value optimized out>, </font></tt>
<br><tt><font size=2>    sig=<value optimized out>, opaque=<value
optimized out>) at libvirtd.c:1153</font></tt>
<br><tt><font size=2>#10 0x00007f3c2fefd4ba in virNetServerSignalEvent
(</font></tt>
<br><tt><font size=2>    watch=<value optimized out>, fd=<value
optimized out>, </font></tt>
<br><tt><font size=2>    events=<value optimized out>,
opaque=0x200fe50) at rpc/virnetserver.c:500</font></tt>
<br><tt><font size=2>#11 0x00007f3c2fe0f651 in virEventPollDispatchHandles
()</font></tt>
<br><tt><font size=2>    at util/event_poll.c:490</font></tt>
<br><tt><font size=2>#12 virEventPollRunOnce () at util/event_poll.c:637</font></tt>
<br><tt><font size=2>#13 0x00007f3c2fe0dd15 in virEventRunDefaultImpl ()
at util/event.c:247</font></tt>
<br><tt><font size=2>#14 0x00007f3c2fefdffd in virNetServerRun (srv=0x200fe50)</font></tt>
<br><tt><font size=2>    at rpc/virnetserver.c:736</font></tt>
<br><tt><font size=2>#15 0x000000000042235d in main (argc=<value optimized
out>, </font></tt>
<br><tt><font size=2>    argv=<value optimized out>) at
libvirtd.c:1609</font></tt>
<br>
<br><tt><font size=2>I bet thread 1 was trying to grab a lock that wasn't
properly unlocked due to the async cancel. All the other threads look pretty
much the same and I doubt either one holds the lock.</font></tt>
<br>
<br><tt><font size=2>Maybe we should go with the previous code from a while
ago which was setting a flag for the thread to die. It caused other work-arounds
to become necessary but at least we don't have to deal with possibly async.
deaths of threads holding locks.</font></tt>
<br>
<br><tt><font size=2>    Stefan</font></tt>
<br>