chirpstack / chirpstack-gateway-bridge

ChirpStack Gateway Bridge abstracts Packet Forwarder protocols into Protobuf or JSON over MQTT.
https://www.chirpstack.io
MIT License
422 stars 270 forks source link

#118 fix read lock netst #119

Closed orientlu closed 5 years ago

orientlu commented 5 years ago

fix read lock nest

orientlu commented 5 years ago

is a bug, i test lorasever project ,found my gateway-bridge will block on handlePackage where try to get the read lock. and i think the block is cause by read lock nest 1.function handlePushData is called by handlePacket which will get the read lock, 2.fucntion handleStats is called by handlePushData and will get the read lock too here, if somewhere get the write lock betwen 1 and 2, will cause deadlock

brocaar commented 5 years ago

I don't believe this should create a deadlock, as there can be multiple read-locks simultaneously (in contrast to a acquiring a write-lock, which will wait until all other read or write locks are released).

However you're right that there is no need to get a new read-lock in the handleStats function.

orientlu commented 5 years ago

I don't believe this should create a deadlock, as there can be multiple read-locks simultaneously (in contrast to a acquiring a write-lock, which will wait until all other read or write locks are released).

However you're right that there is no need to get a new read-lock in the handleStats function.

yes, i totally agree multiple read-locks and acquiring a write-lock which will wait until all other locks are released. but what i mean is this scene: get multiple read-locks in the sam function call. the example show what i mean

package main
import "fmt"
import "sync"
import "time"

var testMutex sync.RWMutex

func main() {
    fmt.Println("start")

    go func() {
        testMutex.RLock()
        defer testMutex.RUnlock()
        fmt.Println("get r lock 1")
        time.Sleep(time.Duration(3) * time.Second) // wait write lock

        fmt.Println("try to get r lock 2")
        // block by write lock
                testMutex.RLock()
        fmt.Println("get r lock 2")
        defer testMutex.RUnlock()
    }()

    go func() {
        time.Sleep(time.Duration(1) * time.Second) 
                // get write lock after one read lock had got
        // block by read lock 1
                fmt.Println("try to get w lock")
        testMutex.Lock()
        defer testMutex.Unlock()
        fmt.Println("get w lock")
    }()

    time.Sleep(time.Duration(20) * time.Second)
    fmt.Println("killed")
}
brocaar commented 5 years ago

Sorry, you're right. When it tries to acquire a write-lock between two read-locks then there is indeed a deadlock. Good catch :+1: