Commit 05c0c0ba authored by Mygod's avatar Mygod

Fix ConcurrentModificationException

parent 64c48a34
...@@ -31,8 +31,8 @@ import com.github.shadowsocks.utils.thread ...@@ -31,8 +31,8 @@ import com.github.shadowsocks.utils.thread
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.*
import java.util.concurrent.ArrayBlockingQueue import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.atomic.AtomicReference
class GuardedProcessPool { class GuardedProcessPool {
companion object { companion object {
...@@ -57,11 +57,11 @@ class GuardedProcessPool { ...@@ -57,11 +57,11 @@ class GuardedProcessPool {
pushed = true pushed = true
} }
fun looper() { fun looper(host: HashSet<Thread>) {
var process: Process? = null var process: Process? = null
try { try {
var callback: (() -> Unit)? = null var callback: (() -> Unit)? = null
while (!isDestroyed) { while (guardThreads.get() === host) {
if (BuildConfig.DEBUG) Log.d(TAG, "start process: " + Commandline.toString(cmd)) if (BuildConfig.DEBUG) Log.d(TAG, "start process: " + Commandline.toString(cmd))
val startTime = SystemClock.elapsedRealtime() val startTime = SystemClock.elapsedRealtime()
...@@ -78,11 +78,8 @@ class GuardedProcessPool { ...@@ -78,11 +78,8 @@ class GuardedProcessPool {
pushException(null) pushException(null)
process.waitFor() process.waitFor()
synchronized(this) { if (SystemClock.elapsedRealtime() - startTime < 1000) {
if (SystemClock.elapsedRealtime() - startTime < 1000) { Log.w(TAG, "process exit too fast, stop guard: $cmdName")
Log.w(TAG, "process exit too fast, stop guard: $cmdName")
isDestroyed = true
}
} }
} }
} catch (_: InterruptedException) { } catch (_: InterruptedException) {
...@@ -103,26 +100,32 @@ class GuardedProcessPool { ...@@ -103,26 +100,32 @@ class GuardedProcessPool {
} }
} }
private val guardThreads = HashSet<Thread>() /**
@Volatile * This is an indication of which thread pool is being active.
private var isDestroyed = false * Reading/writing this collection still needs an additional lock to prevent concurrent modification.
*/
private val guardThreads = AtomicReference<HashSet<Thread>>(HashSet())
fun start(cmd: List<String>, onRestartCallback: (() -> Unit)? = null): GuardedProcessPool { fun start(cmd: List<String>, onRestartCallback: (() -> Unit)? = null): GuardedProcessPool {
val guard = Guard(cmd, onRestartCallback) val guard = Guard(cmd, onRestartCallback)
guardThreads.add(thread("GuardThread-${guard.cmdName}", block = guard::looper)) val guardThreads = guardThreads.get()
synchronized(guardThreads) {
guardThreads.add(thread("GuardThread-${guard.cmdName}") {
guard.looper(guardThreads)
})
}
val ioException = guard.excQueue.take() val ioException = guard.excQueue.take()
if (ioException !== dummy) throw ioException if (ioException !== dummy) throw ioException
return this return this
} }
fun killAll() { fun killAll() {
isDestroyed = true val guardThreads = guardThreads.getAndSet(HashSet())
guardThreads.forEach { it.interrupt() } synchronized(guardThreads) {
try { guardThreads.forEach { it.interrupt() }
guardThreads.forEach { it.join() } try {
} catch (_: InterruptedException) { } guardThreads.forEach { it.join() }
} catch (_: InterruptedException) { }
guardThreads.clear() }
isDestroyed = false
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment