Skip to content

Commit 1b7b5fc

Browse files
lopadovaclaude
andcommitted
perf(transport): use tiny probe timeout in isConnected so idle sockets don't block
The liveness probe read under READ_TIMEOUT_MS (100ms), so a healthy but idle socket — the normal between-transactions state — made every pre-send check wait the full reader timeout. Set a 1ms soTimeout for the probe (safe under ioLock, restored before releasing), so an alive idle socket returns near-instantly while a peer-closed socket still reports EOF immediately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fc18700 commit 1b7b5fc

1 file changed

Lines changed: 17 additions & 1 deletion

File tree

package/android/src/main/java/com/margelo/nitro/ecr17/HybridEcr17Transport.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,13 @@ class HybridEcr17Transport : HybridEcr17TransportSpec() {
127127
}
128128
return synchronized(ioLock) {
129129
if (!running || s.isClosed) return@synchronized false
130+
// Use a tiny probe timeout instead of the reader's READ_TIMEOUT_MS so a healthy
131+
// IDLE socket (the normal between-transactions case) returns "alive" almost
132+
// immediately rather than blocking every pre-send check for the full read
133+
// timeout. Safe to retune soTimeout here: we hold ioLock, so the reader thread
134+
// is not mid-read; we restore READ_TIMEOUT_MS before releasing the lock.
130135
try {
136+
s.soTimeout = PROBE_TIMEOUT_MS
131137
val b = pin.read() // EOF (-1) if peer closed; SocketTimeoutException if idle+alive
132138
if (b < 0) {
133139
markDropped()
@@ -137,10 +143,16 @@ class HybridEcr17Transport : HybridEcr17TransportSpec() {
137143
true
138144
}
139145
} catch (_: SocketTimeoutException) {
140-
true // idle but alive (no FIN received within the timeout)
146+
true // idle but alive (no FIN received within the probe timeout)
141147
} catch (_: IOException) {
142148
markDropped() // genuine I/O error: treat as dropped (other throwables propagate)
143149
false
150+
} finally {
151+
try {
152+
s.soTimeout = READ_TIMEOUT_MS // restore the reader loop's timeout
153+
} catch (_: IOException) {
154+
// socket already closed by markDropped(); nothing to restore
155+
}
144156
}
145157
}
146158
}
@@ -209,6 +221,10 @@ class HybridEcr17Transport : HybridEcr17TransportSpec() {
209221
// long for `ioLock`, long enough to avoid busy-spinning.
210222
private const val READ_TIMEOUT_MS = 100
211223

224+
// Probe read timeout used by isConnected(): tiny so a healthy idle socket reports
225+
// "alive" near-instantly instead of paying READ_TIMEOUT_MS on every pre-send check.
226+
private const val PROBE_TIMEOUT_MS = 1
227+
212228
// Sentinels returned by the synchronized read block; kept below the real EOF
213229
// value (-1) so `read < 0` still catches a genuine EOF after these are handled.
214230
private const val SENTINEL_TIMEOUT = -2

0 commit comments

Comments
 (0)