The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

pthreads and signals on Linux

I come from a Windows background, but I'm thinking of writing my next server project for Linux.  I have a question about signal delivery and pthreads on Linux.

I plan to have a pool of threads accepting TCP/IP client connections.  As you probably know, applications that deal with socket I/O *should* handle SIG_PIPE because this signal can be delivered when a client closes unexpectedly. 

My question is: suppose I have two threads, A and B, and A is trying to read from socket 1 while B is reading from socket 2.  If the client on the other end of socket 1 terminates his connection, which thread does the SIG_PIPE handler get run on?  I would hope thread A, and that control would return to thread A (after the read) with an error of EINTR..

Also- does POSIX have the equivalent of thread local storage?
Tom Send private email
Wednesday, December 19, 2007
Google pthread_key_create
Wednesday, December 19, 2007
Got it.  What about signal delivery? Any thoughts?
Meganonymous Rex Send private email
Wednesday, December 19, 2007
It's unfortunate that SIG_PIPE is delivered by default on tcp sockets -- it makes sense on stdin/stdout or disk files, but not on network sockets.

My advice would be to disable SIGPIPE completely (by way of signal(SIGPIPE, SIG_IGN)), and then when a socket breaks you'll just get a read() or write() error when reading or writing respectively (which .. you have to handle anyway, because some errors do not sigpipe).

Alternatively, there's a ioctl/fnctl that disables sigpipe on an fd by fd basis -- use that if you need sigpipe handling for real files.

Linux does have simple per-thread handling of signals, but not all unixes do (e.g., FreeBSD didn't last time I looked at it a couple of years ago), so it's bad practice to rely on that. If you really want to go the signal handler route, you'll have to make it unportable to other unixes, or have logic to handle the fact that the thread handling the signal is generally random.

Wednesday, December 19, 2007
Thanks, I'll probably take the ioctl()-per-handle route. 

I looked into aio_read() and aio_write() and someone told me (somewhere) that Linux doesn't _really_ do asynchronous I/O on sockets.  Does anyone know if THIS is true?

Maybe I should take a serious look at ACE.
Tom Send private email
Wednesday, December 19, 2007
In all seriousness, just turn SIG_PIPE off. It's a complete and utter waste of everyone's time.

"I looked into aio_read() and aio_write() and someone told me (somewhere) that Linux doesn't _really_ do asynchronous I/O on sockets."

The aio_ series *might* go do proper Async IO in some implementations (assuming a bundle of things, like whether the operations are aligned properly, the right filesystems are involved and all manner of other limitations).

However normally they just run the operation in another thread, but hide some of the icky from you. If you're already happy writing threads, ignore it.

Just put the sockets into non-blocking mode, use an epoll loop to find readable/writeable ones and then farm the reading work out to worker tasks. Or, the other option is to have a number of network handler threads each of which is running several connections using epoll.

Epoll is a Linux-only beefed-up select which basically means you can manage huge arrays of FDs and just run round servicing them - we often have thousands or tens of thousands of connections hooked into the sets and it's all peachy.
Katie Lucas
Thursday, December 20, 2007
"which thread does the SIG_PIPE handler get run on?"

Completely uncontrollable. Which is why it's useless.

"Also- does POSIX have the equivalent of thread local storage?"

pthread_key_create, pthread_getspecific and pthread_setspecific are your starting points here; basically you use the first to create a "key". The key you share across the threads -- but each of the "sees" its own specific storage. The other two get and store thread specific values against the key. When you create the key you can add a destructor which is called at thread end passing your stored value in (so you can clean up).
Katie Lucas
Thursday, December 20, 2007
Katie- Thanks, I'll check out epoll.
Tom Send private email
Thursday, December 20, 2007

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz