Open
Description
Description
Thread sanitiser and valgrind (--tool=helgrind) report a data race (probably read) in typedthreads.nim on line 274 (Using devel version of the compiler. The problem also occurs with other compiler versions, but the reported line numbers vary.).
Example using channels:
import
std/net,
std/locks,
std/os
var lock: Lock = Lock()
type SocketOpts* = object
socket*: Socket
proc processSession(thChan: ptr Channel[Socket]) {.thread.} =
var response: tuple[dataAvailable: bool, msg: Socket]
withLock lock:
try:
response = thChan[].tryRecv()
except:
debugEcho "Unable to receive chan message"
return
if response.dataAvailable:
if response.msg.isNil:
withLock lock:
debugEcho "Client socket is nil"
return
withLock lock:
debugEcho "Thread ", getThreadId(), " got request to send to socket ", cast[uint16](response.msg[])
discard trySend(response.msg, "hello\n")
sleep(1000)
withLock lock:
response.msg.close
try:
initLock(lock)
except:
#log error
debugEcho "Unable to init rlock"
var
thr: array[10, Thread[ptr Channel[Socket]]]
sockets: array[10, Channel[Socket]]
address: string = ""
client: Socket = Socket()
for id in 0..sockets.high:
try:
sockets[id].open()
except:
quit 1
proc startServer*(srv: var SocketOpts): void =
try:
srv.socket = newSocket()
srv.socket.setSockOpt(OptReusePort, true)
srv.socket.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint)
srv.socket.bindAddr(Port(3333))
srv.socket.listen()
var id: int = 0
while true:
srv.socket.acceptAddr(client, address)
withLock lock:
if thr[id].running:
debugEcho "No threads available"
client.send("No threads available")
client.close()
continue
createThread(thr[id], processSession, sockets[id].unsafeAddr)
while not sockets[id].trySend(client):
echo "Try again"
client = Socket()
if id == thr.high:
id = 0
else:
id.inc
except:
#log error here!!!
debugEcho "ERROR!"
deinitLock lock
let excpt: ref Exception = getCurrentException()
debugEcho excpt.msg
return
deinitLock(lock)
var params: SocketOpts
startServer(params)
Example of using an array to store client sockets:
import
std/net,
std/locks,
std/os
type SocketOpts* = object
socket*: Socket
var lock: Lock = Lock()
proc processSession(sock: Socket) {.thread.} =
if sock.isNil:
withLock lock:
debugEcho "Client socket is nil"
return
withLock lock:
debugEcho "Thread ", getThreadId(), " got request to send to socket ", cast[uint16](sock[])
discard trySend(sock, "hello\n")
sleep(1000)
withLock lock:
sock.close
try:
initLock(lock)
except:
#log error
debugEcho "Unable to init rlock"
var
thr: array[0..10, Thread[Socket]]
sockets: array[0..10, Socket]
address: string = ""
client: Socket = Socket()
proc startServer*(srv: var SocketOpts): void =
try:
srv.socket = newSocket()
srv.socket.setSockOpt(OptReusePort, true)
srv.socket.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint)
srv.socket.bindAddr(Port(3333))
srv.socket.listen()
var id: int = 0
while true:
srv.socket.accept(client)
withLock lock:
if thr[id].running:
debugEcho "No threads available"
client.send("No threads available")
client.close()
continue
sockets[id] = client
copyMem(sockets[id].unsafeAddr, client.unsafeAddr, sizeof(Socket))
echo "Client connected from: ", address, ". Socket: ", cast[uint16](sockets[id])
createThread(thr[id], processSession, sockets[id])
client = Socket()
if id == thr.high:
id = 0
else:
id.inc
except:
#log error here!!!
debugEcho "ERROR!"
deinitLock lock
let excpt: ref Exception = getCurrentException()
debugEcho excpt.msg
return
deinitLock(lock)
var params: SocketOpts
startServer(params)
nim.cfg :
--gc:orc
--lineTrace:on
--lineDir:on
--d:nimTypeNames
--debuginfo
--d:debug
--d:nimDebugDlOpen
--d:useMalloc
--opt:none
--passC:" -g3 -O0 -fsanitize=thread"
--passL:" -g3 -O0 -fsanitize=thread"
Nim Version
Current devel version,
2.2.0
1.6.20
Current Output
Following output
WARNING: ThreadSanitizer: data race (pid=41382)
Read of size 8 at 0x000102add050 by main thread (mutexes: write M0):
#0 typedthreads::running(Thread<ptr<Channel<ref<net::SocketImpl>>>>) typedthreads.nim:154 (testTcpServerChannels:arm64+0x100023a28)
#1 testTcpServerChannels::startServer(var<testTcpServerChannels::SocketOpts>) testTcpServerChannels.nim:71 (testTcpServerChannels:arm64+0x1000233f8)
#2 NimMainModule testTcpServerChannels.nim:93 (testTcpServerChannels:arm64+0x100024384)
#3 NimMainInner testTcpServerChannels.nim:58 (testTcpServerChannels:arm64+0x10002403c)
#4 NimMain testTcpServerChannels.nim:64 (testTcpServerChannels:arm64+0x1000244e4)
#5 main testTcpServerChannels.nim:72 (testTcpServerChannels:arm64+0x1000245b0)
Previous write of size 8 at 0x000102add050 by thread T1:
#0 typedthreads::threadProcWrapper(pointer) threadimpl.nim:110 (testTcpServerChannels:arm64+0x100008148)
Location is global 'thr__test84cp83erver67hannels_u86' at 0x000102add040 (testTcpServerChannels+0x100031050)
Mutex M0 (0x000102adc8e0) created at:
#0 pthread_mutex_init <null>:91232944 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x3181c)
#1 locks::initLock(var<syslocks::SysLockObj>) locks.nim:38 (testTcpServerChannels:arm64+0x100024614)
#2 NimMainModule testTcpServerChannels.nim:32 (testTcpServerChannels:arm64+0x1000240b0)
#3 NimMainInner testTcpServerChannels.nim:58 (testTcpServerChannels:arm64+0x10002403c)
#4 NimMain testTcpServerChannels.nim:64 (testTcpServerChannels:arm64+0x1000244e4)
#5 main testTcpServerChannels.nim:72 (testTcpServerChannels:arm64+0x1000245b0)
Thread T1 (tid=10953362, finished) created by main thread at:
#0 pthread_create <null>:91232944 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
#1 typedthreads::createThread(var<Thread<ptr<Channel<ref<net::SocketImpl>>>>>, proc<ptr<Channel<ref<net::SocketImpl>>>>, ptr<Channel<ref<net::SocketImpl>>>) typedthreads.nim:292 (testTcpServerChannels:arm64+0x100008350)
#2 testTcpServerChannels::startServer(var<testTcpServerChannels::SocketOpts>) testTcpServerChannels.nim:78 (testTcpServerChannels:arm64+0x1000235e0)
#3 NimMainModule testTcpServerChannels.nim:93 (testTcpServerChannels:arm64+0x100024384)
#4 NimMainInner testTcpServerChannels.nim:58 (testTcpServerChannels:arm64+0x10002403c)
#5 NimMain testTcpServerChannels.nim:64 (testTcpServerChannels:arm64+0x1000244e4)
#6 main testTcpServerChannels.nim:72 (testTcpServerChannels:arm64+0x1000245b0)
SUMMARY: ThreadSanitizer: data race typedthreads.nim:154 in typedthreads::running(Thread<ptr<Channel<ref<net::SocketImpl>>>>)
==================
==================
WARNING: ThreadSanitizer: data race (pid=41382)
Write of size 8 at 0x000102add040 by main thread (mutexes: write M0):
#0 typedthreads::createThread(var<Thread<ptr<Channel<ref<net::SocketImpl>>>>>, proc<ptr<Channel<ref<net::SocketImpl>>>>, ptr<Channel<ref<net::SocketImpl>>>) typedthreads.nim:274 (testTcpServerChannels:arm64+0x100008214)
#1 testTcpServerChannels::startServer(var<testTcpServerChannels::SocketOpts>) testTcpServerChannels.nim:78 (testTcpServerChannels:arm64+0x1000235e0)
#2 NimMainModule testTcpServerChannels.nim:93 (testTcpServerChannels:arm64+0x100024384)
#3 NimMainInner testTcpServerChannels.nim:58 (testTcpServerChannels:arm64+0x10002403c)
#4 NimMain testTcpServerChannels.nim:64 (testTcpServerChannels:arm64+0x1000244e4)
#5 main testTcpServerChannels.nim:72 (testTcpServerChannels:arm64+0x1000245b0)
Previous write of size 8 at 0x000102add040 by thread T1:
#0 typedthreads::threadProcWrapper(pointer) threadimpl.nim:109 (testTcpServerChannels:arm64+0x100008130)
Location is global 'thr__test84cp83erver67hannels_u86' at 0x000102add040 (testTcpServerChannels+0x100031040)
Mutex M0 (0x000102adc8e0) created at:
#0 pthread_mutex_init <null>:91232944 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x3181c)
#1 locks::initLock(var<syslocks::SysLockObj>) locks.nim:38 (testTcpServerChannels:arm64+0x100024614)
#2 NimMainModule testTcpServerChannels.nim:32 (testTcpServerChannels:arm64+0x1000240b0)
#3 NimMainInner testTcpServerChannels.nim:58 (testTcpServerChannels:arm64+0x10002403c)
#4 NimMain testTcpServerChannels.nim:64 (testTcpServerChannels:arm64+0x1000244e4)
#5 main testTcpServerChannels.nim:72 (testTcpServerChannels:arm64+0x1000245b0)
Thread T1 (tid=10953362, finished) created by main thread at:
#0 pthread_create <null>:91232944 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
#1 typedthreads::createThread(var<Thread<ptr<Channel<ref<net::SocketImpl>>>>>, proc<ptr<Channel<ref<net::SocketImpl>>>>, ptr<Channel<ref<net::SocketImpl>>>) typedthreads.nim:292 (testTcpServerChannels:arm64+0x100008350)
#2 testTcpServerChannels::startServer(var<testTcpServerChannels::SocketOpts>) testTcpServerChannels.nim:78 (testTcpServerChannels:arm64+0x1000235e0)
#3 NimMainModule testTcpServerChannels.nim:93 (testTcpServerChannels:arm64+0x100024384)
#4 NimMainInner testTcpServerChannels.nim:58 (testTcpServerChannels:arm64+0x10002403c)
#5 NimMain testTcpServerChannels.nim:64 (testTcpServerChannels:arm64+0x1000244e4)
#6 main testTcpServerChannels.nim:72 (testTcpServerChannels:arm64+0x1000245b0)
SUMMARY: ThreadSanitizer: data race typedthreads.nim:274 in typedthreads::createThread(var<Thread<ptr<Channel<ref<net::SocketImpl>>>>>, proc<ptr<Channel<ref<net::SocketImpl>>>>, ptr<Channel<ref<net::SocketImpl>>>)
Expected Output
No response
Known Workarounds
No response
Additional Information
To test the code, use the following tools in two separate terminals
watch -n 0.1 nc 127.0.0.1 3333
To test with valgrind (--tool=helgrind), the thread sanitiser should be disabled.
Metadata
Metadata
Assignees
Labels
No labels