3

I am currently writing a fuse using fuse-python. It's already doing what it should. However, after it's mounted for a few weeks, it's becoming noticeably slow. So I wanted to profile it. I know about a few point where it could be optimized. But these should not be the culprits.

However, fuse-python hangs in an infinite loop (see line 733 and 757 of the fuse source). If I run fuse in debug mode (using the -d switch), it will run in foreground. However, I cannot stop it with SIGINT nor with CTRL+C (which is anyway the same).

I tried to use the signal module to trap the signal in the main thread. But this does not work either. Interestingly, once I shoot the process down with SIGKILL, I see the KeyboardInterrupt on stdout. Also, after a SIGKILL, the signal handler is executed as expected.

This has repercussions on profiling. As the process never terminates normally, cProfile never gets the chance to save the stats file.

Any ideas?

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
exhuma
  • 20,071
  • 12
  • 90
  • 123
  • @matt: I haven't had a chance to work on it yet. I've briefly read over your answer and it looks sound. I told myself I'd only accept answers that I did indeed check and verify. I'll see what I can do in the coming weeks. As it's only a very-low-priority project I do in my spare time, I don't get much time to work on it. Performance and profiling is currently the last of my concern in it. – exhuma Mar 18 '11 at 09:55

1 Answers1

8

Python installs a handler that raises KeyboardInterrupt on SIGINT. If a non-default signal handler is detected when fuse's main is called, it will not replace the handler with its own, which normally calls fuse_session_exit and cleans up. After you've called fuse's main, the KeyboardInterrupt is swallowed by CFUNCTYPE wrappers and you never see them.

Your options are to:

  • Send SIGQUIT by pressing Ctrl+\, or any other terminating signal other than SIGINT. However fuse will not exit cleanly.
  • Install the default signal handler to SIGINT before calling fuse's main, and restore the original when you're done.

old_handler =signal(SIGINT, SIG_DFL)
# call main
signal(SIGINT, old_handler)

I'd highly recommend you switch to an alternative binding also, fuse-python is terribly messy and difficult to work with. I've had a lot of luck with fusepy, and have submitted a few patches there.

When you're able to terminate your FUSE instance without using uncaught signals, the Python profiler will be able to save the stats as per normal.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • Thank you for mentioning `fusepy`. `fuse-python` is indeed terribly messy. I tried to dig into the code exactly twice. Never looked at it again ;) I will change my code to using `fusepy` first. Then I'll look up profiling again... – exhuma Feb 21 '11 at 08:10
  • @exhuma: I've adapted fusepy to my own binding after some heavy use. You can read the latest version here: http://code.google.com/p/cpfs/source/browse/python/fuse.py If it's of value, I'll rip it out, document it and make a stand alone project for it. – Matt Joiner Jun 10 '11 at 02:12
  • Do you have some sort of changelog? A quick summary of the changes? I'll download it and I'll do a `diff` once I get the time. But a quick changelog would be helpful nonetheless ;) – exhuma Jun 10 '11 at 07:26