devork

E pur si muove

Letters on keyboard stop working

Thursday, July 30, 2009

Dear Lazy Web

I have some Very weird behaviour where the lowercase letters "C" and "V" stop generating the Correct key press event after a short while (which is why I am typing them as upper Case here...). But only when using Compiz as window manager, when switching away from X to the Console they work again but in X they don't. When looking at the keypress in xeV it shows up like this:

FocusOut event, serial 34, synthetic NO, window 0x5000001,
    mode NotifyGrab, detail NotifyAncestor

FocusIn event, serial 34, synthetic NO, window 0x5000001,
    mode NotifyUngrab, detail NotifyAncestor

KeymapNotify event, serial 31, synthetic NO, window 0x0,
    keys:  82  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   
           0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

For Comparison with a normal keypress:

KeyPress event, serial 31, synthetic NO, window 0x5000001,
    root 0xa9, subw 0x0, time 18685100, (888,414), root:(898,513),
    state 0x10, keycode 53 (keysym 0x78, x), same_screen YES,
    XLookupString gives 1 bytes: (78) "x"
    XmbLookupString gives 1 bytes: (78) "x"
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0x5000001,
    root 0xa9, subw 0x0, time 18685275, (888,414), root:(898,513),
    state 0x10, keycode 53 (keysym 0x78, x), same_screen YES,
    XLookupString gives 1 bytes: (78) "x"
    XFilterEvent returns: False

I am totally at a loss what the problem Could be. And searching for this is really hard and so far entire unsuccessful. The most suspicious thing I Can find in Xorg.log is:

(WW) Logitech USB Multimedia Keyboard: unable to handle keycode 267

But I have no idea if this is related.

Any hints?

How to bring a running python program under debugger control

Saturday, July 25, 2009

Of course pdb has already got functions to start a debugger in the middle of your program, most notably pdb.set_trace(). This however requires you to know where you want to start debugging, it also means you can't leave it in for production code.

But I've always been envious of what I can do with GDB: just interrupt a running program and start to poke around with a debugger. This can be handy in some situations, e.g. you're stuck in a loop and want to investigate. And today it suddenly occurred to me: just register a signal handler that sets the trace function! Here the proof of concept code:

import os
import signal
import sys
import time


def handle_pdb(sig, frame):
    import pdb
    pdb.Pdb().set_trace(frame)


def loop():
    while True:
        x = 'foo'
        time.sleep(0.2)


if __name__ == '__main__':
    signal.signal(signal.SIGUSR1, handle_pdb)
    print(os.getpid())
    loop()

Now I can send SIGUSR1 to the running application and get a debugger. Lovely!

I imagine you could spice this up by using Winpdb to allow remote debugging in case your application is no longer attached to a terminal. And the other problem the above code has is that it can't seem to resume the program after pdb got invoked, after exiting pdb you just get a traceback and are done (but since this is only bdb raising the bdb.BdbQuit exception I guess this could be solved in a few ways). The last immediate issue is running this on Windows, I don't know much about Windows but I know they don't have signals so I'm not sure how you could do this there.

devenv.com via cygwin ssh (visual studio 2003)

Monday, July 13, 2009

Integrating an automatic build on a windows host with the rest of your one-command cross-platform build system can be quite a pain. Luckily there is cygwin which makes things like ssh, bash, make etc all work on windows. It's great.

The trick to building using visual studio from there is to use the devenv.com tool, which is a version of the full blown visual studio (devenv.exe) that does not pop up windows on your screen (ahem, should not- see below) but instead shows all output nicely on your terminal (which you tee to the logfiles of your build system of course). Life still looks good.

So you set up your build system to do remote, unattended logins to the windows build slave using ssh public keys. This is trivial as you do this on all your build slaves. But all of a sudden devenv.com just hangs. That's weird. Do some searching on the mighty Internet and it turns out there's a bug somewhere in Mircosofts authentication handling. There is some token that does something weird and somehow when you use public key authentication visual studio 2003 (and 2005) think they're the system service (since that is what the ssh service runs as) and don't run properly (various errors possible). But everyone reports errors instead of just hanging, how is this possible? So you go to the ssh service and tick the "Allow service to interact with desktop" box, restart ssh and try again. Success! Now you get a window from devenv.com that visual studio crashed on the screen. Never mind that devenv.com was supposed to be command-line only.

But still not closer to the solution. It turns out that Microsoft actually fixed this error for visual studio 2005, but you're stuck with 2003 for some reason.

Time for ugly solutions.

Since this Windows box is a build slave anyway, it's not supposed to be used for anything else. So the only account of use on it is the one used by the build system. What if we run the ssh service in the name of this account? This requires some fiddling with the permissions of the ssh files (/etc/ssh_* and /var/log/sshd.log) in cygwin, but once the ssh service is happy and wants to start it all works! No more errors from devenv.com

Ugly, but it finally works.

Importing modules in C extension modules

Sunday, July 05, 2009

It seems that if you need another module in a function of your extension module, the way modules in the standard library seem to solve this is like this:

static PyObject *
func(void)
{
    PyObject *foo;

    foo = PyImport_ImportModuleNoBlock("foo");
    if (foo == NULL)
        return NULL;
    /* do stuff with foo */
    Py_DECREF(foo);
    return something;
}

This means that you have to import the module each time you enter the function (yes, it's looked up in the modules dict by PyImport_ImportModuleNoBlock() but that function is only avaliable since 2.6, before you have to use PyImport_ImportModule()).

Personally I like storing the module in a static variable so that it only needs to be imported the first time:

static PyObject *
func(void)
{
    static PyObject *foo = NULL;

    if (foo == NULL) {
        foo = PyImport_ImportModuleNoBlock("foo");
        if (foo == NULL)
            return NULL;
    }
    /* do stuff with foo */
    return something;
}

Note here that the Py_DECREF() is gone. This function will effectively leak a reference to the module object. But is this really bad? How often do module objects get deleted in production code? My guess is that they normally stay loaded until the application exits.

Subscribe to: Posts (Atom)