fix data input and output signal

pull/314/head
Darien Raymond 8 years ago
parent 40249dfacb
commit 41fcffbfab
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169

@ -168,15 +168,15 @@ type SystemConnection interface {
// Connection is a KCP connection over UDP. // Connection is a KCP connection over UDP.
type Connection struct { type Connection struct {
conn SystemConnection conn SystemConnection
connRecycler internal.ConnectionRecyler connRecycler internal.ConnectionRecyler
block internet.Authenticator block internet.Authenticator
rd time.Time rd time.Time
wd time.Time // write deadline wd time.Time // write deadline
since int64 since int64
dataInputCond *sync.Cond dataInput chan bool
dataOutputCond *sync.Cond dataOutput chan bool
Config *Config Config *Config
conv uint16 conv uint16
state State state State
@ -203,15 +203,15 @@ func NewConnection(conv uint16, sysConn SystemConnection, recycler internal.Conn
log.Info("KCP|Connection: creating connection ", conv) log.Info("KCP|Connection: creating connection ", conv)
conn := &Connection{ conn := &Connection{
conv: conv, conv: conv,
conn: sysConn, conn: sysConn,
connRecycler: recycler, connRecycler: recycler,
since: nowMillisec(), since: nowMillisec(),
dataInputCond: sync.NewCond(new(sync.Mutex)), dataInput: make(chan bool, 1),
dataOutputCond: sync.NewCond(new(sync.Mutex)), dataOutput: make(chan bool, 1),
Config: config, Config: config,
output: NewSegmentWriter(sysConn, config.GetMtu().GetValue()-uint32(sysConn.Overhead())), output: NewSegmentWriter(sysConn, config.GetMtu().GetValue()-uint32(sysConn.Overhead())),
mss: config.GetMtu().GetValue() - uint32(sysConn.Overhead()) - DataSegmentOverhead, mss: config.GetMtu().GetValue() - uint32(sysConn.Overhead()) - DataSegmentOverhead,
roundTrip: &RoundTripInfo{ roundTrip: &RoundTripInfo{
rto: 100, rto: 100,
minRtt: config.Tti.GetValue(), minRtt: config.Tti.GetValue(),
@ -247,6 +247,20 @@ func (v *Connection) Elapsed() uint32 {
return uint32(nowMillisec() - v.since) return uint32(nowMillisec() - v.since)
} }
func (v *Connection) OnDataInput() {
select {
case v.dataInput <- true:
default:
}
}
func (v *Connection) OnDataOutput() {
select {
case v.dataOutput <- true:
default:
}
}
// Read implements the Conn Read method. // Read implements the Conn Read method.
func (v *Connection) Read(b []byte) (int, error) { func (v *Connection) Read(b []byte) (int, error) {
if v == nil { if v == nil {
@ -266,22 +280,20 @@ func (v *Connection) Read(b []byte) (int, error) {
return 0, io.EOF return 0, io.EOF
} }
var timer *time.Timer duration := time.Duration(time.Minute)
if !v.rd.IsZero() { if !v.rd.IsZero() {
duration := v.rd.Sub(time.Now()) duration = v.rd.Sub(time.Now())
if duration <= 0 { if duration < 0 {
return 0, ErrIOTimeout return 0, ErrIOTimeout
} }
timer = time.AfterFunc(duration, v.dataInputCond.Signal)
}
v.dataInputCond.L.Lock()
v.dataInputCond.Wait()
v.dataInputCond.L.Unlock()
if timer != nil {
timer.Stop()
} }
if !v.rd.IsZero() && v.rd.Before(time.Now()) {
return 0, ErrIOTimeout select {
case <-v.dataInput:
case <-time.After(duration):
if !v.rd.IsZero() && v.rd.Before(time.Now()) {
return 0, ErrIOTimeout
}
} }
} }
} }
@ -304,24 +316,20 @@ func (v *Connection) Write(b []byte) (int, error) {
} }
} }
var timer *time.Timer duration := time.Duration(time.Minute)
if !v.wd.IsZero() { if !v.rd.IsZero() {
duration := v.wd.Sub(time.Now()) duration = v.wd.Sub(time.Now())
if duration <= 0 { if duration < 0 {
return totalWritten, ErrIOTimeout return totalWritten, ErrIOTimeout
} }
timer = time.AfterFunc(duration, v.dataOutputCond.Signal)
}
v.dataOutputCond.L.Lock()
v.dataOutputCond.Wait()
v.dataOutputCond.L.Unlock()
if timer != nil {
timer.Stop()
} }
if !v.wd.IsZero() && v.wd.Before(time.Now()) { select {
return totalWritten, ErrIOTimeout case <-v.dataOutput:
case <-time.After(duration):
if !v.wd.IsZero() && v.wd.Before(time.Now()) {
return totalWritten, ErrIOTimeout
}
} }
} }
} }
@ -360,8 +368,8 @@ func (v *Connection) Close() error {
return ErrClosedConnection return ErrClosedConnection
} }
v.dataInputCond.Broadcast() v.OnDataInput()
v.dataOutputCond.Broadcast() v.OnDataOutput()
state := v.State() state := v.State()
if state.Is(StateReadyToClose, StateTerminating, StateTerminated) { if state.Is(StateReadyToClose, StateTerminating, StateTerminated) {
@ -447,8 +455,9 @@ func (v *Connection) Terminate() {
log.Info("KCP|Connection: Terminating connection to ", v.RemoteAddr()) log.Info("KCP|Connection: Terminating connection to ", v.RemoteAddr())
//v.SetState(StateTerminated) //v.SetState(StateTerminated)
v.dataInputCond.Broadcast() v.OnDataInput()
v.dataOutputCond.Broadcast() v.OnDataOutput()
if v.Config.ConnectionReuse.IsEnabled() && v.reusable { if v.Config.ConnectionReuse.IsEnabled() && v.reusable {
v.connRecycler.Put(v.conn.Id(), v.conn) v.connRecycler.Put(v.conn.Id(), v.conn)
} else { } else {
@ -481,19 +490,21 @@ func (v *Connection) Input(segments []Segment) {
for _, seg := range segments { for _, seg := range segments {
if seg.Conversation() != v.conv { if seg.Conversation() != v.conv {
return break
} }
switch seg := seg.(type) { switch seg := seg.(type) {
case *DataSegment: case *DataSegment:
v.HandleOption(seg.Option) v.HandleOption(seg.Option)
v.receivingWorker.ProcessSegment(seg) v.receivingWorker.ProcessSegment(seg)
v.dataInputCond.Signal() if seg.Number == v.receivingWorker.nextNumber {
v.OnDataInput()
}
v.dataUpdater.WakeUp() v.dataUpdater.WakeUp()
case *AckSegment: case *AckSegment:
v.HandleOption(seg.Option) v.HandleOption(seg.Option)
v.sendingWorker.ProcessSegment(current, seg, v.roundTrip.Timeout()) v.sendingWorker.ProcessSegment(current, seg, v.roundTrip.Timeout())
v.dataOutputCond.Signal() v.OnDataOutput()
v.dataUpdater.WakeUp() v.dataUpdater.WakeUp()
case *CmdOnlySegment: case *CmdOnlySegment:
v.HandleOption(seg.Option) v.HandleOption(seg.Option)

Loading…
Cancel
Save