Skip to content

Commit 959d76c

Browse files
authored
Merge pull request #63842 from apple/rokhinip/105634683-tsan-consume-annotations
TSAN and memory order consume semantics
2 parents 8790101 + e8d9fd9 commit 959d76c

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ void _swift_taskGroup_detachChild(TaskGroup *group, AsyncTask *child);
103103
/// on the same address.
104104
void _swift_tsan_acquire(void *addr);
105105
void _swift_tsan_release(void *addr);
106+
/// Technically, this consume relies on implicit HW address dependency ordering
107+
/// and is paired with a corresponding release. Since TSAN doesn't know how to
108+
/// reason about this, we tell TSAN it's an acquire instead. See also
109+
/// SWIFT_MEMORY_ORDER_CONSUME definition.
110+
#define _swift_tsan_consume _swift_tsan_acquire
106111

107112
/// Special values used with DispatchQueueIndex to indicate the global and main
108113
/// executors.

stdlib/public/Concurrency/TaskStatus.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ static bool waitForStatusRecordUnlockIfNotSelfLocked(AsyncTask *task,
116116
// withStatusRecordLock so that lock record contents are visible due to
117117
// load-through HW address dependency
118118
status = task->_private()._status().load(SWIFT_MEMORY_ORDER_CONSUME);
119+
_swift_tsan_consume(task);
119120

120121
if (!status.isStatusRecordLocked())
121122
return nullptr;
@@ -134,6 +135,7 @@ static bool waitForStatusRecordUnlockIfNotSelfLocked(AsyncTask *task,
134135

135136
// Reload the status before trying to relock
136137
status = task->_private()._status().load(SWIFT_MEMORY_ORDER_CONSUME);
138+
_swift_tsan_consume(task);
137139
if (!status.isStatusRecordLocked())
138140
return false;
139141
}
@@ -159,6 +161,7 @@ static void waitForStatusRecordUnlock(AsyncTask *task,
159161
// withStatusRecordLock so that lock record contents are visible due to
160162
// load-through HW address dependency
161163
status = task->_private()._status().load(SWIFT_MEMORY_ORDER_CONSUME);
164+
_swift_tsan_consume(task);
162165
if (!status.isStatusRecordLocked())
163166
return nullptr;
164167

@@ -175,6 +178,7 @@ static void waitForStatusRecordUnlock(AsyncTask *task,
175178

176179
// Reload the status before trying to relock.
177180
status = task->_private()._status().load(SWIFT_MEMORY_ORDER_CONSUME);
181+
_swift_tsan_consume(task);
178182
if (!status.isStatusRecordLocked())
179183
return;
180184
}
@@ -215,13 +219,17 @@ static bool withStatusRecordLock(AsyncTask *task, ActiveTaskStatus status,
215219
oldRecord = status.getInnermostRecord();
216220
lockingRecord = worker.createQueue(oldRecord);
217221

218-
// Publish the lock record with an acquire so that all lock operations are
219-
// bounded.
222+
// Publish the lock record
223+
// * We need an acquire to pair with release of someone else who might have
224+
// unlocked
225+
// * We need a store release to publish the lock record contents
220226
ActiveTaskStatus newStatus = status.withLockingRecord(lockingRecord);
221227
if (task->_private()._status().compare_exchange_weak(status, newStatus,
222-
/*success*/ std::memory_order_acquire,
228+
/*success*/ std::memory_order_acq_rel,
223229
/*failure*/ std::memory_order_relaxed)) {
224230
_swift_tsan_acquire(task);
231+
_swift_tsan_release(task);
232+
225233
status = newStatus;
226234

227235
status.traceStatusChanged(task);
@@ -617,6 +625,7 @@ static void swift_task_cancelImpl(AsyncTask *task) {
617625
if (task->_private()._status().compare_exchange_weak(oldStatus, newStatus,
618626
/*success*/ SWIFT_MEMORY_ORDER_CONSUME,
619627
/*failure*/ std::memory_order_relaxed)) {
628+
_swift_tsan_consume(task);
620629
break;
621630
}
622631
}
@@ -723,6 +732,7 @@ static swift_task_escalateImpl(AsyncTask *task, JobPriority newPriority) {
723732
if (task->_private()._status().compare_exchange_weak(oldStatus, newStatus,
724733
/* success */ SWIFT_MEMORY_ORDER_CONSUME,
725734
/* failure */ std::memory_order_relaxed)) {
735+
_swift_tsan_consume(task);
726736
break;
727737
}
728738
}

0 commit comments

Comments
 (0)