Skip to content

Commit ea23988

Browse files
authored
Merge pull request #36802 from mikeash/concurrentreadablearray-operator-new-delete
2 parents 6c47454 + 70354af commit ea23988

File tree

3 files changed

+50
-57
lines changed

3 files changed

+50
-57
lines changed

include/swift/Runtime/Concurrent.h

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,35 @@ class ConcurrentMap
416416
}
417417
};
418418

419+
/// A simple linked list representing pointers that need to be freed. This is
420+
/// not a concurrent data structure, just a bit of support used in the types
421+
/// below.
422+
struct ConcurrentFreeListNode {
423+
ConcurrentFreeListNode *Next;
424+
void *Ptr;
425+
426+
static void add(ConcurrentFreeListNode **head, void *ptr) {
427+
auto *newNode = reinterpret_cast<ConcurrentFreeListNode *>(
428+
malloc(sizeof(ConcurrentFreeListNode)));
429+
newNode->Next = *head;
430+
newNode->Ptr = ptr;
431+
*head = newNode;
432+
}
433+
434+
/// Free all nodes in the free list, resetting `head` to `NULL`. Calls
435+
/// `FreeFn` on the Ptr field of every node.
436+
template <typename FreeFn>
437+
static void freeAll(ConcurrentFreeListNode **head, const FreeFn &freeFn) {
438+
auto *node = *head;
439+
while (node) {
440+
auto *next = node->Next;
441+
freeFn(node->Ptr);
442+
free(node);
443+
node = next;
444+
}
445+
*head = nullptr;
446+
}
447+
};
419448

420449
/// An append-only array that can be read without taking locks. Writes
421450
/// are still locked and serialized, but only with respect to other
@@ -454,8 +483,8 @@ template <class ElemTy> struct ConcurrentReadableArray {
454483
std::atomic<size_t> ReaderCount;
455484
std::atomic<Storage *> Elements;
456485
Mutex WriterLock;
457-
std::vector<Storage *> FreeList;
458-
486+
ConcurrentFreeListNode *FreeList{nullptr};
487+
459488
void incrementReaders() {
460489
ReaderCount.fetch_add(1, std::memory_order_acquire);
461490
}
@@ -465,10 +494,9 @@ template <class ElemTy> struct ConcurrentReadableArray {
465494
}
466495

467496
void deallocateFreeList() {
468-
for (Storage *storage : FreeList)
469-
storage->deallocate();
470-
FreeList.clear();
471-
FreeList.shrink_to_fit();
497+
ConcurrentFreeListNode::freeAll(&FreeList, [](void *ptr) {
498+
reinterpret_cast<Storage *>(ptr)->deallocate();
499+
});
472500
}
473501

474502
public:
@@ -522,7 +550,7 @@ template <class ElemTy> struct ConcurrentReadableArray {
522550
if (storage) {
523551
std::copy(storage->data(), storage->data() + count, newStorage->data());
524552
newStorage->Count.store(count, std::memory_order_release);
525-
FreeList.push_back(storage);
553+
ConcurrentFreeListNode::add(&FreeList, storage);
526554
}
527555

528556
storage = newStorage;
@@ -797,28 +825,6 @@ struct ConcurrentReadableHashMap {
797825
ElemTy *data() { return &Elem; }
798826
};
799827

800-
/// A simple linked list representing pointers that need to be freed.
801-
struct FreeListNode {
802-
FreeListNode *Next;
803-
void *Ptr;
804-
805-
static void add(FreeListNode **head, void *ptr) {
806-
auto *newNode = new FreeListNode{*head, ptr};
807-
*head = newNode;
808-
}
809-
810-
static void freeAll(FreeListNode **head) {
811-
auto *node = *head;
812-
while (node) {
813-
auto *next = node->Next;
814-
free(node->Ptr);
815-
delete node;
816-
node = next;
817-
}
818-
*head = nullptr;
819-
}
820-
};
821-
822828
/// The number of readers currently active, equal to the number of snapshot
823829
/// objects currently alive.
824830
std::atomic<uint32_t> ReaderCount{0};
@@ -840,7 +846,7 @@ struct ConcurrentReadableHashMap {
840846
MutexTy WriterLock;
841847

842848
/// The list of pointers to be freed once no readers are active.
843-
FreeListNode *FreeList{nullptr};
849+
ConcurrentFreeListNode *FreeList{nullptr};
844850

845851
void incrementReaders() {
846852
ReaderCount.fetch_add(1, std::memory_order_acquire);
@@ -854,7 +860,7 @@ struct ConcurrentReadableHashMap {
854860
/// there are active readers, do nothing.
855861
void deallocateFreeListIfSafe() {
856862
if (ReaderCount.load(std::memory_order_seq_cst) == 0)
857-
FreeListNode::freeAll(&FreeList);
863+
ConcurrentFreeListNode::freeAll(&FreeList, free);
858864
}
859865

860866
/// Grow the elements array, adding the old array to the free list and
@@ -868,7 +874,7 @@ struct ConcurrentReadableHashMap {
868874
if (elements) {
869875
memcpy(newElements->data(), elements->data(),
870876
elementCount * sizeof(ElemTy));
871-
FreeListNode::add(&FreeList, elements);
877+
ConcurrentFreeListNode::add(&FreeList, elements);
872878
}
873879

874880
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
@@ -916,7 +922,7 @@ struct ConcurrentReadableHashMap {
916922
Indices.store(newIndices.Value, std::memory_order_seq_cst);
917923

918924
if (auto *ptr = indices.pointer())
919-
FreeListNode::add(&FreeList, ptr);
925+
ConcurrentFreeListNode::add(&FreeList, ptr);
920926

921927
return newIndices;
922928
}
@@ -1122,8 +1128,8 @@ struct ConcurrentReadableHashMap {
11221128
Elements.store(nullptr, std::memory_order_relaxed);
11231129

11241130
if (auto *ptr = indices.pointer())
1125-
FreeListNode::add(&FreeList, ptr);
1126-
FreeListNode::add(&FreeList, elements);
1131+
ConcurrentFreeListNode::add(&FreeList, ptr);
1132+
ConcurrentFreeListNode::add(&FreeList, elements);
11271133

11281134
deallocateFreeListIfSafe();
11291135
}

stdlib/public/runtime/ImageInspectionMachO.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ void addImageCallback2Sections(const mach_header *mh, intptr_t vmaddr_slide) {
129129
#define REGISTER_FUNC(...) _dyld_register_func_for_add_image(__VA_ARGS__)
130130
#endif
131131

132+
// WARNING: the callbacks are called from unsafe contexts (with the dyld and
133+
// ObjC runtime locks held) and must be very careful in what they do. Locking
134+
// must be arranged to avoid deadlocks (other code must never call out to dyld
135+
// or ObjC holding a lock that gets taken in one of these callbacks) and the
136+
// new/delete operators must not be called, in case a program supplies an
137+
// overload which does not cooperate with these requirements.
138+
132139
void swift::initializeProtocolLookup() {
133140
REGISTER_FUNC(addImageCallback<TextSegment, ProtocolsSection,
134141
addImageProtocolsBlockCallbackUnsafe>);

test/stdlib/symbol-visibility-linux.test-sh

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,7 @@
2323
// RUN: -e _ZN9__gnu_cxx12__to_xstringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEET_PFiPT0_mPKS8_P13__va_list_tagEmSB_z \
2424
// RUN: -e _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag \
2525
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEDnEEEvv \
26-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA1_cEEEvv \
27-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA8_cEEEvv \
28-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA24_cEEEvv \
29-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA32_cEEEvv \
30-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA40_cEEEvv \
31-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \
32-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \
33-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \
34-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA160_cEEEvv \
35-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \
36-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \
26+
// RUN: -e '_ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA[0-9]\+_cEEEvv' \
3727
// RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \
3828
// RUN: -e _ZZNSt8__detail18__to_chars_10_implIjEEvPcjT_E8__digits \
3929
// RUN: -e _ZZNSt8__detail18__to_chars_10_implImEEvPcjT_E8__digits \
@@ -51,17 +41,7 @@
5141
// RUN: -e _ZN9__gnu_cxx12__to_xstringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEET_PFiPT0_mPKS8_P13__va_list_tagEmSB_z \
5242
// RUN: -e _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag \
5343
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEDnEEEvv \
54-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA1_cEEEvv \
55-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA8_cEEEvv \
56-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA24_cEEEvv \
57-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA32_cEEEvv \
58-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA40_cEEEvv \
59-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \
60-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \
61-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \
62-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA160_cEEEvv \
63-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA168_cEEEvv \
64-
// RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA216_cEEEvv \
44+
// RUN: -e '_ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA[0-9]\+_cEEEvv' \
6545
// RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \
6646
// RUN: -e _ZZNSt8__detail18__to_chars_10_implIjEEvPcjT_E8__digits \
6747
// RUN: -e _ZZNSt8__detail18__to_chars_10_implImEEvPcjT_E8__digits \

0 commit comments

Comments
 (0)