i3: Seemingly random i3 freezes (SIGSTOP)

Arch Linux, 4.12-158-ge48119a

Since September (I think), i3 randomly freezes. Sending SIGCONT to i3 makes it responsive. It seems I’m not the only one: https://marc.ttias.be/arch-general/2016-09/msg00067.php

I’ll try to get more info…

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 37 (18 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve had random freezes of i3 when I started it using dbus-launch like so:

dbus-launch --exit-with-session -- i3

Apparently dbus tried to read from stdin from the tty that I ran startx from. Since the .xinitrc was run as a background job, the read caused the whole process group to be stopped by SIGTTIN. The workaround was to redirect stdin from /dev/null like so:

dbus-launch --exit-with-session -- i3 </dev/null

So maybe it helps to add </dev/null to the script or add the line

exec </dev/null

to redirect stdin for all processes after it.

This is old and possibly not directly related, but it’s the closest hit to my (workaround solved) problem, so thought it might be useful to somebody. I use i3-input to switch workspaces, and once every couple of days it hangs. Keyboard input is stolen, but mouse still works. Multi-monitor setup, seems to be related to typing too fast, but that’s a guess, no peripherals involved.

I tried ssh-ing in from another machine and looking for things to kill, nothing. So for ages I just used to reboot the machine. Yesterday I discovered that if someone Skypes me, which on my machine shows a popup in the top right of the screen, the keyboard unlocks and everything is fine again.

Perhaps that’s a clue, or at least useful to someone. (sorry if this is a thread hijack, I scoured the internet looking for a solution)

I think the problem in the script is that the event IPC connection is not closed upon KeyboardInterrupt.

I filed issue #2999 to improve i3’s behavior when IPC clients misbehave.

In the go.i3wm.org/i3 Go package, users must call Next() in a loop (i3 might block until the next call to Next()) and Close() once done. A good way to do this is to use defer to ensure that Close is called:

func() {
  recv := i3.Subscribe(i3.WindowEventType)
  defer recv.Close() // ensure cleanup to prevent i3 deadlocks
  for recv.Next() {
    ev := recv.Event().(*i3.WindowEvent)
    // …process ev… — blocking here might mean blocking i3
  }
}()
// At this point, the IPC connection is closed.

If receiving all events is not a requirement, one can receive events in a different goroutine and discard events when the processing goroutine is busy:

// Make this channel buffered if required
// (e.g. if each event is persisted to (slow) storage):
windowEvents := make(chan *i3.WindowEvent)
go func() {
  recv := i3.Subscribe(i3.WindowEventType)
  defer recv.Close() // ensure cleanup to prevent i3 deadlocks
  for recv.Next() {
    select {
      case windowEvents <- recv.Event().(*i3.WindowEvent):
      default:
        // discard event to never block i3
    }
  }
}()
for ev := range windowEvents {
  // …process ev…
}

Why is .xinitrc run as a background job in your setup? I was under the impression that .xinitrc is usually run as the session itself, i.e. a foreground job.

Turns out xinit starts both the X server and .xinitrc in separate process groups, in the background:

$ ps -H -o stat,pgid,cmd -t /dev/tty2
STAT  PGID CMD
Ss+   3919 /bin/sh /usr/bin/startx
S+    3919   xinit /home/test/.xinitrc -- /etc/X11/xinit/xserverrc :1 vt2 -auth /tmp/serverauth.wgFUTQwZr2
S<    8813     /usr/lib/xorg-server/Xorg -nolisten tcp :1 vt2 -auth /tmp/serverauth.wgFUTQwZr2
S     8818     i3

Xorg’s and i3’s pgid are different from xinit’s while xinit being the foreground (STAT shows +).

It probably has to do this so it can exit if any of the two processes exit. It then kills the other and exits itself.

Note though that I don’t start i3 using dbus-launch anymore. It’s not needed anymore because it’s now automatically started by the systemd user daemon (which happens by default these days on Arch I think).

I think when your X session terminates for whatever reason, the resulting state should be a login prompt, not a shell.

Solution to this is starting startx with exec, so it replaces your shell. So you get back to the login prompt if your X session crashes.