mirror of
https://github.com/mochi-mqtt/server.git
synced 2025-11-01 12:02:44 +08:00
Fixes sync.cond deadlock
This commit is contained in:
@@ -81,12 +81,25 @@ func (b *buffer) Close() {
|
|||||||
atomic.StoreInt64(&b.done, 1)
|
atomic.StoreInt64(&b.done, 1)
|
||||||
debug.Println(b.id, "[B] STORE done=1 buffer closing")
|
debug.Println(b.id, "[B] STORE done=1 buffer closing")
|
||||||
|
|
||||||
|
debug.Println(b.id, "##### [X] wcond.Locking")
|
||||||
b.wcond.L.Lock()
|
b.wcond.L.Lock()
|
||||||
|
debug.Println(b.id, "##### [X] wcond.Locked")
|
||||||
|
debug.Println(b.id, "##### [X] wcond.Broadcasting")
|
||||||
b.wcond.Broadcast()
|
b.wcond.Broadcast()
|
||||||
|
debug.Println(b.id, "##### [X] wcond.Broadcasted")
|
||||||
|
debug.Println(b.id, "##### [X] wcond.Unlocking")
|
||||||
b.wcond.L.Unlock()
|
b.wcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### [X] wcond.Unlocked")
|
||||||
|
|
||||||
|
debug.Println(b.id, "##### [Y] rcond.Locking")
|
||||||
b.rcond.L.Lock()
|
b.rcond.L.Lock()
|
||||||
|
debug.Println(b.id, "##### [Y] rcond.Locked")
|
||||||
|
debug.Println(b.id, "##### [Y] rcond.Broadcasting")
|
||||||
b.rcond.Broadcast()
|
b.rcond.Broadcast()
|
||||||
|
debug.Println(b.id, "##### [Y] rcond.Broadcasted")
|
||||||
|
debug.Println(b.id, "##### [Y] rcond.Unlocking")
|
||||||
b.rcond.L.Unlock()
|
b.rcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### [Y] rcond.Unlocked")
|
||||||
|
|
||||||
debug.Println(b.id, "[B] DONE REBROADCASTED")
|
debug.Println(b.id, "[B] DONE REBROADCASTED")
|
||||||
}
|
}
|
||||||
@@ -118,22 +131,32 @@ func (b *buffer) awaitCapacity(n int64) (head int64, err error) {
|
|||||||
head = atomic.LoadInt64(&b.head)
|
head = atomic.LoadInt64(&b.head)
|
||||||
next := head + n
|
next := head + n
|
||||||
wrapped := next - b.size
|
wrapped := next - b.size
|
||||||
tail := atomic.LoadInt64(&b.tail)
|
//tail := atomic.LoadInt64(&b.tail)
|
||||||
|
var tail int64
|
||||||
|
|
||||||
debug.Println(b.id, "[B] awaiting capacity (n)", n)
|
debug.Println(b.id, "[B] awaiting capacity (n)", n)
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Locking")
|
||||||
b.rcond.L.Lock()
|
b.rcond.L.Lock()
|
||||||
for ; wrapped > tail || (tail > head && next > tail && wrapped < 0); tail = atomic.LoadInt64(&b.tail) {
|
debug.Println(b.id, "##### [B] rcond.Locked")
|
||||||
|
for tail = atomic.LoadInt64(&b.tail); wrapped > tail || (tail > head && next > tail && wrapped < 0); tail = atomic.LoadInt64(&b.tail) {
|
||||||
debug.Println(b.id, "[B] iter no capacity")
|
debug.Println(b.id, "[B] iter no capacity")
|
||||||
|
|
||||||
//fmt.Println("\t", wrapped, ">", tail, wrapped > tail, "||", tail, ">", head, "&&", next, ">", tail, "&&", wrapped, "<", 0, (tail > head && next > tail && wrapped < 0))
|
//fmt.Println("\t", wrapped, ">", tail, wrapped > tail, "||", tail, ">", head, "&&", next, ">", tail, "&&", wrapped, "<", 0, (tail > head && next > tail && wrapped < 0))
|
||||||
if atomic.LoadInt64(&b.done) == 1 {
|
if atomic.LoadInt64(&b.done) == 1 {
|
||||||
|
debug.Println(b.id, "************ [B] awaitCap caught DONE")
|
||||||
|
b.rcond.L.Unlock() // Make sure we unlock
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Println(b.id, "[B] iter no capacity waiting")
|
debug.Println(b.id, "[B] iter no capacity waiting")
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Wating")
|
||||||
b.rcond.Wait()
|
b.rcond.Wait()
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Waited")
|
||||||
}
|
}
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Unlocked")
|
||||||
b.rcond.L.Unlock()
|
b.rcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Unlocked")
|
||||||
|
|
||||||
debug.Println(b.id, "[B] capacity unlocked (tail)", tail)
|
debug.Println(b.id, "[B] capacity unlocked (tail)", tail)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -142,22 +165,31 @@ func (b *buffer) awaitCapacity(n int64) (head int64, err error) {
|
|||||||
// awaitFilled will hold until there are at least n bytes waiting between the
|
// awaitFilled will hold until there are at least n bytes waiting between the
|
||||||
// tail and head.
|
// tail and head.
|
||||||
func (b *buffer) awaitFilled(n int64) (tail int64, err error) {
|
func (b *buffer) awaitFilled(n int64) (tail int64, err error) {
|
||||||
head := atomic.LoadInt64(&b.head)
|
//head := atomic.LoadInt64(&b.head)
|
||||||
|
var head int64
|
||||||
tail = atomic.LoadInt64(&b.tail)
|
tail = atomic.LoadInt64(&b.tail)
|
||||||
|
|
||||||
debug.Println(b.id, "[B] awaiting filled (tail, head)", tail, head)
|
debug.Println(b.id, "[B] awaiting filled (tail, head)", tail, head)
|
||||||
|
debug.Println(b.id, "##### [B] wcond.Locking")
|
||||||
b.wcond.L.Lock()
|
b.wcond.L.Lock()
|
||||||
for ; head > tail && tail+n > head || head < tail && b.size-tail+head < n; head = atomic.LoadInt64(&b.head) {
|
debug.Println(b.id, "##### [B] rcond.Locked")
|
||||||
|
for head = atomic.LoadInt64(&b.head); head > tail && tail+n > head || head < tail && b.size-tail+head < n; head = atomic.LoadInt64(&b.head) {
|
||||||
debug.Println(b.id, "[B] iter no fill")
|
debug.Println(b.id, "[B] iter no fill")
|
||||||
|
|
||||||
if atomic.LoadInt64(&b.done) == 1 {
|
if atomic.LoadInt64(&b.done) == 1 {
|
||||||
|
debug.Println(b.id, "************ [B] awaitFilled caught DONE")
|
||||||
|
b.wcond.L.Unlock() // Make sure we unlock
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Println(b.id, "[B] iter no fill waiting")
|
debug.Println(b.id, "[B] iter no fill waiting")
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Waiting")
|
||||||
b.wcond.Wait()
|
b.wcond.Wait()
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Waited")
|
||||||
}
|
}
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Unlocking")
|
||||||
b.wcond.L.Unlock()
|
b.wcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### [B] rcond.Unlocked")
|
||||||
debug.Println(b.id, "[B] filled (head)", head)
|
debug.Println(b.id, "[B] filled (head)", head)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -62,15 +62,24 @@ DONE:
|
|||||||
n, err := r.Read(b.buf[start:end])
|
n, err := r.Read(b.buf[start:end])
|
||||||
total += int64(n) // incr total bytes read.
|
total += int64(n) // incr total bytes read.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
debug.Println("*[R] r.READ error", err)
|
||||||
break DONE
|
break DONE
|
||||||
}
|
}
|
||||||
|
debug.Println(b.id, "*[R] READ (start, end, n)", start, n, b.buf[start:start+int64(n)])
|
||||||
|
|
||||||
// Move the head forward.
|
// Move the head forward.
|
||||||
debug.Println(b.id, "*[R] STORE HEAD", start+int64(n))
|
debug.Println(b.id, "*[R] STORE HEAD", start+int64(n))
|
||||||
atomic.StoreInt64(&b.head, start+int64(n))
|
atomic.StoreInt64(&b.head, start+int64(n))
|
||||||
|
|
||||||
|
debug.Println(b.id, "##### *[R] wcond.Locking")
|
||||||
b.wcond.L.Lock()
|
b.wcond.L.Lock()
|
||||||
|
debug.Println(b.id, "##### *[R] wcond.Locked")
|
||||||
|
debug.Println(b.id, "##### *[R] wcond.Broadcasting")
|
||||||
b.wcond.Broadcast()
|
b.wcond.Broadcast()
|
||||||
|
debug.Println(b.id, "##### *[R] wcond.Broadcasted")
|
||||||
|
debug.Println(b.id, "##### *[R] wcond.Unlocking")
|
||||||
b.wcond.L.Unlock()
|
b.wcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### *[R] wcond.Unlocked")
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Println(b.id, "*[R] FINISHED SPIN")
|
debug.Println(b.id, "*[R] FINISHED SPIN")
|
||||||
@@ -80,19 +89,33 @@ DONE:
|
|||||||
|
|
||||||
// Peek returns the next n bytes without advancing the reader.
|
// Peek returns the next n bytes without advancing the reader.
|
||||||
func (b *Reader) Peek(n int64) ([]byte, error) {
|
func (b *Reader) Peek(n int64) ([]byte, error) {
|
||||||
|
debug.Println(b.id, "[R] START PEEKING (n)", n)
|
||||||
|
|
||||||
tail := atomic.LoadInt64(&b.tail)
|
tail := atomic.LoadInt64(&b.tail)
|
||||||
head := atomic.LoadInt64(&b.head)
|
var head int64
|
||||||
|
//head := atomic.LoadInt64(&b.head)
|
||||||
|
|
||||||
// Wait until there's at least 1 byte of data.
|
// Wait until there's at least 1 byte of data.
|
||||||
debug.Println(b.id, "[R] PEEKING (tail, head, n)", tail, head, n)
|
debug.Println(b.id, "[R] PEEKING (tail, head, n)", tail, head, n, "/", atomic.LoadInt64(&b.head))
|
||||||
|
|
||||||
|
debug.Println(b.id, "##### [R] wcond.Locking")
|
||||||
b.wcond.L.Lock()
|
b.wcond.L.Lock()
|
||||||
for ; head == tail; head = atomic.LoadInt64(&b.head) {
|
debug.Println(b.id, "##### [R] wcond.Locked")
|
||||||
|
for head = atomic.LoadInt64(&b.head); head == atomic.LoadInt64(&b.tail); head = atomic.LoadInt64(&b.head) {
|
||||||
|
debug.Println(b.id, "[R] PEEKING insufficient (tail, head)", tail, head)
|
||||||
if atomic.LoadInt64(&b.done) == 1 {
|
if atomic.LoadInt64(&b.done) == 1 {
|
||||||
|
debug.Println(b.id, "************ [R] PEEK caught DONE")
|
||||||
|
b.wcond.L.Unlock() // make sure we unlock
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
}
|
}
|
||||||
|
debug.Println(b.id, "##### [R] wcond.Waiting")
|
||||||
b.wcond.Wait()
|
b.wcond.Wait()
|
||||||
|
debug.Println(b.id, "##### [R] wcond.Waited")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
debug.Println(b.id, "##### [R] wcond.Unlocking")
|
||||||
b.wcond.L.Unlock()
|
b.wcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### [R] wcond.Unlocked")
|
||||||
debug.Println(b.id, "[R] PEEKING available")
|
debug.Println(b.id, "[R] PEEKING available")
|
||||||
|
|
||||||
// Figure out if we can get all n bytes.
|
// Figure out if we can get all n bytes.
|
||||||
|
|||||||
@@ -23,17 +23,20 @@ func NewWriter(size, block int64) *Writer {
|
|||||||
|
|
||||||
// WriteTo writes the contents of the buffer to an io.Writer.
|
// WriteTo writes the contents of the buffer to an io.Writer.
|
||||||
func (b *Writer) WriteTo(w io.Writer) (total int64, err error) {
|
func (b *Writer) WriteTo(w io.Writer) (total int64, err error) {
|
||||||
|
debug.Println(b.id, "*[R] STARTING SPIN")
|
||||||
var p []byte
|
var p []byte
|
||||||
var n int
|
var n int
|
||||||
|
DONE:
|
||||||
for {
|
for {
|
||||||
cd := b.capDelta(atomic.LoadInt64(&b.tail), atomic.LoadInt64(&b.head))
|
cd := b.capDelta(atomic.LoadInt64(&b.tail), atomic.LoadInt64(&b.head))
|
||||||
debug.Println(b.id, "SPIN (tail, head, delta)", b.tail, b.head, cd)
|
debug.Println(b.id, "* [W] SPIN (tail, head, delta)", b.tail, b.head, cd)
|
||||||
if atomic.LoadInt64(&b.done) == 1 {
|
if atomic.LoadInt64(&b.done) == 1 {
|
||||||
if cd == 0 {
|
if cd == 0 {
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
return total, err
|
debug.Println(b.id, "************ *[W] caught DONE")
|
||||||
|
break DONE
|
||||||
} else {
|
} else {
|
||||||
debug.Println("[W] //// capDelta not reached", cd)
|
debug.Println("*[W] //// capDelta not reached", cd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,31 +44,40 @@ func (b *Writer) WriteTo(w io.Writer) (total int64, err error) {
|
|||||||
// of the Reader type.
|
// of the Reader type.
|
||||||
p, err = (*Reader)(b).Peek(b.block)
|
p, err = (*Reader)(b).Peek(b.block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Println(b.id, "[W] writeTo peek err (p, err)", p, err)
|
debug.Println(b.id, "*[W] writeTo peek err (p, err)", p, err)
|
||||||
continue
|
continue
|
||||||
//break DONE
|
//break DONE
|
||||||
}
|
}
|
||||||
debug.Println(b.id, "[W] PEEKED OK (p)", p)
|
debug.Println(b.id, "*[W] PEEKED OK (p)", p)
|
||||||
|
|
||||||
// Write the peeked bytes to the io.Writer.
|
// Write the peeked bytes to the io.Writer.
|
||||||
n, err = w.Write(p)
|
n, err = w.Write(p)
|
||||||
total += int64(n)
|
total += int64(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return total, err
|
debug.Println(b.id, "*[W] io READ err", err)
|
||||||
|
break DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Println(b.id, "[W] SENT (n, p)", n, p)
|
debug.Println(b.id, "*[W] SENT (n, p)", n, p)
|
||||||
|
|
||||||
// Move the tail forward the bytes written.
|
// Move the tail forward the bytes written.
|
||||||
end := (atomic.LoadInt64(&b.tail) + int64(n)) % b.size
|
end := (atomic.LoadInt64(&b.tail) + int64(n)) % b.size
|
||||||
debug.Println(b.id, "[W] STORE TAIL", end)
|
debug.Println(b.id, "*[W] STORE TAIL", end)
|
||||||
atomic.StoreInt64(&b.tail, end)
|
atomic.StoreInt64(&b.tail, end)
|
||||||
|
|
||||||
|
debug.Println(b.id, "##### *[W] rcond.Locking")
|
||||||
b.rcond.L.Lock()
|
b.rcond.L.Lock()
|
||||||
|
debug.Println(b.id, "##### *[W] rcond.Locked")
|
||||||
|
debug.Println(b.id, "##### *[W] rcond.Broadcasting")
|
||||||
b.rcond.Broadcast()
|
b.rcond.Broadcast()
|
||||||
|
debug.Println(b.id, "##### *[W] rcond.Broadcasted")
|
||||||
|
debug.Println(b.id, "##### *[W] rcond.Unlocking")
|
||||||
b.rcond.L.Unlock()
|
b.rcond.L.Unlock()
|
||||||
debug.Println(b.id, "[W] writeTo unlocked")
|
debug.Println(b.id, "##### *[W] rcond.Unlocked")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug.Println(b.id, "*[W] FINISHED SPIN")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,9 +102,15 @@ func (b *Writer) Write(p []byte) (nn int, err error) {
|
|||||||
atomic.StoreInt64(&b.head, next)
|
atomic.StoreInt64(&b.head, next)
|
||||||
debug.Println(b.id, "[W] STORE HEAD", next)
|
debug.Println(b.id, "[W] STORE HEAD", next)
|
||||||
|
|
||||||
|
debug.Println(b.id, "##### [W] wcond.Locking")
|
||||||
b.wcond.L.Lock()
|
b.wcond.L.Lock()
|
||||||
|
debug.Println(b.id, "##### [W] rcond.Locked")
|
||||||
|
debug.Println(b.id, "##### [W] rcond.Broadcasting")
|
||||||
b.wcond.Broadcast()
|
b.wcond.Broadcast()
|
||||||
|
debug.Println(b.id, "##### [W] rcond.Broadcasted")
|
||||||
|
debug.Println(b.id, "##### [W] rcond.Unlocking")
|
||||||
b.wcond.L.Unlock()
|
b.wcond.L.Unlock()
|
||||||
|
debug.Println(b.id, "##### [W] rcond.Unlocked")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
89
mqtt_test.go
89
mqtt_test.go
@@ -185,54 +185,57 @@ func BenchmarkServerClose(b *testing.B) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func TestServerEstablishConnectionOKCleanSession(t *testing.T) {
|
func TestServerEstablishConnectionOKCleanSession(t *testing.T) {
|
||||||
s := New()
|
for x := 0; x < 10000; x++ {
|
||||||
r, w := net.Pipe()
|
fmt.Println("===========================", x)
|
||||||
o := make(chan error)
|
s := New()
|
||||||
go func() {
|
r, w := net.Pipe()
|
||||||
o <- s.EstablishConnection("tcp", r, new(auth.Allow))
|
o := make(chan error)
|
||||||
}()
|
go func() {
|
||||||
|
o <- s.EstablishConnection("tcp", r, new(auth.Allow))
|
||||||
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
w.Write([]byte{
|
w.Write([]byte{
|
||||||
byte(packets.Connect << 4), 15, // Fixed header
|
byte(packets.Connect << 4), 15, // Fixed header
|
||||||
0, 4, // Protocol Name - MSB+LSB
|
0, 4, // Protocol Name - MSB+LSB
|
||||||
'M', 'Q', 'T', 'T', // Protocol Name
|
'M', 'Q', 'T', 'T', // Protocol Name
|
||||||
4, // Protocol Version
|
4, // Protocol Version
|
||||||
2, // Packet Flags - clean session
|
2, // Packet Flags - clean session
|
||||||
0, 45, // Keepalive
|
0, 45, // Keepalive
|
||||||
0, 3, // Client ID - MSB+LSB
|
0, 3, // Client ID - MSB+LSB
|
||||||
'z', 'e', 'n', // Client ID "zen"
|
'z', 'e', 'n', // Client ID "zen"
|
||||||
})
|
})
|
||||||
w.Write([]byte{byte(packets.Disconnect << 4), 0})
|
w.Write([]byte{byte(packets.Disconnect << 4), 0})
|
||||||
}()
|
}()
|
||||||
|
|
||||||
recv := make(chan []byte)
|
recv := make(chan []byte)
|
||||||
go func() {
|
go func() {
|
||||||
buf, err := ioutil.ReadAll(w)
|
buf, err := ioutil.ReadAll(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
}
|
||||||
|
recv <- buf
|
||||||
|
}()
|
||||||
|
|
||||||
|
//time.Sleep(10 * time.Millisecond)
|
||||||
|
s.clients.Lock()
|
||||||
|
for _, v := range s.clients.internal {
|
||||||
|
v.close()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
recv <- buf
|
s.clients.Unlock()
|
||||||
}()
|
|
||||||
|
|
||||||
//time.Sleep(10 * time.Millisecond)
|
errx := <-o
|
||||||
s.clients.Lock()
|
require.NoError(t, errx)
|
||||||
for _, v := range s.clients.internal {
|
require.Equal(t, []byte{
|
||||||
v.close()
|
byte(packets.Connack << 4), 2,
|
||||||
break
|
0, packets.Accepted,
|
||||||
|
}, <-recv)
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
w.Close()
|
||||||
}
|
}
|
||||||
s.clients.Unlock()
|
|
||||||
|
|
||||||
errx := <-o
|
|
||||||
require.NoError(t, errx)
|
|
||||||
require.Equal(t, []byte{
|
|
||||||
byte(packets.Connack << 4), 2,
|
|
||||||
0, packets.Accepted,
|
|
||||||
}, <-recv)
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
w.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
72
processor.go
72
processor.go
@@ -24,10 +24,13 @@ type Processor struct {
|
|||||||
W *circ.Writer
|
W *circ.Writer
|
||||||
|
|
||||||
// started tracks the goroutines which have been started.
|
// started tracks the goroutines which have been started.
|
||||||
started sync.WaitGroup
|
started *sync.WaitGroup
|
||||||
|
|
||||||
// ended tracks the goroutines which have ended.
|
// endedW tracks when the writer has ended.
|
||||||
ended sync.WaitGroup
|
endedW *sync.WaitGroup
|
||||||
|
|
||||||
|
// endedR tracks when the reader has ended.
|
||||||
|
endedR *sync.WaitGroup
|
||||||
|
|
||||||
// FixedHeader is the FixedHeader from the last read packet.
|
// FixedHeader is the FixedHeader from the last read packet.
|
||||||
FixedHeader packets.FixedHeader
|
FixedHeader packets.FixedHeader
|
||||||
@@ -36,55 +39,68 @@ type Processor struct {
|
|||||||
// NewProcessor returns a new instance of Processor.
|
// NewProcessor returns a new instance of Processor.
|
||||||
func NewProcessor(c net.Conn, r *circ.Reader, w *circ.Writer) *Processor {
|
func NewProcessor(c net.Conn, r *circ.Reader, w *circ.Writer) *Processor {
|
||||||
return &Processor{
|
return &Processor{
|
||||||
Conn: c,
|
Conn: c,
|
||||||
R: r,
|
R: r,
|
||||||
W: w,
|
W: w,
|
||||||
|
started: new(sync.WaitGroup),
|
||||||
|
endedW: new(sync.WaitGroup),
|
||||||
|
endedR: new(sync.WaitGroup),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start spins up the reader and writer goroutines.
|
// Start spins up the reader and writer goroutines.
|
||||||
func (p *Processor) Start() {
|
func (p *Processor) Start() {
|
||||||
go func() {
|
p.started.Add(2)
|
||||||
defer p.ended.Done()
|
fmt.Println("\t\tWG Started ADD", 2)
|
||||||
fmt.Println("starting readFrom", p.Conn)
|
|
||||||
p.started.Done()
|
|
||||||
n, err := p.R.ReadFrom(p.Conn)
|
|
||||||
if err != nil {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
fmt.Println(">>> finished ReadFrom", n, err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
go func(start, end *sync.WaitGroup) {
|
||||||
defer p.ended.Done()
|
defer p.endedW.Done()
|
||||||
fmt.Println("starting writeTo", p.Conn)
|
|
||||||
p.started.Done()
|
p.started.Done()
|
||||||
|
|
||||||
|
fmt.Println("starting writeTo", p.Conn)
|
||||||
n, err := p.W.WriteTo(p.Conn)
|
n, err := p.W.WriteTo(p.Conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(">>> finished WriteTo", n, err)
|
fmt.Println(">>> finished WriteTo", n, err)
|
||||||
}()
|
}(p.started, p.endedW)
|
||||||
|
p.endedW.Add(1)
|
||||||
|
|
||||||
p.started.Add(2)
|
go func(start, end *sync.WaitGroup) {
|
||||||
p.ended.Add(2)
|
defer p.endedR.Done()
|
||||||
|
p.started.Done()
|
||||||
|
|
||||||
|
fmt.Println("starting readFrom", p.Conn)
|
||||||
|
n, err := p.R.ReadFrom(p.Conn)
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
fmt.Println(">>> finished ReadFrom", n, err)
|
||||||
|
}(p.started, p.endedR)
|
||||||
|
p.endedR.Add(1)
|
||||||
|
|
||||||
|
fmt.Println("\t\tWG Started Waiting")
|
||||||
p.started.Wait()
|
p.started.Wait()
|
||||||
|
fmt.Println("Started OK")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops the processor goroutines.
|
// Stop stops the processor goroutines.
|
||||||
func (p *Processor) Stop() {
|
func (p *Processor) Stop() {
|
||||||
fmt.Println("processor stop")
|
|
||||||
|
|
||||||
p.W.Close()
|
p.W.Close()
|
||||||
|
p.endedW.Wait()
|
||||||
|
|
||||||
if p.Conn != nil {
|
if p.Conn != nil {
|
||||||
p.Conn.Close()
|
p.Conn.Close()
|
||||||
|
} else {
|
||||||
|
fmt.Println("--// Conn is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.R.Close()
|
p.R.Close()
|
||||||
|
p.endedR.Wait()
|
||||||
p.ended.Wait()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshDeadline refreshes the read/write deadline for the net.Conn connection.
|
// RefreshDeadline refreshes the read/write deadline for the net.Conn connection.
|
||||||
|
|||||||
Reference in New Issue
Block a user