Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
scala.sys.process.ProcessImpl.scala Maven / Gradle / Ivy
package scala
package sys
package process
import processInternal._
import java.io.{ PipedInputStream , PipedOutputStream }
private [process] trait ProcessImpl {
self: Process .type =>
private [process] object Spawn {
def apply (f: => Unit ): Thread = apply(f, daemon = false )
def apply (f: => Unit , daemon: Boolean ): Thread = {
val thread = new Thread () { override def run () = { f } }
thread.setDaemon(daemon)
thread.start()
thread
}
}
private [process] object Future {
def apply [T ](f: => T ): (Thread , () => T ) = {
val result = new SyncVar [Either [Throwable , T ]]
def run (): Unit =
try result.put(Right (f))
catch { case e: Exception => result.put(Left (e)) }
val t = Spawn (run())
(t, () => result.get match {
case Right (value) => value
case Left (exception) => throw exception
})
}
}
private [process] class AndProcess (
a: ProcessBuilder ,
b: ProcessBuilder ,
io: ProcessIO
) extends SequentialProcess (a, b, io, _ == 0 )
private [process] class OrProcess (
a: ProcessBuilder ,
b: ProcessBuilder ,
io: ProcessIO
) extends SequentialProcess (a, b, io, _ != 0 )
private [process] class ProcessSequence (
a: ProcessBuilder ,
b: ProcessBuilder ,
io: ProcessIO
) extends SequentialProcess (a, b, io, _ => true )
private [process] class SequentialProcess (
a: ProcessBuilder ,
b: ProcessBuilder ,
io: ProcessIO ,
evaluateSecondProcess: Int => Boolean
) extends CompoundProcess {
protected [this ] override def runAndExitValue () = {
val first = a.run(io)
runInterruptible(first.exitValue())(first.destroy()) flatMap { codeA =>
if (evaluateSecondProcess(codeA)) {
val second = b.run(io)
runInterruptible(second.exitValue())(second.destroy())
}
else Some (codeA)
}
}
}
private [process] abstract class BasicProcess extends Process {
def start (): Unit
}
private [process] abstract class CompoundProcess extends BasicProcess {
def isAlive () = processThread.isAlive()
def destroy () = destroyer()
def exitValue () = getExitValue._2() getOrElse scala.sys.error("No exit code: process destroyed." )
def start () = getExitValue
protected lazy val (processThread, getExitValue, destroyer) = {
val code = new SyncVar [Option [Int ]]()
code.put(None )
val thread = Spawn (code.put(runAndExitValue()))
(
thread,
Future { thread.join(); code.get },
() => thread.interrupt()
)
}
protected [this ] def runAndExitValue (): Option [Int ]
protected [this ] def runInterruptible [T ](action: => T )(destroyImpl: => Unit ): Option [T ] = {
try Some (action)
catch onInterrupt { destroyImpl; None }
}
}
private [process] class PipedProcesses (a: ProcessBuilder , b: ProcessBuilder , defaultIO: ProcessIO , toError: Boolean ) extends CompoundProcess {
protected [this ] override def runAndExitValue () = runAndExitValue(new PipeSource (a.toString), new PipeSink (b.toString))
protected [this ] def runAndExitValue (source: PipeSource , sink: PipeSink ): Option [Int ] = {
source connectOut sink
source.start()
sink.start()
def releaseResources (so: PipeSource , sk: PipeSink , p: Process *) = {
so.release()
sk.release()
p foreach( _.destroy() )
}
val firstIO =
if (toError) defaultIO.withError(source.connectIn)
else defaultIO.withOutput(source.connectIn)
val secondIO = defaultIO.withInput(sink.connectOut)
val second =
try b.run(secondIO)
catch onError { err =>
releaseResources(source, sink)
throw err
}
val first =
try a.run(firstIO)
catch onError { err =>
releaseResources(source, sink, second)
throw err
}
runInterruptible {
val exit1 = first.exitValue()
val exit2 = second.exitValue()
if (b.hasExitValue) exit2 else exit1
} {
releaseResources(source, sink, first, second)
}
}
}
private [process] abstract class PipeThread (isSink: Boolean , labelFn: ( ) => String ) extends Thread {
def run (): Unit
private [process] def runloop (src: InputStream , dst: OutputStream ): Unit = {
try BasicIO .transferFully(src, dst)
catch ioFailure(ioHandler)
finally BasicIO close {
if (isSink) dst else src
}
}
private def ioHandler (e: IOException ) {
println("I/O error " + e.getMessage + " for process: " + labelFn())
e.printStackTrace()
}
}
private [process] class PipeSource (label: => String ) extends PipeThread (false, ( ) => label ) {
protected [this ] val pipe = new PipedOutputStream
protected [this ] val source = new LinkedBlockingQueue [Option [InputStream ]]
override def run (): Unit = {
try {
source.take match {
case Some (in) => runloop(in, pipe)
case None =>
}
}
catch onInterrupt(())
finally BasicIO close pipe
}
def connectIn (in: InputStream ): Unit = source add Some (in)
def connectOut (sink: PipeSink ): Unit = sink connectIn pipe
def release (): Unit = {
interrupt()
source add None
join()
}
}
private [process] class PipeSink (label: => String ) extends PipeThread (true, ( ) => label ) {
protected [this ] val pipe = new PipedInputStream
protected [this ] val sink = new LinkedBlockingQueue [Option [OutputStream ]]
override def run (): Unit = {
try {
sink.take match {
case Some (out) => runloop(pipe, out)
case None =>
}
}
catch onInterrupt(())
finally BasicIO close pipe
}
def connectOut (out: OutputStream ): Unit = sink add Some (out)
def connectIn (pipeOut: PipedOutputStream ): Unit = pipe connect pipeOut
def release (): Unit = {
interrupt()
sink add None
join()
}
}
private [process] class DummyProcess (action: => Int ) extends Process {
private [this ] val exitCode = Future (action)
override def isAlive () = exitCode._1.isAlive()
override def exitValue () = exitCode._2()
override def destroy () { }
}
private [process] class SimpleProcess (p: JProcess , inputThread: Thread , outputThreads: List [Thread ] ) extends Process {
override def isAlive () = p.isAlive()
override def exitValue () = {
try p.waitFor()
finally inputThread.interrupt()
outputThreads foreach (_.join())
p.exitValue()
}
override def destroy () = {
try {
outputThreads foreach (_.interrupt())
p.destroy()
}
finally inputThread.interrupt()
}
}
private [process] final class ThreadProcess (thread: Thread , success: SyncVar [Boolean ] ) extends Process {
override def isAlive () = thread.isAlive()
override def exitValue () = {
thread.join()
if (success.get) 0 else 1
}
override def destroy () { thread.interrupt() }
}
}