Skip to content

Commit a28ad7f

Browse files
committed
replace stop chan with ctx cancel, move ticker and pause cb to checkloop
1 parent dd7fc28 commit a28ad7f

1 file changed

Lines changed: 62 additions & 46 deletions

File tree

protocol/group/mutableurltest.go

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/sagernet/sing/common/batch"
1919
"github.com/sagernet/sing/common/metadata"
2020
N "github.com/sagernet/sing/common/network"
21-
"github.com/sagernet/sing/common/x/list"
2221
"github.com/sagernet/sing/service"
2322
"github.com/sagernet/sing/service/pause"
2423
"go.opentelemetry.io/otel"
@@ -74,16 +73,9 @@ func NewMutableURLTest(ctx context.Context, _ A.Router, logger log.ContextLogger
7473
outboundMgr: outboundMgr,
7574
connMgr: service.FromContext[A.ConnectionManager](ctx),
7675
logger: logger,
77-
group: &urlTestGroup{
78-
ctx: ctx,
79-
outboundMgr: outboundMgr,
80-
logger: logger,
81-
tags: options.Outbounds,
82-
link: options.URL,
83-
interval: interval,
84-
idleTimeout: idleTimeout,
85-
tolerance: options.Tolerance,
86-
},
76+
group: newURLTestGroup(
77+
ctx, outboundMgr, logger, options.Outbounds, options.URL, interval, idleTimeout, options.Tolerance,
78+
),
8779
}
8880
return outbound, nil
8981
}
@@ -216,25 +208,47 @@ type urlTestGroup struct {
216208
ctx context.Context
217209
outboundMgr A.OutboundManager
218210
pauseMgr pause.Manager
219-
pauseCallback *list.Element[pause.Callback]
220211
logger log.Logger
221212
tags []string
222213
outbounds isync.TypedMap[string, A.Outbound]
223-
link string
214+
url string
224215
interval time.Duration
225216
tolerance uint16
226217
idleTimeout time.Duration
227218
history *urltest.HistoryStorage
228-
checking atomic.Bool
229219
selectedOutboundTCP atomic.TypedValue[A.Outbound]
230220
selectedOutboundUDP atomic.TypedValue[A.Outbound]
231221
access sync.Mutex
232-
running atomic.Bool
233-
ticker *time.Ticker
222+
checking atomic.Bool
223+
started bool
224+
isAlive bool
234225
idleTimer *time.Timer
235226
lastActive atomic.TypedValue[time.Time]
236-
stop chan struct{}
237-
started bool
227+
pauseC chan struct{}
228+
cancel context.CancelFunc
229+
}
230+
231+
func newURLTestGroup(
232+
ctx context.Context,
233+
outboundMgr A.OutboundManager,
234+
logger log.ContextLogger,
235+
tags []string,
236+
link string,
237+
interval, idleTimeout time.Duration,
238+
tolerance uint16,
239+
) *urlTestGroup {
240+
ctx, cancel := context.WithCancel(ctx)
241+
return &urlTestGroup{
242+
ctx: ctx,
243+
outboundMgr: outboundMgr,
244+
logger: logger,
245+
tags: tags,
246+
url: link,
247+
interval: interval,
248+
idleTimeout: idleTimeout,
249+
tolerance: tolerance,
250+
cancel: cancel,
251+
}
238252
}
239253

240254
func (g *urlTestGroup) Start() error {
@@ -262,7 +276,6 @@ func (g *urlTestGroup) Start() error {
262276
g.history = urltest.NewHistoryStorage()
263277
}
264278
g.pauseMgr = service.FromContext[pause.Manager](g.ctx)
265-
g.stop = make(chan struct{}, 1)
266279
return nil
267280
}
268281

@@ -275,23 +288,19 @@ func (g *urlTestGroup) PostStart() {
275288
}
276289

277290
func (g *urlTestGroup) Close() error {
278-
g.access.Lock()
279-
defer g.access.Unlock()
280291
if g.isClosed() {
281292
return nil
282293
}
283-
if g.ticker != nil {
284-
g.ticker.Stop()
285-
g.idleTimer.Stop()
286-
g.pauseMgr.UnregisterCallback(g.pauseCallback)
287-
}
288-
close(g.stop)
294+
g.access.Lock()
295+
defer g.access.Unlock()
296+
g.cancel()
297+
close(g.pauseC)
289298
return nil
290299
}
291300

292301
func (g *urlTestGroup) isClosed() bool {
293302
select {
294-
case <-g.stop:
303+
case <-g.ctx.Done():
295304
return true
296305
default:
297306
return false
@@ -343,9 +352,9 @@ func (g *urlTestGroup) Remove(tags []string) (n int, err error) {
343352
for tag := range g.outbounds.Iter() {
344353
g.tags = append(g.tags, tag)
345354
}
346-
if len(g.tags) == 0 && g.running.Load() {
355+
if len(g.tags) == 0 && g.isAlive {
347356
select {
348-
case g.stop <- struct{}{}:
357+
case g.pauseC <- struct{}{}:
349358
default:
350359
}
351360
}
@@ -359,39 +368,46 @@ func (g *urlTestGroup) keepAlive() {
359368
if !g.started || len(g.tags) == 0 {
360369
return
361370
}
362-
if !g.running.CompareAndSwap(false, true) {
371+
if g.isAlive {
363372
g.lastActive.Store(time.Now())
364373
g.idleTimer.Reset(g.idleTimeout)
365374
return
366375
}
367-
g.ticker = time.NewTicker(g.interval)
376+
g.pauseC = make(chan struct{}, 1)
368377
go g.checkLoop()
369-
g.pauseCallback = pause.RegisterTicker(g.pauseMgr, g.ticker, g.interval, nil)
370378
}
371379

372380
func (g *urlTestGroup) checkLoop() {
373381
if time.Since(g.lastActive.Load()) > g.interval {
374382
g.lastActive.Store(time.Now())
375383
g.CheckOutbounds(false)
376384
}
385+
g.access.Lock()
386+
ctx, cancel := context.WithCancel(g.ctx)
387+
ticker := time.NewTicker(g.interval)
388+
pauseCallback := pause.RegisterTicker(g.pauseMgr, ticker, g.interval, nil)
377389
g.idleTimer = time.NewTimer(g.idleTimeout)
378-
loop:
390+
g.isAlive = true
391+
g.access.Unlock()
392+
393+
defer func() {
394+
cancel()
395+
g.access.Lock()
396+
g.pauseMgr.UnregisterCallback(pauseCallback)
397+
g.idleTimer.Stop()
398+
g.isAlive = false
399+
g.access.Unlock()
400+
}()
379401
for {
380402
select {
381-
case <-g.stop:
382-
break loop
383-
case <-g.ticker.C:
384-
g.CheckOutbounds(false)
403+
case <-g.pauseC:
404+
return
385405
case <-g.idleTimer.C:
386-
break loop
406+
return
407+
case <-ticker.C:
408+
go g.urlTest(ctx, false)
387409
}
388410
}
389-
g.access.Lock()
390-
g.ticker.Stop()
391-
g.running.Store(false)
392-
g.pauseMgr.UnregisterCallback(g.pauseCallback)
393-
g.pauseCallback = nil
394-
g.access.Unlock()
395411
}
396412

397413
func (g *urlTestGroup) CheckOutbounds(force bool) {
@@ -431,7 +447,7 @@ func (g *urlTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
431447
b.Go(realTag, func() (any, error) {
432448
testCtx, cancel := context.WithTimeout(g.ctx, C.TCPTimeout)
433449
defer cancel()
434-
t, err := urltest.URLTest(testCtx, g.link, p)
450+
t, err := urltest.URLTest(testCtx, g.url, p)
435451
if err != nil {
436452
g.logger.Debug("outbound ", tag, " unavailable: ", err)
437453
g.history.DeleteURLTestHistory(realTag)

0 commit comments

Comments
 (0)