27
27
#include " swift/Basic/Lazy.h"
28
28
#include " swift/Runtime/Config.h"
29
29
#include " swift/Runtime/Debug.h"
30
+ #include " swift/Runtime/EnvironmentVariables.h"
30
31
#include " swift/Runtime/Metadata.h"
31
32
#include " swift/Runtime/ThreadLocalStorage.h"
32
- #include < memory>
33
33
#include < inttypes.h>
34
+ #include < memory>
34
35
#include < stdio.h>
35
36
36
37
// Pick a return-address strategy
@@ -56,6 +57,16 @@ static const char *getAccessName(ExclusivityFlags flags) {
56
57
}
57
58
}
58
59
60
+ // In asserts builds if the environment variable
61
+ // SWIFT_DEBUG_RUNTIME_EXCLUSIVITY_LOGGING is set, emit logging information.
62
+ #ifndef NDEBUG
63
+
64
+ static inline bool isExclusivityLoggingEnabled () {
65
+ return runtime::environment::SWIFT_DEBUG_RUNTIME_EXCLUSIVITY_LOGGING ();
66
+ }
67
+
68
+ #endif
69
+
59
70
SWIFT_ALWAYS_INLINE
60
71
static void reportExclusivityConflict (ExclusivityFlags oldAction, void *oldPC,
61
72
ExclusivityFlags newFlags, void *newPC,
@@ -179,6 +190,10 @@ class AccessSet {
179
190
constexpr bool isHead (Access *access) const { return Head == access; }
180
191
181
192
bool insert (Access *access, void *pc, void *pointer, ExclusivityFlags flags) {
193
+ #ifndef NDEBUG
194
+ if (isExclusivityLoggingEnabled ())
195
+ fprintf (stderr, " Inserting new access: %p\n " , access);
196
+ #endif
182
197
auto action = getAccessAction (flags);
183
198
184
199
for (Access *cur = Head; cur != nullptr ; cur = cur->getNext ()) {
@@ -198,17 +213,33 @@ class AccessSet {
198
213
// 0 means no backtrace will be printed.
199
214
fatalError (0 , " Fatal access conflict detected.\n " );
200
215
}
201
- if (!isTracking (flags))
216
+ if (!isTracking (flags)) {
217
+ #ifndef NDEBUG
218
+ if (isExclusivityLoggingEnabled ()) {
219
+ fprintf (stderr, " Not tracking!\n " );
220
+ }
221
+ #endif
202
222
return false ;
223
+ }
203
224
204
225
// Insert to the front of the array so that remove tends to find it faster.
205
226
access->initialize (pc, pointer, Head, action);
206
227
Head = access;
228
+ #ifndef NDEBUG
229
+ if (isExclusivityLoggingEnabled ()) {
230
+ fprintf (stderr, " Tracking!\n " );
231
+ swift_dumpTrackedAccesses ();
232
+ }
233
+ #endif
207
234
return true ;
208
235
}
209
236
210
237
void remove (Access *access) {
211
238
assert (Head && " removal from empty AccessSet" );
239
+ #ifndef NDEBUG
240
+ if (isExclusivityLoggingEnabled ())
241
+ fprintf (stderr, " Removing access: %p\n " , access);
242
+ #endif
212
243
auto cur = Head;
213
244
// Fast path: stack discipline.
214
245
if (cur == access) {
@@ -419,9 +450,14 @@ char *swift::swift_getOrigOfReplaceable(char **OrigFnPtr) {
419
450
//
420
451
// This is only intended to be used in the debugger.
421
452
void swift::swift_dumpTrackedAccesses () {
422
- getTLSContext ().accessSet .forEach ([](Access *a) {
423
- fprintf (stderr, " Access. Pointer: %p. PC: %p. AccessAction: %s\n " ,
424
- a->Pointer , a->PC , getAccessName (a->getAccessAction ()));
453
+ auto &accessSet = getTLSContext ().accessSet ;
454
+ if (!accessSet) {
455
+ fprintf (stderr, " No Accesses.\n " );
456
+ return ;
457
+ }
458
+ accessSet.forEach ([](Access *a) {
459
+ fprintf (stderr, " Access. Pointer: %p. PC: %p. AccessAction: %s\n " ,
460
+ a->Pointer , a->PC , getAccessName (a->getAccessAction ()));
425
461
});
426
462
}
427
463
@@ -617,6 +653,15 @@ namespace {
617
653
struct SwiftTaskThreadLocalContext {
618
654
uintptr_t state[2 ];
619
655
656
+ #ifndef NDEBUG
657
+ void dump () {
658
+ fprintf (stderr,
659
+ " SwiftTaskThreadLocalContext: (FirstAccess,LastAccess): "
660
+ " (%p, %p)\n " ,
661
+ (void *)state[0 ], (void *)state[1 ]);
662
+ }
663
+ #endif
664
+
620
665
bool hasInitialAccessSet () const {
621
666
// If state[0] is nullptr, we have an initial access set.
622
667
return bool (state[0 ]);
@@ -633,6 +678,25 @@ struct SwiftTaskThreadLocalContext {
633
678
void setTaskAccessSetHead (Access *newHead) { state[0 ] = uintptr_t (newHead); }
634
679
635
680
void setTaskAccessSetTail (Access *newTail) { state[1 ] = uintptr_t (newTail); }
681
+
682
+ #ifndef NDEBUG
683
+ const char *getTaskAddress () const {
684
+ // Constant only used when we have an asserts compiler so that we can output
685
+ // exactly the header location of the task for FileCheck purposes.
686
+ //
687
+ // WARNING: This test will fail if the Task ABI changes. When that happens,
688
+ // update the offset!
689
+ //
690
+ // TODO: This probably will need 32 bit help.
691
+ #if __POINTER_WIDTH__ == 64
692
+ unsigned taskHeadOffsetFromTaskAccessSet = 128 ;
693
+ #else
694
+ unsigned taskHeadOffsetFromTaskAccessSet = 68 ;
695
+ #endif
696
+ auto *self = reinterpret_cast <const char *>(this );
697
+ return self - taskHeadOffsetFromTaskAccessSet;
698
+ }
699
+ #endif
636
700
};
637
701
638
702
} // end anonymous namespace
@@ -642,6 +706,29 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
642
706
auto &taskCtx = *reinterpret_cast <SwiftTaskThreadLocalContext *>(state);
643
707
auto &tlsCtxAccessSet = getTLSContext ().accessSet ;
644
708
709
+ #ifndef NDEBUG
710
+ if (isExclusivityLoggingEnabled ()) {
711
+ fprintf (stderr,
712
+ " Entering Thread Local Context. Before Swizzle. Task: %p\n " ,
713
+ taskCtx.getTaskAddress ());
714
+ taskCtx.dump ();
715
+ swift_dumpTrackedAccesses ();
716
+ }
717
+
718
+ auto logEndState = [&] {
719
+ if (isExclusivityLoggingEnabled ()) {
720
+ fprintf (stderr,
721
+ " Entering Thread Local Context. After Swizzle. Task: %p\n " ,
722
+ taskCtx.getTaskAddress ());
723
+ taskCtx.dump ();
724
+ swift_dumpTrackedAccesses ();
725
+ }
726
+ };
727
+ #else
728
+ // Just a no-op that should inline away.
729
+ auto logEndState = [] {};
730
+ #endif
731
+
645
732
// First handle all of the cases where our task does not start without an
646
733
// initial access set.
647
734
//
@@ -653,6 +740,7 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
653
740
//
654
741
// Handles push cases 1-2.
655
742
if (!tlsCtxAccessSet) {
743
+ logEndState ();
656
744
return ;
657
745
}
658
746
@@ -663,6 +751,7 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
663
751
//
664
752
// Handles push cases 3-4.
665
753
taskCtx.setTaskAccessSetHead (tlsCtxAccessSet.getHead ());
754
+ logEndState ();
666
755
return ;
667
756
}
668
757
@@ -679,6 +768,7 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
679
768
tlsCtxAccessSet = taskCtx.getTaskAccessSetHead ();
680
769
taskCtx.setTaskAccessSetHead (nullptr );
681
770
taskCtx.setTaskAccessSetTail (nullptr );
771
+ logEndState ();
682
772
return ;
683
773
}
684
774
@@ -694,13 +784,40 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
694
784
tail->setNext (oldHead);
695
785
taskCtx.setTaskAccessSetHead (oldHead);
696
786
taskCtx.setTaskAccessSetTail (nullptr );
787
+ logEndState ();
697
788
}
698
789
699
790
// See algorithm description on SwiftTaskThreadLocalContext.
700
791
void swift::swift_task_exitThreadLocalContext (char *state) {
701
792
auto &taskCtx = *reinterpret_cast <SwiftTaskThreadLocalContext *>(state);
702
793
auto &tlsCtxAccessSet = getTLSContext ().accessSet ;
703
794
795
+ #ifndef NDEBUG
796
+ if (isExclusivityLoggingEnabled ()) {
797
+ fprintf (stderr,
798
+ " Exiting Thread Local Context. Before Swizzle. Task: %p\n " ,
799
+ taskCtx.getTaskAddress ());
800
+ taskCtx.dump ();
801
+ swift_dumpTrackedAccesses ();
802
+ }
803
+
804
+ auto logEndState = [&] {
805
+ if (isExclusivityLoggingEnabled ()) {
806
+ fprintf (stderr,
807
+ " Exiting Thread Local Context. After Swizzle. Task: %p\n " ,
808
+ taskCtx.getTaskAddress ());
809
+ taskCtx.dump ();
810
+ swift_dumpTrackedAccesses ();
811
+ }
812
+ };
813
+ #else
814
+ // If we are not compiling with asserts, just use a simple identity function
815
+ // that should be inlined away.
816
+ //
817
+ // TODO: Can we use defer in the runtime?
818
+ auto logEndState = [] {};
819
+ #endif
820
+
704
821
// First check our ctx to see if we were tracking a previous synchronous
705
822
// head. If we don't then we know that our synchronous thread was not
706
823
// initially tracking any accesses.
@@ -719,6 +836,7 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
719
836
if (!tlsCtxAccessSet) {
720
837
assert (taskCtx.getTaskAccessSetTail () == nullptr &&
721
838
" Make sure we set this to nullptr when we pushed" );
839
+ logEndState ();
722
840
return ;
723
841
}
724
842
@@ -735,6 +853,7 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
735
853
tlsCtxAccessSet = nullptr ;
736
854
taskCtx.setTaskAccessSetHead (newHead);
737
855
taskCtx.setTaskAccessSetTail (newTail);
856
+ logEndState ();
738
857
return ;
739
858
}
740
859
@@ -752,6 +871,7 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
752
871
if (tlsCtxAccessSet.getHead () == oldHead) {
753
872
taskCtx.setTaskAccessSetHead (nullptr );
754
873
taskCtx.setTaskAccessSetTail (nullptr );
874
+ logEndState ();
755
875
return ;
756
876
}
757
877
@@ -770,4 +890,5 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
770
890
newEnd->setNext (nullptr );
771
891
taskCtx.setTaskAccessSetHead (newHead);
772
892
taskCtx.setTaskAccessSetTail (newEnd);
893
+ logEndState ();
773
894
}
0 commit comments