File tree Expand file tree Collapse file tree 2 files changed +65
-3
lines changed
Expand file tree Collapse file tree 2 files changed +65
-3
lines changed Original file line number Diff line number Diff line change @@ -1146,9 +1146,15 @@ struct StableAddressConcurrentReadableHashMap
11461146 return {lastFound, false };
11471147
11481148 // Optimize for the case where the value already exists.
1149- if (auto wrapper = this ->snapshot ().find (key)) {
1150- LastFound.store (wrapper->Ptr , std::memory_order_relaxed);
1151- return {wrapper->Ptr , false };
1149+ {
1150+ // Tightly scope the snapshot so it's gone before we call getOrInsert
1151+ // below, otherwise that call will always see an outstanding snapshot and
1152+ // never be able to collect garbage.
1153+ auto snapshot = this ->snapshot ();
1154+ if (auto wrapper = snapshot.find (key)) {
1155+ LastFound.store (wrapper->Ptr , std::memory_order_relaxed);
1156+ return {wrapper->Ptr , false };
1157+ }
11521158 }
11531159
11541160 // No such element. Insert if needed. Note: another thread may have inserted
Original file line number Diff line number Diff line change 1+ // RUN: %target-run-simple-swift
2+ // REQUIRES: executable_test
3+
4+ // Exercise the metadata cache from multiple threads to shake out any
5+ // concurrency bugs.
6+
7+ import StdlibUnittest
8+
9+ import SwiftPrivateThreadExtras
10+
11+ struct One { }
12+ struct Two { }
13+
14+ struct Cat < T, U> { }
15+
16+ protocol Growable { }
17+ extension Growable {
18+ func grow( ) -> ( Growable , Growable ) {
19+ return ( Cat < Self , One > ( ) , Cat < Self , Two > ( ) )
20+ }
21+ }
22+
23+ extension One : Growable { }
24+ extension Two : Growable { }
25+ extension Cat : Growable { }
26+
27+ var ConcurrentMetadataTestSuite = TestSuite ( " ConcurrentMetadata " )
28+
29+ ConcurrentMetadataTestSuite . test ( " ConcurrentMetadata " ) {
30+ let threadCount = 16
31+ let iterationCount = 10000
32+
33+ func threadFunc( ) {
34+ var array : [ Growable ] = [ One ( ) , Two ( ) ]
35+ for i in 0 ..< iterationCount {
36+ // Each call to grow() creates a new generic metadata specialization which
37+ // will race with creating that same metadata on the other threads.
38+ let ( a, b) = array [ i] . grow ( )
39+ array. append ( a)
40+ array. append ( b)
41+ }
42+ }
43+
44+ let threadIDs = ( 0 ..< 16 ) . map { _ -> ThreadHandle in
45+ let ( ret, threadID) = _stdlib_thread_create_block ( threadFunc, ( ) )
46+ expectEqual ( 0 , ret)
47+ return threadID!
48+ }
49+
50+ for threadID in threadIDs {
51+ let ( ret, _) = _stdlib_thread_join ( threadID, Void . self)
52+ expectEqual ( 0 , ret)
53+ }
54+ }
55+
56+ runAllTests ( )
You can’t perform that action at this time.
0 commit comments