PDA

View Full Version : How can I cancel bloking operation with accept() ?


Yutaka Takeda
02-19-2003, 10:28 PM
My TCP application uses bloking functions and works fine until when it tries to remove a listener socket. I am calling close() from another thread (using pthread) to close listener socket with an expectation of that the accept() function would return. (Windows works well with this way.) However, it does't return in Unix environment.

Please let me know the proper way to cancel the accept operation.

Thanks in advance.
--
Yutaka :(

mlampkin
02-22-2003, 11:38 AM
Most systems will keep a socket open as long as there is one process with a reference to it... the deal being that, while you may be using threads in your program, many of the unix derivatives treat threads as processes internally (for creation, scheduling and so forth)... end result being closing it in one thread does not cause another thread to fault out / exit from accept( ) with an errno...

Ok... so thats means the "windows way" of doing things won't work... there is another way though and that is to send a signal (using e.g. pthread_kill) to the thread stuck in accept... this will cause accept to return with a -1 and an errno of EINTR...

If you ran out and checked that on some boxes (Linux is just one of many) without reading the rest of this message... you've probably discovered it didn't work...

If it didn't work, the system you are on uses BSD style signals which means system calls are by default automatically restarted... to get around this I would suggest you try using sigaction to set an appropriate signal handler and make certain you do not use the SA_RESTART flag (you may have to define _XOPEN_SOURCE 600 as the first thing in your code to get that flag)... also make certain all other threads are masking out the signal you are using so you know it will get delivered to the appropriate target... and be aware that not just accept, but any interruptable system call in the target thread can / will be interrupted if the signal is received...

Hope that was of some assistance and wasn't too confusing... :-/

Michael

olsner
04-26-2003, 06:00 PM
I would like to use the described method (sigaction, SA_RESTART, pthread_kill) to cancel select calls, but I don't have control over all the application's threads (I'm trying to make an API)...

I want to assure that the signal only affects the thread controlled by the API, and I want to be certain that the select call is aborted.

how would I do this with sigaction? which signal do I choose?

Or, perhaps there is a better way to abort the select() loop?

I have a select loop that adds all sockets to the read-fds, and adds sockets that have a non-empty send buffer (the buffer is managed by the API) to the write-fds. The problem is that if the send buffer is empty, the select call blocks, and data is added to the buffer by another thread *while the select is blocking*, the data will not be sent until another socket has had events.

The easiest way, by far, is of course to give a timeout to select, but I don't like polling =)

RobSeace
04-26-2003, 07:32 PM
I think a nice clean method of forcing select() to return on some
condition is to always keep around a special signalling FD of some
sort (usually a pipe or Unix domain socket is best), and always
keep that in your read fd_set... Then, to force the select() to
return, you just write something down the other end, and it'll
select as readable... Then, the process/thread doing the select()
will spot that it's the special FD, and presumably know what to do
in that case... (In your case, it sounds like it doesn't really need
to do anything special, since all you wanted to do was get it to
break out of the select(), and recalculate its fd_sets... But, of
course, it'll need to read the signalling message written to the FD,
to clear it out, so it no longer selects as readable...)