Selaa lähdekoodia

Fix race condition in closing a relay

This commit fixes a situration when relay can be reset before all
waiting goroutines are finished. For example, we terminate processing
based on some event: socket error etc. So, error happens and context is
cancelled. After that a main relay goroutine starts to wait. Meanwhile a
second goroutine reaches deferred function and set wg to done. It means
that main goroutine can continue.

In this case this is really possible that we can start resetting before
transmit goroutine really exits.

A correct solution is to always do wg.Done() as a first deferred thing
on entering to a function. In that case we do not need reordering and so
on.
tags/v2.0.1^2
9seconds 5 vuotta sitten
vanhempi
commit
16f9ec690b
1 muutettua tiedostoa jossa 5 lisäystä ja 4 poistoa
  1. 5
    4
      mtglib/internal/relay/relay.go

+ 5
- 4
mtglib/internal/relay/relay.go Näytä tiedosto

@@ -68,11 +68,12 @@ func (r *Relay) Process(eastConn, westConn io.ReadWriteCloser) error {
68 68
 
69 69
 func (r *Relay) transmit(src io.ReadCloser, dst io.WriteCloser,
70 70
 	buffer []byte, direction string, wg *sync.WaitGroup) {
71
+	defer wg.Done()
72
+
71 73
 	defer func() {
74
+		r.ctxCancel()
72 75
 		src.Close()
73 76
 		dst.Close()
74
-		wg.Done()
75
-		r.ctxCancel()
76 77
 	}()
77 78
 
78 79
 	if _, err := io.CopyBuffer(dst, src, buffer); err != nil {
@@ -92,6 +93,8 @@ func (r *Relay) transmit(src io.ReadCloser, dst io.WriteCloser,
92 93
 }
93 94
 
94 95
 func (r *Relay) runObserver(one, another io.Closer, wg *sync.WaitGroup) {
96
+	defer wg.Done()
97
+
95 98
 	ticker := time.NewTicker(time.Second)
96 99
 
97 100
 	defer func() {
@@ -104,8 +107,6 @@ func (r *Relay) runObserver(one, another io.Closer, wg *sync.WaitGroup) {
104 107
 		case <-ticker.C:
105 108
 		default:
106 109
 		}
107
-
108
-		wg.Done()
109 110
 	}()
110 111
 
111 112
 	lastTickAt := time.Now()

Loading…
Peruuta
Tallenna