Skip to content

Commit 86fc41a

Browse files
committed
[Runtime] Fix ConcurrentReadableArray's handling of FreeList to not double-free items. Also implement a destructor so it can be used for non-globals.
rdar://problem/40484362
1 parent 733f425 commit 86fc41a

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

include/swift/Runtime/Concurrent.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,13 @@ template <class ElemTy> struct ConcurrentReadableArray {
458458
ReaderCount.fetch_sub(1, std::memory_order_release);
459459
}
460460

461+
void deallocateFreeList() {
462+
for (Storage *storage : FreeList)
463+
storage->deallocate();
464+
FreeList.clear();
465+
FreeList.shrink_to_fit();
466+
}
467+
461468
public:
462469
struct Snapshot {
463470
ConcurrentReadableArray *Array;
@@ -488,6 +495,12 @@ template <class ElemTy> struct ConcurrentReadableArray {
488495

489496
ConcurrentReadableArray() : Capacity(0), ReaderCount(0), Elements(nullptr) {}
490497

498+
~ConcurrentReadableArray() {
499+
assert(ReaderCount.load(std::memory_order_acquire) == 0 &&
500+
"deallocating ConcurrentReadableArray with outstanding snapshots");
501+
deallocateFreeList();
502+
}
503+
491504
void push_back(const ElemTy &elem) {
492505
ScopedLock guard(WriterLock);
493506

@@ -511,8 +524,7 @@ template <class ElemTy> struct ConcurrentReadableArray {
511524
storage->Count.store(count + 1, std::memory_order_release);
512525

513526
if (ReaderCount.load(std::memory_order_acquire) == 0)
514-
for (Storage *storage : FreeList)
515-
storage->deallocate();
527+
deallocateFreeList();
516528
}
517529

518530
Snapshot snapshot() {

unittests/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND
3434
add_swift_unittest(SwiftRuntimeTests
3535
Array.cpp
3636
CompatibilityOverride.cpp
37+
Concurrent.cpp
3738
Exclusivity.cpp
3839
Metadata.cpp
3940
Mutex.cpp

unittests/runtime/Concurrent.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===--- Concurrent.cpp - Concurrent data structure tests -----------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Runtime/Concurrent.h"
14+
#include "gtest/gtest.h"
15+
16+
using namespace swift;
17+
18+
TEST(ConcurrentReadableArrayTest, SingleThreaded) {
19+
ConcurrentReadableArray<size_t> array;
20+
21+
auto add = [&](size_t limit) {
22+
for (size_t i = array.snapshot().count(); i < limit; i++)
23+
array.push_back(i);
24+
};
25+
auto check = [&]{
26+
size_t i = 0;
27+
for (auto element : array.snapshot()) {
28+
ASSERT_EQ(element, i);
29+
i++;
30+
}
31+
};
32+
33+
check();
34+
add(1);
35+
check();
36+
add(16);
37+
check();
38+
add(100);
39+
check();
40+
add(1000);
41+
check();
42+
add(1000000);
43+
check();
44+
}

0 commit comments

Comments
 (0)