diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go index aafd6a7010..dc0faf6a60 100644 --- a/src/sync/rwmutex.go +++ b/src/sync/rwmutex.go @@ -66,21 +66,26 @@ func (rw *RWMutex) RUnlock() { race.Disable() } if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { - if r+1 == 0 || r+1 == -rwmutexMaxReaders { - race.Enable() - throw("sync: RUnlock of unlocked RWMutex") - } - // A writer is pending. - if atomic.AddInt32(&rw.readerWait, -1) == 0 { - // The last reader unblocks the writer. - runtime_Semrelease(&rw.writerSem, false, 0) - } + // Outlined slow-path to allow the fast-path to be inlined + rw.rUnlockSlow(r) } if race.Enabled { race.Enable() } } +func (rw *RWMutex) rUnlockSlow(r int32) { + if r+1 == 0 || r+1 == -rwmutexMaxReaders { + race.Enable() + throw("sync: RUnlock of unlocked RWMutex") + } + // A writer is pending. + if atomic.AddInt32(&rw.readerWait, -1) == 0 { + // The last reader unblocks the writer. + runtime_Semrelease(&rw.writerSem, false, 1) + } +} + // Lock locks rw for writing. // If the lock is already locked for reading or writing, // Lock blocks until the lock is available. diff --git a/test/inline_sync.go b/test/inline_sync.go index 3473b92b4a..46ee4c62ed 100644 --- a/test/inline_sync.go +++ b/test/inline_sync.go @@ -38,3 +38,16 @@ func small7() { // ERROR "can inline small7" // the Do fast path should be inlined once.Do(small5) // ERROR "inlining call to sync\.\(\*Once\)\.Do" "&sync\.o\.done escapes to heap" } + +var rwmutex *sync.RWMutex + +func small8() { // ERROR "can inline small8" + // the RUnlock fast path should be inlined + rwmutex.RUnlock() // ERROR "inlining call to sync\.\(\*RWMutex\)\.RUnlock" "&sync\.rw\.readerCount escapes to heap" +} + +func small9() { // ERROR "can inline small9" + // the RLock fast path should be inlined + rwmutex.RLock() // ERROR "inlining call to sync\.\(\*RWMutex\)\.RLock" "&sync\.rw\.readerCount escapes to heap" "&sync\.rw\.readerSem escapes to heap" +} +