Ok, so the problem is that my 'simpler' version of do_read gave up the interpreter lock earlier and aquired it later. This unfortunately also meant that signal handling only happened outside of the loop. The 'extra' character after CTRL+C terminated the read-loop which then triggered the signal handling. Will fix.