Page MenuHomePhabricator

fix sdwdate sigterm handling during remote_times.py get_time_from_servers
Open, NormalPublic

Description

When sdwdate is inside the threads loop in function get_time_from_servers from file remote_times.py, signal sigterm does not lead to sdwdate terminating.

https://github.com/Whonix/sdwdate/blob/master/usr/lib/python3/dist-packages/sdwdate/remote_times.py

signal_sigterm_handler is triggered, but sys.exit(143) is without effect.

Apparently that is to be expected.

http://stackoverflow.com/questions/905189/why-does-sys-exit-not-exit-when-called-inside-a-thread-in-python

TODO:

  • Shut terminate all eventually running threads and exit.

How to reproduce?

#!/bin/bash
set -x

cd ~/Whonix/packages/sdwdate
sudo make install
sudo -u sdwdate sdwdate &

sdwdate_pid="$!"

sleep 1

sudo kill -sigterm "$sdwdate_pid"

wait "$sdwdate_pid"
true $?

The signal must send during.

Requested urls ['x.onion', 'y.onion', 'z.onion']

I.e. signal must send during gevent.wait().

Details

Impact
Normal

Event Timeline

https://github.com/Whonix/sdwdate/commit/429b0156c8242e2353f5c1d64406f829f90c4168 by @joysn1980 helped a lot. Showed be the correct place where to implement this.

https://github.com/Whonix/sdwdate/commit/66341d6b3232f3f812b0ac3ebd6f49a7928c543f

Maybe not the cleanest implementation. Help welcome.

Can we call /usr/bin/sdwdate's exit_handler() directly from remotes.py?

A python coding question. These two code blocks.

My implementation is a bit weird. Can we call /usr/bin/sdwdate's exit_handler() directly from remotes.py? @marmarek

Where the other thread is created? For me it looks like get_time_from_servers is running in the main thread, so simply not catching SystemExit should be enough. At the point where it was raised, you already called sys.exit (which is how SystemExit is raised), so exit_handler was already called.

If I'm mistaken about this, and it's running in non-main thread, you may want to use https://docs.python.org/3/library/threading.html#event-objects instead, and check it in main loop. Something like:

exit_event = threading.Event()

...

if exit_event.is_set():
  sys.exit(143)

And from the other thread:

exit_event.set()

Also, Python >= 3.4 comes with great API for concurrent execution - asyncio - much more powerful version of asyncore. In this case it could be used to avoid threads at all. But I'm still learning how to use it... You may want to read/watch this: https://fosdem.org/2017/schedule/event/python_coroutines/ if you want quick intro.