2727#include " swift/Basic/Lazy.h"
2828#include " swift/Runtime/Config.h"
2929#include " swift/Runtime/Debug.h"
30+ #include " swift/Runtime/EnvironmentVariables.h"
3031#include " swift/Runtime/Metadata.h"
3132#include " swift/Runtime/ThreadLocalStorage.h"
32- #include < memory>
3333#include < inttypes.h>
34+ #include < memory>
3435#include < stdio.h>
3536
3637// Pick a return-address strategy
@@ -56,6 +57,16 @@ static const char *getAccessName(ExclusivityFlags flags) {
5657 }
5758}
5859
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+
5970SWIFT_ALWAYS_INLINE
6071static void reportExclusivityConflict (ExclusivityFlags oldAction, void *oldPC,
6172 ExclusivityFlags newFlags, void *newPC,
@@ -179,6 +190,10 @@ class AccessSet {
179190 constexpr bool isHead (Access *access) const { return Head == access; }
180191
181192 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
182197 auto action = getAccessAction (flags);
183198
184199 for (Access *cur = Head; cur != nullptr ; cur = cur->getNext ()) {
@@ -198,17 +213,33 @@ class AccessSet {
198213 // 0 means no backtrace will be printed.
199214 fatalError (0 , " Fatal access conflict detected.\n " );
200215 }
201- if (!isTracking (flags))
216+ if (!isTracking (flags)) {
217+ #ifndef NDEBUG
218+ if (isExclusivityLoggingEnabled ()) {
219+ fprintf (stderr, " Not tracking!\n " );
220+ }
221+ #endif
202222 return false ;
223+ }
203224
204225 // Insert to the front of the array so that remove tends to find it faster.
205226 access->initialize (pc, pointer, Head, action);
206227 Head = access;
228+ #ifndef NDEBUG
229+ if (isExclusivityLoggingEnabled ()) {
230+ fprintf (stderr, " Tracking!\n " );
231+ swift_dumpTrackedAccesses ();
232+ }
233+ #endif
207234 return true ;
208235 }
209236
210237 void remove (Access *access) {
211238 assert (Head && " removal from empty AccessSet" );
239+ #ifndef NDEBUG
240+ if (isExclusivityLoggingEnabled ())
241+ fprintf (stderr, " Removing access: %p\n " , access);
242+ #endif
212243 auto cur = Head;
213244 // Fast path: stack discipline.
214245 if (cur == access) {
@@ -419,9 +450,14 @@ char *swift::swift_getOrigOfReplaceable(char **OrigFnPtr) {
419450//
420451// This is only intended to be used in the debugger.
421452void 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 ()));
425461 });
426462}
427463
@@ -617,6 +653,15 @@ namespace {
617653struct SwiftTaskThreadLocalContext {
618654 uintptr_t state[2 ];
619655
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+
620665 bool hasInitialAccessSet () const {
621666 // If state[0] is nullptr, we have an initial access set.
622667 return bool (state[0 ]);
@@ -633,6 +678,25 @@ struct SwiftTaskThreadLocalContext {
633678 void setTaskAccessSetHead (Access *newHead) { state[0 ] = uintptr_t (newHead); }
634679
635680 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
636700};
637701
638702} // end anonymous namespace
@@ -642,6 +706,29 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
642706 auto &taskCtx = *reinterpret_cast <SwiftTaskThreadLocalContext *>(state);
643707 auto &tlsCtxAccessSet = getTLSContext ().accessSet ;
644708
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+
645732 // First handle all of the cases where our task does not start without an
646733 // initial access set.
647734 //
@@ -653,6 +740,7 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
653740 //
654741 // Handles push cases 1-2.
655742 if (!tlsCtxAccessSet) {
743+ logEndState ();
656744 return ;
657745 }
658746
@@ -663,6 +751,7 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
663751 //
664752 // Handles push cases 3-4.
665753 taskCtx.setTaskAccessSetHead (tlsCtxAccessSet.getHead ());
754+ logEndState ();
666755 return ;
667756 }
668757
@@ -679,6 +768,7 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
679768 tlsCtxAccessSet = taskCtx.getTaskAccessSetHead ();
680769 taskCtx.setTaskAccessSetHead (nullptr );
681770 taskCtx.setTaskAccessSetTail (nullptr );
771+ logEndState ();
682772 return ;
683773 }
684774
@@ -694,13 +784,40 @@ void swift::swift_task_enterThreadLocalContext(char *state) {
694784 tail->setNext (oldHead);
695785 taskCtx.setTaskAccessSetHead (oldHead);
696786 taskCtx.setTaskAccessSetTail (nullptr );
787+ logEndState ();
697788}
698789
699790// See algorithm description on SwiftTaskThreadLocalContext.
700791void swift::swift_task_exitThreadLocalContext (char *state) {
701792 auto &taskCtx = *reinterpret_cast <SwiftTaskThreadLocalContext *>(state);
702793 auto &tlsCtxAccessSet = getTLSContext ().accessSet ;
703794
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+
704821 // First check our ctx to see if we were tracking a previous synchronous
705822 // head. If we don't then we know that our synchronous thread was not
706823 // initially tracking any accesses.
@@ -719,6 +836,7 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
719836 if (!tlsCtxAccessSet) {
720837 assert (taskCtx.getTaskAccessSetTail () == nullptr &&
721838 " Make sure we set this to nullptr when we pushed" );
839+ logEndState ();
722840 return ;
723841 }
724842
@@ -735,6 +853,7 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
735853 tlsCtxAccessSet = nullptr ;
736854 taskCtx.setTaskAccessSetHead (newHead);
737855 taskCtx.setTaskAccessSetTail (newTail);
856+ logEndState ();
738857 return ;
739858 }
740859
@@ -752,6 +871,7 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
752871 if (tlsCtxAccessSet.getHead () == oldHead) {
753872 taskCtx.setTaskAccessSetHead (nullptr );
754873 taskCtx.setTaskAccessSetTail (nullptr );
874+ logEndState ();
755875 return ;
756876 }
757877
@@ -770,4 +890,5 @@ void swift::swift_task_exitThreadLocalContext(char *state) {
770890 newEnd->setNext (nullptr );
771891 taskCtx.setTaskAccessSetHead (newHead);
772892 taskCtx.setTaskAccessSetTail (newEnd);
893+ logEndState ();
773894}
0 commit comments