Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with destroying channels on linux #73

Open
planetis-m opened this issue Aug 12, 2024 · 1 comment
Open

Problem with destroying channels on linux #73

planetis-m opened this issue Aug 12, 2024 · 1 comment

Comments

@planetis-m
Copy link
Contributor

planetis-m commented Aug 12, 2024

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(ptrchannels::ChannelObj, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:243:267 (test_chan2+0x105cbb)
#4 channels::recv(Chan<ref<test_chan2::WorkRequestcolonObjectType
>>, var<ref<test_chan2::WorkRequestcolonObjectType
>>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#5 test_chan2::workThread(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a)
#6 system::threadProcWrapDispatch(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#7 system::threadProcWrapStackFrame(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /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(varsyslocks::SysLockObj) /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<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>, proc<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>, Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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(ptrchannels::ChannelObj) /home/antonisg/Code/threading/threading/channels.nim:175:2 (test_chan2+0x105796)
#3 channels::eqdestroy_(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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(varsyslocks::SysLockObj) /home/antonisg/Build/Nim/lib/core/locks.nim:56:2 (test_chan2+0x105d29) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#2 channels::channelReceive(ptrchannels::ChannelObj, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:250:2 (test_chan2+0x105d29)
#3 channels::recv(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>, var<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#4 test_chan2::workThread(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a)
#5 system::threadProcWrapDispatch(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#6 system::threadProcWrapStackFrame(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /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(varsyslocks::SysLockObj) /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<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>, proc<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>, Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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(ptrchannels::ChannelObj) /home/antonisg/Code/threading/threading/channels.nim:176:2 (test_chan2+0x10579f)
#3 channels::eqdestroy_(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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(varsyslocks::SysCondObj) /home/antonisg/Build/Nim/lib/core/locks.nim:73:2 (test_chan2+0x105d21) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#2 channels::channelReceive(ptrchannels::ChannelObj, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:249:2 (test_chan2+0x105d21)
#3 channels::recv(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>, var<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#4 test_chan2::workThread(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a)
#5 system::threadProcWrapDispatch(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#6 system::threadProcWrapStackFrame(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /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(varsyslocks::SysLockObj) /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<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>, proc<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>, Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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(ptrchannels::ChannelObj) /home/antonisg/Code/threading/threading/channels.nim:179:2 (test_chan2+0x1057b0) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#2 channels::eqdestroy_(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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(ptrchannels::ChannelObj, pointer, int, static) /home/antonisg/Code/threading/threading/channels.nim:246:180 (test_chan2+0x105cea) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#1 channels::recv(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>, var<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/channels.nim:352:27 (test_chan2+0x10637a) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#2 test_chan2::workThread(Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /home/antonisg/Code/threading/threading/test_chan2.nim:14:2 (test_chan2+0x10637a)
#3 system::threadProcWrapDispatch(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /home/antonisg/Build/Nim/lib/system/threadimpl.nim:69:2 (test_chan2+0x105266) (BuildId: af47ab0ed122b9b0ba59f0cbf3a7b839a67873e3)
#4 system::threadProcWrapStackFrame(ptr<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>) /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(varsyslocks::SysLockObj) /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<Thread<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>>, proc<Chan<ref<test_chan2::WorkRequestcolonObjectType_>>>, Chan<ref<test_chan2::WorkRequestcolonObjectType_>>) /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 planetis-m changed the title Problem with destroying channels on unix Problem with destroying channels on linux Aug 12, 2024
@planetis-m
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant