Shutting down a cross-platform multithreaded app

James Harris james.harris.1 at gmail.com
Sat Sep 19 11:49:55 CEST 2015


"Chris Angelico" <rosuav at gmail.com> wrote in message 
news:mailman.8.1442612439.21674.python-list at python.org...
> On Sat, Sep 19, 2015 at 3:17 AM, James Harris 
> <james.harris.1 at gmail.com> wrote:
>> Needless to say, on a test Windows machine AF_UNIX is not present. 
>> The only
>> cross-platform option, therefore, seems to be to use each subthread's
>> select()s to monitor two AF_INET sockets: the one to the client and a
>> control one from the master thread. I would seem to need IP socket 
>> pairs
>> between the master thread and the subthreads. If the master thead 
>> receives a
>> shutdown signal it will send a shutdown command to each subthread.
>>
>> The above seems logical but would use quite a few IP sockets. I 
>> cannot think
>> of a better way, though. Any comments on the ideas above?
>
> If you're using select() to monitor the sockets, you don't actually
> then have to _do_ anything with the shutdown socket. You could have a
> single socket that sends the shutdown signal to all your workers.

I don't understand how a single socket could send the signal to all the 
workers. I did consider some form of multicast but thought it too 
complicated (and possibly infeasible).

Re. not understanding the single sending socket idea that you mention 
perhaps I had better explain a bit of what I had in mind:

1. A worker thread would have a TCP socket connection to its client, and 
another socket for communicating with the master. That second socket has 
to be AF_INET for portability. It could be TCP or UDP. A connected UDP 
socket may be most appropriate and seems worth trying.

2. If something happens to the master thread so that it determines that 
the application should shut down it would iterate over the sockets to 
the workers and tell each one to shut down. It would then shut itself 
down. (Am not sure at the moment whether to wait for the worker 
threads.)

3. A worker thread, being told to shutdown (basically a single byte 
received from the master thread) would tell its client to close the TCP 
connection and then it would wait a little while for it to do so - maybe 
a second or two. When the client closes the TCP connection (or the 
timeout wait period expires) the worker thread will close its end and 
exit.

> Bear in mind, though, that Windows has no protection against other
> processes shutting you down. You can restrict it to 127.0.0.1 (of
> course) but any program running on the same computer as the server -
> regardless of user permissions etc - will be able to connect to your
> sockets.

I was thinking of a connected UDP socket. That way, AIUI, at least in 
the absence of forged datagrams, only the master thread will be able to 
communicate with the worker, due to connected UDP sockets demulitplexing 
datagrams based on their source as well as their destination, i.e. on a 
5-tuple (UDP, source IP, source port, destination IP, destination port).

> So it might be best to do something like this (all on the
> main thread):
>
> 1) Open a listening socket
> 2) Connect to the listening socket
> 3) Accept a connection
> 4) Close the original listening socket
> 5) Spin off all your threads, passing them the socket from step 2
> 6) To terminate them all, write a byte to the socket from step 3.

That sounds similar to what I had in mind but I am not sure why you 
would close the listening socket. Connections could come in at any time 
and threads could therefore be needed at any time so I was thinking that 
the master thread (the one with the listening TCP socket) would just sit 
waiting for new connection requests (or an interrupting signal).

In reality, due to Windows not recognising signals while in the accept() 
call I think there would be a real master thread and a listening thread 
but I have omitted that in the descriptions above. As far as the normal 
worker threads are concerned they would be ready to be told to shut down 
by the listening thread, and it would be ready to be told to shut down 
by the master thread. Still with me? ;-)

> This will make it difficult for ordinary userspace code to mess with
> you. It'd still be possible, I think, for something with raw sockets
> access to feign a termination signal; I have no idea what protections
> Windows offers you there.

Yes, something which could forge a packet could tell a worker to close 
down. I don't think there's any significant problem here, thought, 
because:

* other programs are similarly vulnerable to forged packets
* the only forgery effect is to tell a worker thread to stop - not a big 
loss
* the shutdown protocol would/should cause the client to re-request
* a forger would have to know the specific port number used by the 
master thread to communicate with that particular worker, and the port 
number that worker was using.

Overall, I think it would be more than robust enough.

Notwithstanding your comment about a single socket, above, no one seems 
so far to have objected to the number of sockets this would need, which 
was my main concern, so that's good!

James



More information about the Python-list mailing list