16

Inside a shell script, I need to wait for a window that has a string on its title to appear, do some action, and then wait for it to disappear, and do some other action.

Until yesterday, I had this simple code. The problem with it is that the disk can't be put in a power saving state while the script is left running, and it can be for many hours:

while :; do
    until wmctrl -l | grep -q "$string"; do   # until
        sleep 0.5
    done
    : do action 1

    while wmctrl -l | grep -q "$string"; do   # while
        sleep 0.5
    done
    : do action 2
done

Since I decided the mentioned code was insanely waking the disk, I went through the documentation of a few command line tools, and decided on xdotool to wait for the window to appear, and xprop to figure out when the window has vanished:

while :; do
    # we use `until' because sometimes xdotool just crashes
    until xdotool search -sync -all -onlyvisible -pid $pid -name "$string"; do
        :
    done

    # xdotool isn't trustworthy either, so check again
    wmctrl -l | grep -q "$string" ||
        continue

    : do action 1

    xprop -spy -root _NET_CLIENT_LIST_STACKING | while read line; do
        if [[ ! ${_line:-} || $_line = $line ]]; then
            _line=$line
            continue
        else
            _line=$line
            if wmctrl -l | grep -q "$string"; then
                continue
            else
                : do action 2
                break
            fi
        fi
    done
done

Now I have two new problems with the code above:

  • xdotool not only crashes and gives strange results, as I have workarounded before, but it also sucks about 15% of CPU while left waiting for the window to appear. So that means I got rid of simple code that wakes the disk, to write code that is left wasting the CPU for hours, and my intention was saving power in the first place.
  • xprop -spy will notify me every time I change focus (which I have workarounded through $_line) or create and destroy windows. That wakes the disk more frequently than xdotool.

I'm looking for a simple program that just waits for the window with the title $string to appear or disappear. It can be an existing command line tool, a python script, compilable C code..., but I should be able to integrate it somehow to my script (even if it just writes some information to a fifo)!

admirabilis
  • 4,712
  • 1
    Wouldn't it make sense to find out why your old code wakes the disk and search for a solution? Something like chroot and ramdisk. I guess strace -f -e trace=file wmctrl -l should be informative. – Hauke Laging May 07 '13 at 19:50
  • I'm using fatrace to check for disk wakeups, and it tells me bash reads /bin/sleep and /usr/bin/wmctrl every half second, that's why I'm looking for some program that'll actually wait for window events. Am I missing something? – admirabilis May 07 '13 at 20:01
  • 1
    reading those wouldn't wake up the disk as they would likely be cached if they were run twice every second. Did you mount your filesystems with noatime? See also btrace from blktrace to investigate sources of disk activity. – Stéphane Chazelas May 07 '13 at 20:06
  • A better program may be the more elegant solution. But why should reading a cached file wake the disk? Why should reading /usr/bin/wmctrl wake the disk but reading /what/ever/xdotool not? I guess you have to look for write accesses (writes to files, creating files, deleting files). You should try a chroot to a ramdisk (which contains a bind mount of the X socket, of course). – Hauke Laging May 07 '13 at 20:07
  • @HaukeLaging, see also memlockd to lock some files in memory and avoid having to use a ramdisk (and a ramfs/tmpfs would probably be more appropriate than a ramdisk). read accesses can also cause writes because of the access time. – Stéphane Chazelas May 07 '13 at 20:11
  • @StephaneChazelas they are mounted with noatime, so I guess the disk isn't really being waken, then. – admirabilis May 07 '13 at 20:16
  • I'll probably accept an answer teaching me how to measure if the disk is really being waken :) This memlock stuff is new to me! – admirabilis May 07 '13 at 20:18
  • @StephaneChazelas I meant "ramdisk" in the wide sense (tmpfs). Thanks for making that clear to the readers. Locking files into memory doesn't help here as this would not solve the problem of writing . I don't suggest tmpfs as a file cache but as chroot target. – Hauke Laging May 07 '13 at 20:27
  • 1
    If you haven't looked at it yet xwininfo might be of use, it certainly loads far fewer shared libraries than wmctrl and operates on a level closer to bare X. – msw May 07 '13 at 20:32
  • @StephaneChazelas btrace fails on /dev/sda and /dev/sda1 with 25/Inappropriate ioctl for device – admirabilis May 07 '13 at 20:35
  • @msw I'll have a look at the man page, thanks! – admirabilis May 07 '13 at 20:35
  • Oh, and sleeping for 0.5 seconds is better than no sleep, but not by much. What happens so urgently that you need that granularity of action? Is it possible to use some proxy item (a file) that tells you when the window is likely to change state? This question would be better if you explained what you are trying to accomplish. – msw May 07 '13 at 20:36
  • 1
    @msw I'm trying to fix the unfixable, which is an autosave feature for Google Earth (closed sourced and reporting bugs is a waste of time) – admirabilis May 07 '13 at 20:38
  • @HaukeLaging could you explain a bit more about what I should try to achieve through a chroot to a ramdisk? – admirabilis May 07 '13 at 20:40
  • @TeresaeJunior See the edit to my answer. – Hauke Laging May 07 '13 at 20:49

2 Answers2

8

It might be simpler, and more reliable, to rely on your window manager or X11 to handle this by writing a "real" X11 application.

What you want from the shell is something that registers with the window manager and waits for a desired event type before returning to the shell... it's much more load-friendly if you can avoid looping inside the shell. (Your until xdotool... causes load because there's no delay (sleep) inside the loop.)

Ah... apparently xdotool had that feature added over year ago --sync. That's not available in my current Linux distro (Debian Squeeze), so I haven't tried it out.

The xdotool developer answering a similar question to yours: https://groups.google.com/d/msg/xdotool-users/7zfKTtyWm0Q/DM6TSOBUWZMJ

  • Yes, exactly, -sync was supposed to do what I want, but it needs the while because it will eventually crash before the window appears, and wastes too much CPU. I actually compiled xdotool from source because the one from Debian was incredibly slow to type. Writing an application that interacts directly with X is actually beyond me. Thanks, though! – admirabilis May 07 '13 at 23:12
5

This should give you all (OK: most. What have I forgotten? Sockets?) file system activities which include writes:

strace -f command 2>&1 | 
  grep -e '^open.*O_CREAT' \
    -e ^write   \
    -e ^mkdir   \
    -e ^rmdir   \
    -e ^unlink  \
    -e ^rename  \
    -e ^chmod   \
    -e ^link    \
    -e ^symlink \
    -e ^mknod

With this information a working chroot environment can be created in tmpfs (as an action of last resort; maybe symlinks to tmpfs are enough). If the program is started in a RAM chroot then it does not have a chance to wake the disk directly. No write to its file system hierarchy is ever written to disk.

admirabilis
  • 4,712
Hauke Laging
  • 90,279
  • I believe there are times when reading a file, at least for the first time, will wake the disk too, isn't it? I'm wondering if blktrace would be the right tool for that, but it would require a kernel compilation # CONFIG_BLK_DEV_IO_TRACE is not set :( That is beyond the scope of this question, though. Thank you! – admirabilis May 07 '13 at 23:19
  • 1
    @TeresaeJunior Sure but who would consider that a problem? This is about keeping the script running all the time not about starting it. And you can create the tmpfs from boot.local / rc.local so that you don't have disk accesses even if you start the script later. I just had a look at blktrace (didn't know that before). That's so terrible I wonder if I will get to sleep tonight... – Hauke Laging May 08 '13 at 00:13
  • Yes, I shouldn't really worry about this one anymore, you're right again. But I think I'll also loose this night of sleep compiling the kernel, since I want to check everything that might be waking constantly the disk, not only this particular Google Earth hack :) – admirabilis May 08 '13 at 00:34