nim-lang / threading

New atomics, thread primitives, atomic refcounting for --gc:arc/orc.
MIT License
72 stars 12 forks source link

Problem with destroying channels on linux #73

Open planetis-m opened 1 month ago

planetis-m commented 1 month ago

The manpage for pthread_mutex_init that Lock on linux is based on, states that (section: Destroying Mutexes):

Implementations are required to allow an object to be destroyed and freed and potentially unmapped (for example, lines A and B) immediately after the object is unlocked (line C).

Unfortunately without the lock/unlock on a lock before destroying it, there are multiple TSanitizers errors, in the following program:

import channels, os, std/isolation

type
  WorkRequest = ref object
    id: int

var
  chanIn: Chan[WorkRequest]
  thread: Thread[Chan[WorkRequest]]

proc workThread(chanIn: Chan[WorkRequest]) {.thread.} =
  echo "Started work thread"
  var req: WorkRequest
  chanIn.recv(req)
  echo "Got work ", req.id

proc main =
  chanIn = newChan[WorkRequest]()
  createThread(thread, workThread, chanIn)

  chanIn.send(isolate(WorkRequest(id: 1)))

  sleep(100) # Give thread time to run
  # joinThread(thread)

main()
Outputs 4 data-race warnings for the lock. ================== WARNING: ThreadSanitizer: data race (pid=2177) Write of size 8 at 0x723c00000000 by main thread: #0 free (test_chan2+0x768fa) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 channels::freeChannel(ptr) /home/antonisg/Code/threading/threading/channels.nim:173:3 (test_chan2+0x10578e) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::eqdestroy_(Chan>) /home/antonisg/Code/threading/threading/channels.nim:267:4 (test_chan2+0x10578e) #3 NimMainModule /home/antonisg/Code/threading/threading/channels.nim:270:2 (test_chan2+0x1068af) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x1068af) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x1068af) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x1068af) Previous read of size 8 at 0x723c00000000 by thread T1 (mutexes: write M0): #0 __tsan_memcpy (test_chan2+0x64e2b) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 nimCopyMem /home/antonisg/Build/Nim/lib/system/memory.nim:10:24 (test_chan2+0x105cbb) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 system::copyMem(pointer, pointer, range09223372036854775807) /home/antonisg/Build/Nim/lib/system.nim:2076:2 (test_chan2+0x105cbb) #3 channels::channelReceive(ptr, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:243:267 (test_chan2+0x105cbb) #4 channels::recv(Chan>, var>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 test_chan2::workThread(Chan>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a) #6 system::threadProcWrapDispatch(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #7 system::threadProcWrapStackFrame(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:95:2 (test_chan2+0x105266) #8 typedthreads::threadProcWrapper(pointer) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:101:2 (test_chan2+0x101c05) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) Mutex M0 (0x722c00000000) created at: #0 pthread_mutex_init (test_chan2+0x7880f) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::initLock(var) /home/antonisg/Build/Nim/lib/core/locks.nim:38:2 (test_chan2+0x1059b5) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::allocChannel(int, int) /home/antonisg/Code/threading/threading/channels.nim:159:2 (test_chan2+0x1059b5) #3 channels::newChan(range19223372036854775807) /home/antonisg/Code/threading/threading/channels.nim:377:13 (test_chan2+0x1059b5) #4 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:18:8 (test_chan2+0x1064d1) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #6 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #7 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #8 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Thread T1 (tid=2179, finished) created by main thread at: #0 pthread_create (test_chan2+0x77b5b) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 typedthreads::createThread(var>>>, proc>>, Chan>) /home/antonisg/Build/Nim/lib/std/typedthreads.nim:286:106 (test_chan2+0x101cfb) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:19:2 (test_chan2+0x106505) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #3 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) SUMMARY: ThreadSanitizer: data race (/home/antonisg/Code/threading/threading/test_chan2+0x768fa) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) in free ================== ================== WARNING: ThreadSanitizer: data race (pid=2177) Write of size 1 at 0x722c00000000 by main thread: #0 pthread_mutex_destroy (test_chan2+0x789cc) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::deinitLock(syslocks::SysLockObj) /home/antonisg/Build/Nim/lib/core/locks.nim:42:2 (test_chan2+0x105796) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::freeChannel(ptr) /home/antonisg/Code/threading/threading/channels.nim:175:2 (test_chan2+0x105796) #3 channels::eqdestroy_(Chan>) /home/antonisg/Code/threading/threading/channels.nim:267:4 (test_chan2+0x105796) #4 NimMainModule /home/antonisg/Code/threading/threading/channels.nim:270:2 (test_chan2+0x1068af) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x1068af) #6 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x1068af) #7 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x1068af) Previous atomic read of size 1 at 0x722c00000000 by thread T1 (mutexes: write M0): #0 pthread_mutex_unlock (test_chan2+0x7938c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::release(var) /home/antonisg/Build/Nim/lib/core/locks.nim:56:2 (test_chan2+0x105d29) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::channelReceive(ptr, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:250:2 (test_chan2+0x105d29) #3 channels::recv(Chan>, var>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 test_chan2::workThread(Chan>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a) #5 system::threadProcWrapDispatch(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #6 system::threadProcWrapStackFrame(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:95:2 (test_chan2+0x105266) #7 typedthreads::threadProcWrapper(pointer) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:101:2 (test_chan2+0x101c05) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) Location is heap block of size 176 at 0x722c00000000 allocated by main thread: #0 malloc (test_chan2+0x763ee) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 channels::allocChannel(int, int) /home/antonisg/Code/threading/threading/channels.nim:154:24 (test_chan2+0x105965) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::newChan(range19223372036854775807) /home/antonisg/Code/threading/threading/channels.nim:377:13 (test_chan2+0x105965) #3 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:18:8 (test_chan2+0x1064d1) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #6 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #7 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Mutex M0 (0x722c00000000) created at: #0 pthread_mutex_init (test_chan2+0x7880f) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::initLock(var) /home/antonisg/Build/Nim/lib/core/locks.nim:38:2 (test_chan2+0x1059b5) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::allocChannel(int, int) /home/antonisg/Code/threading/threading/channels.nim:159:2 (test_chan2+0x1059b5) #3 channels::newChan(range19223372036854775807) /home/antonisg/Code/threading/threading/channels.nim:377:13 (test_chan2+0x1059b5) #4 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:18:8 (test_chan2+0x1064d1) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #6 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #7 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #8 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Thread T1 (tid=2179, finished) created by main thread at: #0 pthread_create (test_chan2+0x77b5b) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 typedthreads::createThread(var>>>, proc>>, Chan>) /home/antonisg/Build/Nim/lib/std/typedthreads.nim:286:106 (test_chan2+0x101cfb) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:19:2 (test_chan2+0x106505) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #3 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) SUMMARY: ThreadSanitizer: data race (/home/antonisg/Code/threading/threading/test_chan2+0x789cc) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) in pthread_mutex_destroy ================== ================== WARNING: ThreadSanitizer: data race (pid=2177) Write of size 8 at 0x722c00000028 by main thread: #0 pthread_cond_destroy (test_chan2+0x78675) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::deinitCond(syslocks::SysCondObj) /home/antonisg/Build/Nim/lib/core/locks.nim:65:2 (test_chan2+0x10579f) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::freeChannel(ptr) /home/antonisg/Code/threading/threading/channels.nim:176:2 (test_chan2+0x10579f) #3 channels::eqdestroy_(Chan>) /home/antonisg/Code/threading/threading/channels.nim:267:4 (test_chan2+0x10579f) #4 NimMainModule /home/antonisg/Code/threading/threading/channels.nim:270:2 (test_chan2+0x1068af) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x1068af) #6 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x1068af) #7 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x1068af) Previous read of size 8 at 0x722c00000028 by thread T1 (mutexes: write M0): #0 pthread_cond_signal (test_chan2+0x78393) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::signal(var) /home/antonisg/Build/Nim/lib/core/locks.nim:73:2 (test_chan2+0x105d21) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::channelReceive(ptr, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:249:2 (test_chan2+0x105d21) #3 channels::recv(Chan>, var>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 test_chan2::workThread(Chan>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a) #5 system::threadProcWrapDispatch(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #6 system::threadProcWrapStackFrame(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:95:2 (test_chan2+0x105266) #7 typedthreads::threadProcWrapper(pointer) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:101:2 (test_chan2+0x101c05) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) As if synchronized via sleep: #0 nanosleep (test_chan2+0x81272) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 nossleep /home/antonisg/Build/Nim/lib/pure/os.nim:704:22 (test_chan2+0x106266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:23:2 (test_chan2+0x10666d) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #3 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Location is heap block of size 176 at 0x722c00000000 allocated by main thread: #0 malloc (test_chan2+0x763ee) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 channels::allocChannel(int, int) /home/antonisg/Code/threading/threading/channels.nim:154:24 (test_chan2+0x105965) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::newChan(range19223372036854775807) /home/antonisg/Code/threading/threading/channels.nim:377:13 (test_chan2+0x105965) #3 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:18:8 (test_chan2+0x1064d1) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #6 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #7 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Mutex M0 (0x722c00000000) created at: #0 pthread_mutex_init (test_chan2+0x7880f) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::initLock(var) /home/antonisg/Build/Nim/lib/core/locks.nim:38:2 (test_chan2+0x1059b5) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::allocChannel(int, int) /home/antonisg/Code/threading/threading/channels.nim:159:2 (test_chan2+0x1059b5) #3 channels::newChan(range19223372036854775807) /home/antonisg/Code/threading/threading/channels.nim:377:13 (test_chan2+0x1059b5) #4 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:18:8 (test_chan2+0x1064d1) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #6 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #7 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #8 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Thread T1 (tid=2179, finished) created by main thread at: #0 pthread_create (test_chan2+0x77b5b) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 typedthreads::createThread(var>>>, proc>>, Chan>) /home/antonisg/Build/Nim/lib/std/typedthreads.nim:286:106 (test_chan2+0x101cfb) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:19:2 (test_chan2+0x106505) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #3 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) SUMMARY: ThreadSanitizer: data race (/home/antonisg/Code/threading/threading/test_chan2+0x78675) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) in pthread_cond_destroy ================== ================== WARNING: ThreadSanitizer: data race (pid=2177) Write of size 8 at 0x722c00000088 by main thread: #0 free (test_chan2+0x768fa) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 channels::freeChannel(ptr) /home/antonisg/Code/threading/threading/channels.nim:179:2 (test_chan2+0x1057b0) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::eqdestroy_(Chan>) /home/antonisg/Code/threading/threading/channels.nim:267:4 (test_chan2+0x1057b0) #3 NimMainModule /home/antonisg/Code/threading/threading/channels.nim:270:2 (test_chan2+0x1068af) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x1068af) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x1068af) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x1068af) Previous read of size 8 at 0x722c00000088 by thread T1 (mutexes: write M0): #0 channels::channelReceive(ptr, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:246:180 (test_chan2+0x105cea) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 channels::recv(Chan>, var>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 test_chan2::workThread(Chan>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a) #3 system::threadProcWrapDispatch(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 system::threadProcWrapStackFrame(ptr>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:95:2 (test_chan2+0x105266) #5 typedthreads::threadProcWrapper(pointer) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:101:2 (test_chan2+0x101c05) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) Mutex M0 (0x722c00000000) created at: #0 pthread_mutex_init (test_chan2+0x7880f) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 locks::initLock(var) /home/antonisg/Build/Nim/lib/core/locks.nim:38:2 (test_chan2+0x1059b5) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 channels::allocChannel(int, int) /home/antonisg/Code/threading/threading/channels.nim:159:2 (test_chan2+0x1059b5) #3 channels::newChan(range19223372036854775807) /home/antonisg/Code/threading/threading/channels.nim:377:13 (test_chan2+0x1059b5) #4 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:18:8 (test_chan2+0x1064d1) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #5 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #6 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #7 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #8 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) Thread T1 (tid=2179, finished) created by main thread at: #0 pthread_create (test_chan2+0x77b5b) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #1 typedthreads::createThread(var>>>, proc>>, Chan>) /home/antonisg/Build/Nim/lib/std/typedthreads.nim:286:106 (test_chan2+0x101cfb) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #2 test_chan2::main /home/antonisg/Code/threading/threading/test_chan2.nim:19:2 (test_chan2+0x106505) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #3 NimMainModule /home/antonisg/Code/threading/threading/test_chan2.nim:26:2 (test_chan2+0x10687c) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) #4 NimMainInner /home/antonisg/Code/threading/threading/test_chan2.nim:44:2 (test_chan2+0x10687c) #5 NimMain /home/antonisg/Code/threading/threading/test_chan2.nim:55:2 (test_chan2+0x10687c) #6 main /home/antonisg/Code/threading/threading/test_chan2.nim:63:2 (test_chan2+0x10687c) SUMMARY: ThreadSanitizer: data race (/home/antonisg/Code/threading/threading/test_chan2+0x768fa) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3) in free ==================

It can be circumvented by using:

proc `=destroy`*[T](c: Chan[T]) =
  if c.d != nil:
    # this `fetchSub` returns current val then subs
    # so count == 0 means we're the last
    if c.d.atomicCounter.fetchSub(1, moAcquireRelease) == 0:
      acquire(c.d.lock)
      release(c.d.lock)
      freeChannel(c.d)

At this point I don't know if it would make any sense to just use the example code in the above manpage and reuse the lock for the ref count, like: Edit: bad idea

proc `=destroy`*[T](c: Chan[T]) =
  if c.d != nil:
    acquire(c.d.lock)
    dec c.d.counter
    if c.d.counter == 0:
      release(c.d.lock)
      freeChannel(c.d)

Thoughts?

planetis-m commented 1 month ago

The tests https://github.com/nim-lang/threading/actions/runs/10359938571/job/28677376500?pr=72 report these errors only on linux and macosx seems unaffected.