瀏覽代碼

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

Loading…
取消
儲存