<div dir="ltr">Hey all,<div><br></div><div>I am trying to find a race in my threaded app, so I decided to give valgrind+helgrind a try.</div><div><br></div><div>My app is spawning N worker threads. each has its own event loop and nicely runs in parallel.</div>
<div>Sometimes one worker needs to wakeup another worker in order to make sure it knows</div><div>about something, so I use ev_async_send() for this.</div><div><br></div><div>However, even though the man page states (unless I am misreading it) that ev_async is</div>
<div>for this very purpose and is thread safe without any further doing, I get tons of</div><div>messages by Valgrind's tool "helgrind" about possible data races.</div><div><br></div><div>The race basically occures inside ev_async_send() in thread A, a read operation that is said to</div>
<div>be in conflict to a prior read in the same data region happened inside ev_invoke_pending()+... in thread B.</div><div><br></div><div><br></div><div>The Valgrind output about the data race looks like this:</div><div><br>
</div><div><div><font face="courier new, monospace" size="1">==5023== Possible data race during write of size 4 at 0x76DBB68 by thread #1                                                                                               </font></div>
<div><font face="courier new, monospace" size="1"><br></font></div><div><span style="font-family:'courier new',monospace;font-size:x-small">==5023== Locks held: 1, at address 0x76B9968</span><br></div><div><font face="courier new, monospace" size="1">==5023==    at 0x6BBAD70: ev_async_send (in /usr/lib/x86_64-linux-gnu/libev.so.4.0.0)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x50E6E28: ev::async::send() (ev++.h:798)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x5110D8F: x0::HttpWorker::enqueue(std::pair<x0::Socket*, x0::ServerSocket*>&&) (HttpWorker.cpp:197)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x510AAD8: x0::HttpServer::onNewConnection(x0::Socket*, x0::ServerSocket*) (HttpServer.cpp:145)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x510D520: void x0::ServerSocket::callback_thunk<x0::HttpServer, &x0::HttpServer::onNewConnection>(x0::Socket*, x0::ServerSocket*) (ServerSocket.h:130)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x4E802EC: x0::ServerSocket::acceptOne() (ServerSocket.cpp:705)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x4E7F9E9: x0::ServerSocket::accept(ev::io&, int) (ServerSocket.cpp:665)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x4E803C2: void ev::base<ev_io, ev::io>::method_thunk<x0::ServerSocket, &x0::ServerSocket::accept>(ev_loop*, ev_io*, int) (ev++.h:479)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x6BB5E44: ev_invoke_pending (in /usr/lib/x86_64-linux-gnu/libev.so.4.0.0)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x510FE34: x0::HttpWorker::invoke_pending(ev_loop*) (HttpWorker.cpp:51)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x6BB8FE6: ev_run (in /usr/lib/x86_64-linux-gnu/libev.so.4.0.0)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x5110A3A: ev_loop(ev_loop*, int) (ev.h:826)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x51109B2: x0::HttpWorker::run() (HttpWorker.cpp:157)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x510ABE3: x0::HttpServer::run() (HttpServer.cpp:225)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x4734BD: x0d::XzeroDaemon::run() (XzeroDaemon.cpp:289)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x492915: main (x0d.cpp:16)</font></div>
<div><font face="courier new, monospace" size="1">==5023== </font></div><div><font face="courier new, monospace" size="1">==5023== This conflicts with a previous read of size 4 by thread #2</font></div><div><font face="courier new, monospace" size="1">==5023== Locks held: 1, at address 0x76DAC28</font></div>
<div><font face="courier new, monospace" size="1">==5023==    at 0x6BB6BF5: ??? (in /usr/lib/x86_64-linux-gnu/libev.so.4.0.0)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x6BB5E44: ev_invoke_pending (in /usr/lib/x86_64-linux-gnu/libev.so.4.0.0)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x510FE34: x0::HttpWorker::invoke_pending(ev_loop*) (HttpWorker.cpp:51)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x6BB8FE6: ev_run (in /usr/lib/x86_64-linux-gnu/libev.so.4.0.0)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x5110A3A: ev_loop(ev_loop*, int) (ev.h:826)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x51109B2: x0::HttpWorker::run() (HttpWorker.cpp:157)</font></div>
<div><font face="courier new, monospace" size="1">==5023==    by 0x5110474: x0::HttpWorker::_run(void*) (HttpWorker.cpp:141)</font></div><div><font face="courier new, monospace" size="1">==5023==    by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)</font></div>
</div><div><br></div><div>I hope somebody can tell me that this is a false positive or what I might be missing.</div><div><br></div><div>From what I can think of, I should not need any locks at for my threading model, there watchers are only modified inside their respective worker threads *except* the fact, that ev_async is used to notify thread A to thread B to wake up and do some work.</div>
<div><br></div><div>As you may see in the backtrace, I also tried to add a lock around struct ev_loop uses, as shown in the example of the libev man page, in the hope, that maybe I need that part there anyways, but appearently that didn't fix it either.</div>
<div><br></div><div>Any ideas?</div><div><br></div><div>Many thanks in advance,</div><div>Christian Parpart.</div></div>