This is an archive of the discontinued LLVM Phabricator instance.

[tsan] Stop extending the block’s lifetime in dispatch_group_async
ClosedPublic

Authored by kubamracek on Jun 28 2016, 2:49 PM.

Details

Summary

Our dispatch_group_async interceptor actually extends the lifetime of the executed block. This means the destructor of the block (and captured variables) is called *after* dispatch_group_leave, which changes the semantics of dispatch_group_async.

Diff Detail

Repository
rL LLVM

Event Timeline

kubamracek updated this revision to Diff 62139.Jun 28 2016, 2:49 PM
kubamracek retitled this revision from to [tsan] Stop extending the block’s lifetime in dispatch_group_async.
kubamracek updated this object.
kubamracek added reviewers: dvyukov, kcc, glider.
kubamracek added a project: Restricted Project.
kubamracek added subscribers: llvm-commits, zaks.anna.
dvyukov added inline comments.Jun 29 2016, 1:21 AM
lib/tsan/rtl/tsan_libdispatch_mac.cc
289 ↗(On Diff #62139)

What does keep the block alive currently? When is it destroyed without this change?

test/tsan/Darwin/gcd-groups-destructor.mm
43 ↗(On Diff #62139)

AFAIK, filecheck checks line-by-line, so this ensures that there are no WARNINGS _after_ "Done." is printed. I think you need to move CHECK_NOT before Done CHECK.

kubamracek added inline comments.Jun 29 2016, 2:31 AM
lib/tsan/rtl/tsan_libdispatch_mac.cc
289 ↗(On Diff #62139)

Without this change, the block named "block" is captured by this anonymous block that's submitted via dispatch_async, and it's also released only when this anonymous block is released (after dispatch completely executes it). That means the release only happens after the two lines below (call to dispatch_group_leave and dispatch_release).

With this change, we're avoiding the capture (with __block) by explicitly copying the block. It will be released/destroyed at the call to _Block_release (as long as there are no other references to the block).

test/tsan/Darwin/gcd-groups-destructor.mm
43 ↗(On Diff #62139)

Ok

dvyukov accepted this revision.Jun 29 2016, 2:45 AM
dvyukov edited edge metadata.

Is that pile of fixes happened because people started using tsan for their real programs?

lib/tsan/rtl/tsan_libdispatch_mac.cc
289 ↗(On Diff #62139)

For my education: how does compiler/runtime know that it needs to capture the block with the current code, but does not need to capture with the new code? I mean in both cases a dispatch_block_t variable is referenced from ^(void){} block. So I would expect the capture happen in both cases.

This revision is now accepted and ready to land.Jun 29 2016, 2:45 AM
kubamracek added inline comments.Jun 29 2016, 3:10 AM
lib/tsan/rtl/tsan_libdispatch_mac.cc
289 ↗(On Diff #62139)

It’s the __block keyword. Objects with __block (blocks are objects) aren’t retained, they’re "captured directly" instead.

This revision was automatically updated to reflect the committed changes.

Is that pile of fixes happened because people started using tsan for their real programs?

Yes. A lot of both internal and external developers are using TSan now and they’re finding real races.