Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What causes this Scala program to become suspended due to tty output when run in the background? [duplicate]

Tags:

shell

scala

tty

Suppose we have the following Scala (2.12). It is using ProcessBuilder to execute a very trivial set of commands (a sleep, followed by an echo). The program also captures both stdout and stderr, and prints all lines - with those respective prefixes - to either stdout or stderr of the Scala process itself.

import scala.sys.process._
import scala.language.postfixOps

object BackgroundProcessRedirect {
  def main(args: Array[String]) = {
    val output = "sleep 5" #&& s"echo myoutput" lineStream_! ProcessLogger(line => System.err.println(s"stderr: $line"))
    output.foreach(line => System.out.println(s"stdout: $line"))
  }
}

When executed on OS X, either in zsh 5.6.2 or GNU bash 4.4.23(1), the process becomes suspended due to tty output unless stdin is attached. This happens despite the fact that neither command (sleep nor echo) should be trying to read from stdin.

# first, compile
scalac BackgroundProcessRedirect.scala

# now, run as a background process, redirecting stdout and stderr to files
scala BackgroundProcessRedirect >/tmp/scala.out 2>/tmp/scala.err &

# after 5 seconds, the process is suspended, as in the following jobs output
[1]  + <PID> suspended (tty output)  scala BackgroundProcessRedirect > /tmp/scala.out 2> /tmp/scala.err

# now, foreground the process; it will complete immediately
fg
# the output file contents are as expected
cat /tmp/scala.out
stdout: myoutput

# run the same thing again, but this time redirect stdin from /dev/null
scala BackgroundProcessRedirect </dev/null >/tmp/scala.out 2>/tmp/scala.err &

# now, the process completes normally after 5 seconds (not suspended), and the file contents are as expected
cat /tmp/scala.out
stdout: myoutput

If the program is simply run in the foreground to begin with, then it also doesn't become suspended. Any ideas what could be causing this?

Running stty -tostop in either the terminal that launches scala, or in a new script file that invokes these same commands, and is then invoked by scala, has no effect on this behavior.

like image 401
Jeff Evans Avatar asked Apr 03 '19 21:04

Jeff Evans


1 Answers

This happens despite the fact that neither command (sleep nor echo) should be trying to read from stdin

Note that the message says "tty output", not "tty input". So it's complaining about the fact that the process produces output, not that it reads from stdin. That's weird for two reasons:

  1. Regular output to stdout or stderr doesn't usually cause background processes to be suspended
  2. You're redirecting stdout and stderr anyway, so even if your terminal were setup to suspend on output, that shouldn't happen in this case.

Suspension on output usually only happens if the process uses tty features beyond just writing to the standard streams (such as writing to specific position on the screen or generally anything that requires curses or similar functionality).

Your program doesn't do this, but apparently the scala binary does¹. At least I can reproduce your problem when trying to run any Scala program with scala className&, but it goes away when I use java -cp /usr/share/scala/lib/scala-library.jar:. className& instead.

So my conclusion is that scala interacts with the tty in a way that breaks background processes and a workaround is to use java instead.


¹ After looking at /usr/bin/scala, it looks like it's calling stty to save and restore the terminal settings. Apparently that doesn't work if the process is run in the background (and thus not properly connected to tty) and that's why the process is suspended.

like image 75
sepp2k Avatar answered Sep 22 '22 15:09

sepp2k