Browse Source

Possible IdleTimer lock fix

tags/v0.11.0-beta
Daniel Oaks 6 years ago
parent
commit
7b88d21e58
1 changed files with 32 additions and 19 deletions
  1. 32
    19
      irc/idletimer.go

+ 32
- 19
irc/idletimer.go View File

@@ -37,29 +37,42 @@ type IdleTimer struct {
37 37
 	sync.Mutex // tier 1
38 38
 
39 39
 	// immutable after construction
40
-	registerTimeout       time.Duration
41
-	idleTimeout           time.Duration
42
-	idleTimeoutWithResume time.Duration
43
-	quitTimeout           time.Duration
44
-	client                *Client
40
+	registerTimeout time.Duration
41
+	quitTimeout     time.Duration
42
+	client          *Client
45 43
 
46 44
 	// mutable
47
-	state TimerState
48
-	timer *time.Timer
45
+	idleTimeout time.Duration
46
+	state       TimerState
47
+	timer       *time.Timer
49 48
 }
50 49
 
51 50
 // NewIdleTimer sets up a new IdleTimer using constant timeouts.
52 51
 func NewIdleTimer(client *Client) *IdleTimer {
53 52
 	it := IdleTimer{
54
-		registerTimeout:       RegisterTimeout,
55
-		idleTimeout:           IdleTimeout,
56
-		idleTimeoutWithResume: IdleTimeoutWithResumeCap,
57
-		quitTimeout:           QuitTimeout,
58
-		client:                client,
53
+		registerTimeout: RegisterTimeout,
54
+		idleTimeout:     IdleTimeout,
55
+		quitTimeout:     QuitTimeout,
56
+		client:          client,
59 57
 	}
60 58
 	return &it
61 59
 }
62 60
 
61
+// updateIdleDuration updates the idle duration, given the client's caps.
62
+func (it *IdleTimer) updateIdleDuration() {
63
+	newIdleTime := IdleTimeout
64
+
65
+	// if they have the resume cap, wait longer before pinging them out
66
+	// to give them a chance to resume their connection
67
+	if it.client.capabilities.Has(caps.Resume) {
68
+		newIdleTime = IdleTimeoutWithResumeCap
69
+	}
70
+
71
+	it.Lock()
72
+	defer it.Unlock()
73
+	it.idleTimeout = newIdleTime
74
+}
75
+
63 76
 // Start starts counting idle time; if there is no activity from the client,
64 77
 // it will eventually be stopped.
65 78
 func (it *IdleTimer) Start() {
@@ -75,6 +88,8 @@ func (it *IdleTimer) Touch() {
75 88
 		return
76 89
 	}
77 90
 
91
+	it.updateIdleDuration()
92
+
78 93
 	it.Lock()
79 94
 	defer it.Unlock()
80 95
 	// a touch transitions TimerUnregistered or TimerIdle into TimerActive
@@ -85,6 +100,8 @@ func (it *IdleTimer) Touch() {
85 100
 }
86 101
 
87 102
 func (it *IdleTimer) processTimeout() {
103
+	it.updateIdleDuration()
104
+
88 105
 	var previousState TimerState
89 106
 	func() {
90 107
 		it.Lock()
@@ -125,13 +142,7 @@ func (it *IdleTimer) resetTimeout() {
125 142
 	case TimerUnregistered:
126 143
 		nextTimeout = it.registerTimeout
127 144
 	case TimerActive:
128
-		// if they have the resume cap, wait longer before pinging them out
129
-		// to give them a chance to resume their connection
130
-		if it.client.capabilities.Has(caps.Resume) {
131
-			nextTimeout = it.idleTimeoutWithResume
132
-		} else {
133
-			nextTimeout = it.idleTimeout
134
-		}
145
+		nextTimeout = it.idleTimeout
135 146
 	case TimerIdle:
136 147
 		nextTimeout = it.quitTimeout
137 148
 	case TimerDead:
@@ -146,6 +157,8 @@ func (it *IdleTimer) quitMessage(state TimerState) string {
146 157
 		return fmt.Sprintf("Registration timeout: %v", it.registerTimeout)
147 158
 	case TimerIdle:
148 159
 		// how many seconds before registered clients are timed out (IdleTimeout plus QuitTimeout).
160
+		it.Lock()
161
+		defer it.Unlock()
149 162
 		return fmt.Sprintf("Ping timeout: %v", (it.idleTimeout + it.quitTimeout))
150 163
 	default:
151 164
 		// shouldn't happen

Loading…
Cancel
Save