4990 Self->park(); |
4990 Self->park(); |
4991 } |
4991 } |
4992 } |
4992 } |
4993 } |
4993 } |
4994 |
4994 |
4995 void Thread::muxAcquireW(volatile intptr_t * Lock, ParkEvent * ev) { |
|
4996 intptr_t w = Atomic::cmpxchg(LOCKBIT, Lock, (intptr_t)0); |
|
4997 if (w == 0) return; |
|
4998 if ((w & LOCKBIT) == 0 && Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { |
|
4999 return; |
|
5000 } |
|
5001 |
|
5002 ParkEvent * ReleaseAfter = NULL; |
|
5003 if (ev == NULL) { |
|
5004 ev = ReleaseAfter = ParkEvent::Allocate(NULL); |
|
5005 } |
|
5006 assert((intptr_t(ev) & LOCKBIT) == 0, "invariant"); |
|
5007 for (;;) { |
|
5008 guarantee(ev->OnList == 0, "invariant"); |
|
5009 int its = (os::is_MP() ? 100 : 0) + 1; |
|
5010 |
|
5011 // Optional spin phase: spin-then-park strategy |
|
5012 while (--its >= 0) { |
|
5013 w = *Lock; |
|
5014 if ((w & LOCKBIT) == 0 && Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { |
|
5015 if (ReleaseAfter != NULL) { |
|
5016 ParkEvent::Release(ReleaseAfter); |
|
5017 } |
|
5018 return; |
|
5019 } |
|
5020 } |
|
5021 |
|
5022 ev->reset(); |
|
5023 ev->OnList = intptr_t(Lock); |
|
5024 // The following fence() isn't _strictly necessary as the subsequent |
|
5025 // CAS() both serializes execution and ratifies the fetched *Lock value. |
|
5026 OrderAccess::fence(); |
|
5027 for (;;) { |
|
5028 w = *Lock; |
|
5029 if ((w & LOCKBIT) == 0) { |
|
5030 if (Atomic::cmpxchg(w|LOCKBIT, Lock, w) == w) { |
|
5031 ev->OnList = 0; |
|
5032 // We call ::Release while holding the outer lock, thus |
|
5033 // artificially lengthening the critical section. |
|
5034 // Consider deferring the ::Release() until the subsequent unlock(), |
|
5035 // after we've dropped the outer lock. |
|
5036 if (ReleaseAfter != NULL) { |
|
5037 ParkEvent::Release(ReleaseAfter); |
|
5038 } |
|
5039 return; |
|
5040 } |
|
5041 continue; // Interference -- *Lock changed -- Just retry |
|
5042 } |
|
5043 assert(w & LOCKBIT, "invariant"); |
|
5044 ev->ListNext = (ParkEvent *) (w & ~LOCKBIT); |
|
5045 if (Atomic::cmpxchg(intptr_t(ev)|LOCKBIT, Lock, w) == w) break; |
|
5046 } |
|
5047 |
|
5048 while (ev->OnList != 0) { |
|
5049 ev->park(); |
|
5050 } |
|
5051 } |
|
5052 } |
|
5053 |
|
5054 // Release() must extract a successor from the list and then wake that thread. |
4995 // Release() must extract a successor from the list and then wake that thread. |
5055 // It can "pop" the front of the list or use a detach-modify-reattach (DMR) scheme |
4996 // It can "pop" the front of the list or use a detach-modify-reattach (DMR) scheme |
5056 // similar to that used by ParkEvent::Allocate() and ::Release(). DMR-based |
4997 // similar to that used by ParkEvent::Allocate() and ::Release(). DMR-based |
5057 // Release() would : |
4998 // Release() would : |
5058 // (A) CAS() or swap() null to *Lock, releasing the lock and detaching the list. |
4999 // (A) CAS() or swap() null to *Lock, releasing the lock and detaching the list. |