Skip to content

Commit 9f5a707

Browse files
committed
back to println tests
1 parent b039691 commit 9f5a707

7 files changed

+132
-95
lines changed

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464

6565
using namespace swift;
6666

67-
#if 1
67+
#if 0
6868
#define SWIFT_TASK_GROUP_DEBUG_LOG(group, fmt, ...) \
6969
fprintf(stderr, "[%#lx] [%s:%d][group(%p%s)] (%s) " fmt "\n", \
7070
(unsigned long)Thread::current().platformThreadId(), \
@@ -390,7 +390,11 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
390390
virtual void enqueueCompletedTask(AsyncTask *completedTask, bool hadErrorResult) = 0;
391391

392392
/// Resume waiting task with result from `completedTask`
393-
void resumeWaitingTask(AsyncTask *completedTask, TaskGroupStatus &assumed, bool hadErrorResult, bool alreadyDecremented = false);
393+
void resumeWaitingTask(AsyncTask *completedTask,
394+
TaskGroupStatus &assumed,
395+
bool hadErrorResult,
396+
bool alreadyDecremented = false,
397+
bool taskWasRetained = false);
394398

395399
// ==== Status manipulation -------------------------------------------------
396400

@@ -827,7 +831,9 @@ class DiscardingTaskGroup: public TaskGroupBase {
827831

828832
private:
829833
/// Resume waiting task with specified error
830-
void resumeWaitingTaskWithError(SwiftError *error, TaskGroupStatus &assumed, bool alreadyDecremented);
834+
void resumeWaitingTaskWithError(SwiftError *error,
835+
TaskGroupStatus &assumed,
836+
bool alreadyDecremented);
831837
};
832838

833839
} // end anonymous namespace
@@ -1040,7 +1046,7 @@ static void fillGroupNextResult(TaskFutureWaitAsyncContext *context,
10401046

10411047
case PollStatus::Error: {
10421048
auto error = reinterpret_cast<SwiftError *>(result.storage);
1043-
fillGroupNextErrorResult(context, error); // FIXME: this specifically retains the error, but likely should not!??!!?
1049+
fillGroupNextErrorResult(context, error);
10441050
return;
10451051
}
10461052

@@ -1240,11 +1246,16 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
12401246
switch (readyErrorItem.getStatus()) {
12411247
case ReadyStatus::RawError:
12421248
SWIFT_TASK_GROUP_DEBUG_LOG(this, "offer, complete, resume with raw error:%p", readyErrorItem.getRawError(this));
1243-
resumeWaitingTaskWithError(readyErrorItem.getRawError(this), assumed, alreadyDecrementedStatus);
1249+
resumeWaitingTaskWithError(readyErrorItem.getRawError(this), assumed,
1250+
alreadyDecrementedStatus);
12441251
break;
12451252
case ReadyStatus::Error:
12461253
SWIFT_TASK_GROUP_DEBUG_LOG(this, "offer, complete, resume with errorItem.task:%p", readyErrorItem.getTask());
1247-
resumeWaitingTask(readyErrorItem.getTask(), assumed, /*hadErrorResult=*/true, alreadyDecrementedStatus);
1254+
SWIFT_TASK_GROUP_DEBUG_LOG(this, "offer, complete, expect that it was extra retained %p", readyErrorItem.getTask());
1255+
resumeWaitingTask(readyErrorItem.getTask(), assumed,
1256+
/*hadErrorResult=*/true,
1257+
alreadyDecrementedStatus,
1258+
/*taskWasRetained=*/true);
12481259
break;
12491260
default:
12501261
swift_Concurrency_fatalError(0,
@@ -1283,7 +1294,10 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
12831294
resumeWaitingTaskWithError(readyErrorItem.getRawError(this), assumed, alreadyDecrementedStatus);
12841295
break;
12851296
case ReadyStatus::Error:
1286-
resumeWaitingTask(readyErrorItem.getTask(), assumed, /*hadErrorResult=*/true, alreadyDecrementedStatus);
1297+
resumeWaitingTask(readyErrorItem.getTask(), assumed,
1298+
/*hadErrorResult=*/true,
1299+
alreadyDecrementedStatus,
1300+
/*taskWasRetained=*/true);
12871301
break;
12881302
default:
12891303
swift_Concurrency_fatalError(0,
@@ -1293,14 +1307,6 @@ void DiscardingTaskGroup::offer(AsyncTask *completedTask, AsyncContext *context)
12931307
// This is the last task, we have a waiting task and there was no error stored previously;
12941308
// We must resume the waiting task with a success, so let us return here.
12951309
resumeWaitingTask(completedTask, assumed, /*hadErrorResult=*/false, alreadyDecrementedStatus);
1296-
1297-
// // TODO: since the DiscardingTaskGroup ended up written as `-> T` in order to use the same pointer auth as the
1298-
// // usual task closures; we end up retaining the value when it is returned. As this is a discarding group
1299-
// // we actually can and should release this value.
1300-
// // Is there a way we could avoid the retain made on the returned value entirely?
1301-
// if (completedTask->futureFragment()->getResultType()->isClassObject()) {
1302-
// swift_release(reinterpret_cast<HeapObject *>(completedTask->futureFragment()->getStoragePtr()));
1303-
// }
13041310
}
13051311
} else {
13061312
// it wasn't the last pending task, and there is no-one to resume;
@@ -1317,7 +1323,8 @@ void TaskGroupBase::resumeWaitingTask(
13171323
AsyncTask *completedTask,
13181324
TaskGroupStatus &assumed,
13191325
bool hadErrorResult,
1320-
bool alreadyDecremented) {
1326+
bool alreadyDecremented,
1327+
bool taskWasRetained) {
13211328
auto waitingTask = waitQueue.load(std::memory_order_acquire);
13221329
assert(waitingTask && "waitingTask must not be null when attempting to resume it");
13231330
assert(assumed.hasWaitingTask());
@@ -1384,14 +1391,14 @@ void TaskGroupBase::resumeWaitingTask(
13841391
auto before = completedTask;
13851392
_swift_taskGroup_detachChild(asAbstract(this), completedTask);
13861393
SWIFT_TASK_GROUP_DEBUG_LOG(this, "completedTask %p; AFTER DETACH (count:%d)", completedTask, swift_retainCount(completedTask));
1387-
if (hadErrorResult) {
1394+
if (isDiscardingResults() && hadErrorResult && taskWasRetained) {
13881395
SWIFT_TASK_GROUP_DEBUG_LOG(this, "BEFORE RELEASE error task=%p (count:%d)\n",
13891396
completedTask,
13901397
swift_retainCount(completedTask));
13911398
// We only used the task to keep the error in the future fragment around
13921399
// so now that we emitted the error and detached the task, we are free to release the task immediately.
1393-
auto error = reinterpret_cast<SwiftError *>(result.storage);
1394-
swift_release(completedTask); // we need to do this if the error is a class
1400+
auto error = completedTask->futureFragment()->getError();
1401+
swift_release(completedTask);
13951402
}
13961403

13971404
_swift_tsan_acquire(static_cast<Job *>(waitingTask));

stdlib/public/runtime/HeapObject.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,15 +525,13 @@ void (*SWIFT_RT_DECLARE_ENTRY _swift_release)(HeapObject *object) =
525525
_swift_release_;
526526

527527
void swift::swift_nonatomic_release(HeapObject *object) {
528-
fprintf(stderr, "[%s:%d](%s) swift_nonatomic_release %p\n", __FILE_NAME__, __LINE__, __FUNCTION__, object);
529528
SWIFT_RT_TRACK_INVOCATION(object, swift_nonatomic_release);
530529
if (isValidPointerForNativeRetain(object))
531530
object->refCounts.decrementAndMaybeDeinitNonAtomic(1);
532531
}
533532

534533
SWIFT_ALWAYS_INLINE
535534
static void _swift_release_n_(HeapObject *object, uint32_t n) {
536-
fprintf(stderr, "[%s:%d](%s) _swift_release_n_ %p (n=%d)\n", __FILE_NAME__, __LINE__, __FUNCTION__, object, n);
537535
SWIFT_RT_TRACK_INVOCATION(object, swift_release_n);
538536
if (isValidPointerForNativeRetain(object))
539537
object->refCounts.decrementAndMaybeDeinit(n);
@@ -797,8 +795,6 @@ void swift::swift_unownedCheck(HeapObject *object) {
797795
}
798796

799797
void _swift_release_dealloc(HeapObject *object) {
800-
fprintf(stderr, "[%s:%d](%s) _swift_release_dealloc %p (count before: %d)\n", __FILE_NAME__, __LINE__, __FUNCTION__, object,
801-
swift_retainCount(object));
802798
asFullMetadata(object->metadata)->destroy(object);
803799
}
804800

test/Concurrency/Runtime/async_taskgroup_discarding.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-run-simple-leaks-swift( -Xfrontend -disable-availability-checking -parse-as-library)
1+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library) | %FileCheck %s
2+
// TODO: move to target-run-simple-leaks-swift once CI is using at least Xcode 14.3
23

34
// REQUIRES: concurrency
45
// REQUIRES: executable_test
@@ -11,31 +12,30 @@
1112
// UNSUPPORTED: OS=windows-msvc
1213

1314
import _Concurrency
14-
import Darwin
1515

16-
final class FIRST_PAYLOAD {}
17-
final class SECOND_PAYLOAD {}
16+
final class PayloadFirst {}
17+
final class PayloadSecond {}
1818

19-
final class FIRST_ERROR: Error {
20-
let first: FIRST_PAYLOAD
19+
final class ErrorFirst: Error {
20+
let first: PayloadFirst
2121

2222
init(file: String = #fileID, line: UInt = #line) {
2323
first = .init()
2424
}
2525
deinit {
26-
fputs("\(Self.self) deinit\n", stderr)
26+
print("deinit \(self)")
2727
}
2828
}
2929

30-
final class SECOND_ERROR: Error {
31-
let second: SECOND_PAYLOAD
30+
final class ErrorSecond: Error {
31+
let second: PayloadSecond
3232

3333
init(file: String = #fileID, line: UInt = #line) {
3434
second = .init()
3535
}
3636

3737
deinit {
38-
fputs("\(Self.self) deinit\n", stderr)
38+
print("deinit \(self)")
3939
}
4040
}
4141

@@ -55,20 +55,20 @@ func shouldStartWith(_ lhs: Any, _ rhs: Any) {
5555
1
5656
}
5757
group.addTask {
58-
throw FIRST_ERROR()
58+
throw ErrorFirst()
5959
}
6060

61-
// try? await Task.sleep(for: .seconds(1))
62-
6361
group.addTask {
64-
throw SECOND_ERROR()
62+
throw ErrorSecond()
6563
}
6664

6765
return 12
6866
}
6967
fatalError("expected error to be re-thrown, got: \(got)")
7068
} catch {
71-
// shouldStartWith(error, "main.Boom")
69+
shouldStartWith(error, "main.Error")
7270
}
71+
// CHECK: deinit main.Error
72+
// CHECK: deinit main.Error
7373
}
7474
}

test/Concurrency/Runtime/async_taskgroup_discarding_dontLeak.swift

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// RUN: %target-run-simple-leaks-swift( -Xfrontend -disable-availability-checking -parse-as-library)
2-
3-
// This test uses `leaks` which is only available on apple platforms; limit it to macOS:
4-
// REQUIRES: OS=macosx
1+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library) | %FileCheck %s --dump-input=always
2+
// TODO: move to target-run-simple-leaks-swift once CI is using at least Xcode 14.3
53

64
// REQUIRES: concurrency
75
// REQUIRES: executable_test
@@ -15,38 +13,45 @@
1513

1614
import _Concurrency
1715

18-
struct Boom: Error {
16+
final class PrintDeinit {
1917
let id: String
18+
init(id: String) {
19+
self.id = id
20+
}
2021

21-
init(file: String = #fileID, line: UInt = #line) {
22-
self.id = "\(file):\(line)"
22+
deinit {
23+
print("deinit, id: \(id)")
2324
}
25+
}
26+
27+
struct Boom: Error {
28+
let printDeinit: PrintDeinit
2429

2530
init(id: String) {
26-
self.id = id
31+
self.printDeinit = PrintDeinit(id: id)
2732
}
2833
}
2934

3035
final class BoomClass: Error {
3136
let id: String
3237

33-
init(file: String = #fileID, line: UInt = #line) {
34-
self.id = "\(file):\(line)"
35-
}
36-
3738
init(id: String) {
3839
self.id = id
3940
}
41+
42+
deinit {
43+
print("deinit, id: \(id)")
44+
}
4045
}
4146

4247
final class SomeClass: @unchecked Sendable {
43-
//struct SomeClass: @unchecked Sendable {
44-
let number: Int
45-
init() {
46-
self.number = 0
48+
let id: String
49+
init(id: String) {
50+
self.id = id
4751
}
48-
init(number: Int) {
49-
self.number = number
52+
53+
deinit {
54+
print("deinit, id: \(id)")
5055
}
5156
}
5257

@@ -56,21 +61,31 @@ final class SomeClass: @unchecked Sendable {
5661
static func main() async {
5762
_ = try? await withThrowingDiscardingTaskGroup() { group in
5863
group.addTask {
59-
throw Boom()
64+
throw Boom(id: "race-boom-class")
6065
}
6166
group.addTask {
62-
SomeClass() // will be discarded
67+
SomeClass(id: "race-boom-class") // will be discarded
6368
}
69+
// since values may deinit in any order, we just assert their count basically
70+
// CHECK: deinit, id: race-boom-class
71+
// CHECK: deinit, id: race-boom-class
6472

6573
return 12
6674
}
6775

6876
// many ok
6977
_ = try? await withThrowingDiscardingTaskGroup() { group in
70-
for i in 0..<10 {
78+
for i in 0..<6 {
7179
group.addTask {
72-
SomeClass(number: i) // will be discarded
80+
SomeClass(id: "many-ok") // will be discarded
7381
}
82+
// since values may deinit in any order, we just assert their count basically
83+
// CHECK: deinit, id: many-ok
84+
// CHECK: deinit, id: many-ok
85+
// CHECK: deinit, id: many-ok
86+
// CHECK: deinit, id: many-ok
87+
// CHECK: deinit, id: many-ok
88+
// CHECK: deinit, id: many-ok
7489
}
7590

7691
return 12
@@ -79,12 +94,20 @@ final class SomeClass: @unchecked Sendable {
7994
// many throws
8095
do {
8196
let value = try await withThrowingDiscardingTaskGroup() { group in
82-
for i in 0..<10 {
97+
for i in 0..<6 {
8398
group.addTask {
84-
throw BoomClass() // will be rethrown
99+
throw BoomClass(id: "many-error") // will be rethrown
85100
}
86101
}
87102

103+
// since values may deinit in any order, we just assert their count basically
104+
// CHECK: deinit, id: many-error
105+
// CHECK: deinit, id: many-error
106+
// CHECK: deinit, id: many-error
107+
// CHECK: deinit, id: many-error
108+
// CHECK: deinit, id: many-error
109+
// CHECK: deinit, id: many-error
110+
88111
12 // must be ignored
89112
}
90113
preconditionFailure("Should throw")
@@ -95,27 +118,34 @@ final class SomeClass: @unchecked Sendable {
95118
// many errors, many values
96119
_ = try? await withThrowingDiscardingTaskGroup() { group in
97120
group.addTask {
98-
SomeClass() // will be discarded
121+
SomeClass(id: "mixed-ok") // will be discarded
99122
}
100123
group.addTask {
101-
SomeClass() // will be discarded
124+
SomeClass(id: "mixed-ok") // will be discarded
102125
}
103126
group.addTask {
104-
SomeClass() // will be discarded
127+
SomeClass(id: "mixed-ok") // will be discarded
105128
}
106129
group.addTask {
107-
throw Boom()
130+
throw Boom(id: "mixed-error")
108131
}
109132
group.addTask {
110-
throw Boom()
133+
throw Boom(id: "mixed-error")
111134
}
112135
group.addTask {
113-
throw Boom()
114-
}
115-
group.addTask {
116-
throw Boom()
136+
throw Boom(id: "mixed-error")
117137
}
118138

139+
// since values may deinit in any order, we just assert their count basically
140+
// three ok's
141+
// CHECK: deinit, id: mixed
142+
// CHECK: deinit, id: mixed
143+
// CHECK: deinit, id: mixed
144+
// three errors
145+
// CHECK: deinit, id: mixed
146+
// CHECK: deinit, id: mixed
147+
// CHECK: deinit, id: mixed
148+
119149
return 12
120150
}
121151
}

0 commit comments

Comments
 (0)