Fix race condition in ReadPacket

This commit is contained in:
世界 2025-12-17 19:44:39 +08:00
parent e9e3fbf0c1
commit 6516c2d8f1
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -395,15 +395,16 @@ retry:
func (t *NativeTun) ReadPacket() ([]byte, func(), error) { func (t *NativeTun) ReadPacket() ([]byte, func(), error) {
t.running.Add(1) t.running.Add(1)
defer t.running.Done()
retry: retry:
if t.close.Load() == 1 { if t.close.Load() == 1 {
t.running.Done()
return nil, nil, os.ErrClosed return nil, nil, os.ErrClosed
} }
start := nanotime() start := nanotime()
shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2 shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2
for { for {
if t.close.Load() == 1 { if t.close.Load() == 1 {
t.running.Done()
return nil, nil, os.ErrClosed return nil, nil, os.ErrClosed
} }
packet, err := t.session.ReceivePacket() packet, err := t.session.ReceivePacket()
@ -411,7 +412,10 @@ retry:
case nil: case nil:
packetSize := len(packet) packetSize := len(packet)
t.rate.update(uint64(packetSize)) t.rate.update(uint64(packetSize))
return packet, func() { t.session.ReleaseReceivePacket(packet) }, nil return packet, func() {
t.session.ReleaseReceivePacket(packet)
t.running.Done()
}, nil
case windows.ERROR_NO_MORE_ITEMS: case windows.ERROR_NO_MORE_ITEMS:
if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration { if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration {
windows.WaitForSingleObject(t.readWait, windows.INFINITE) windows.WaitForSingleObject(t.readWait, windows.INFINITE)
@ -420,10 +424,13 @@ retry:
procyield(1) procyield(1)
continue continue
case windows.ERROR_HANDLE_EOF: case windows.ERROR_HANDLE_EOF:
t.running.Done()
return nil, nil, os.ErrClosed return nil, nil, os.ErrClosed
case windows.ERROR_INVALID_DATA: case windows.ERROR_INVALID_DATA:
t.running.Done()
return nil, nil, errors.New("send ring corrupt") return nil, nil, errors.New("send ring corrupt")
} }
t.running.Done()
return nil, nil, fmt.Errorf("read failed: %w", err) return nil, nil, fmt.Errorf("read failed: %w", err)
} }
} }