ソースを参照

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年前
コミット
16f9ec690b
1個のファイルの変更5行の追加4行の削除
  1. 5
    4
      mtglib/internal/relay/relay.go

+ 5
- 4
mtglib/internal/relay/relay.go ファイルの表示

@@ -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()

読み込み中…
キャンセル
保存