6

I have an implementation of a bi-directional message channel which, to reduce overhead, I implemented as a couple of circular buffers of messages. To write from one end to the other you add the pointer to the message to one circular buffer and tweak the read and write indices for it. To write in the other direction you do the same for the other buffer and so on. The code is small and simple and it avoids the overheads of using a pipe or fifo, although possibly that might have been a better solution in some ways.

I implemented a poll on this by simply checking if there was a message waiting to be read, and if not doing a timed wait on a condition variable that gets signalled when a message is added to the relevant array.

Now I have an application that needs to wait on a socket (more or less) and on the message channel at the same time. I now wish I had used a fifo or pipe, but due to overhead in getting the code changed (long story), it's not really feasible to rewrite it to use a fifo or pipe.

Is there any way to get a file descriptor associated with a conditional variable? If so it is easier to implement a poll on two file descriptors at once, one for the conditional variable and one for the socket.

Out of curiosity, and making this question more useful to others with a similar problem, is it possible to get a file descriptor associated with a semaphore so you could poll on the semaphore and a regular file descriptor at the same time?

AlastairG
  • 4,119
  • 5
  • 26
  • 41
  • 3
    I would guess that the fix in your case is to create a pipe, then start a thread to wait on the condvar and write a byte to the pipe when the associated condition becomes true. Then you can poll on the socket and the pipe. If you want to generalize that code and call it "getting a fd for a condition variable", then yes, you can get a fd for a condition variable ;-) – Steve Jessop Dec 02 '10 at 14:10
  • @Steve, That's even more of a hacky idea than JeremyP's! Create a thread?!? Just for that!? I'm glad the smiley shows you were joking :) – AlastairG Dec 02 '10 at 15:20
  • @AlistairG: shrug. You're the one who said you didn't want to change the existing code that posts the condvar, so writing a different receiver is all there is. Granted, jpalacek's idea of waiting on the condvar normally, but receiving signals for the socket activity to interrupt that wait, saves the thread. Adding threads is the most general way to change blocking ops to asynchronous ones, though, so unless there's a low thread limit on your system I don't think there's any need to get hysterical over it :-) – Steve Jessop Dec 02 '10 at 16:17
  • 1
    Steve you should have posted that as an answer. Given the OP's requirement of not fixing the underlying problem, your answer is probably the most correct. – R.. GitHub STOP HELPING ICE Dec 02 '10 at 16:47

3 Answers3

9

Generally, no. But different OSes offer different solutions for the problem you have.

Windows

You can associate an event with a socket with WSAEventSelect and wait with WaitForMultipleObjectsEx for the data on the socket or mutex or semaphore event etc.

Linux

You can use the futex syscall with FUTEX_FD argument (however this has been removed from the kernel), or use eventfd to implement the condition variable.

And you can spawn a second thread that would be waiting on the condition variable, and signal the one waiting in select(). Or ask for signals when input is received on the socket, etc. See this related question.

Community
  • 1
  • 1
jpalecek
  • 47,058
  • 7
  • 102
  • 144
2

A file descriptor is an index into a kernel-managed array of open files and similar objects (pipes, FIFOs, sockets), so it's not possible to associate a file descriptor with anything not managed by the kernel.

If your message channels and semaphores are entirely in user space (implemented in your own application with recourse to system calls), then you can't get a file descriptor for it. Sorry.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • The semaphore/condition variable is a kernel object. Well actually it's third party code layered on pthreads which is layered on a kernel object, but the layers all give access to the layer below, so I can dig down. Which basically brings me back where I started which is whether the kernel will allow you to obtain a file descriptor for the object. I guess since file descriptors have inherent read and write properties, and semaphores and condition variables, don't that the asnwer is therefore no. Thanks for an answer that clarified my mind. – AlastairG Dec 02 '10 at 15:23
2

It's a bit of a hack, but you could replace your condition variable with a pipe. The read thread would poll/select on the read side and the socket. The thread that writes to your buffer also writes a byte to the pipe to signal there is stuff in the buffer.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • This particular piece of software already has too many hacks. It crashes far too much. It's a case of a team developing a prototype and then management putting so much pressure on that the product development continues with the prototype rather than going back to the beginning and writing it properly :( I don't want to talk about it. It's too depressing. Your idea is workable, but if I was going to put a pipe in there I may as well replace the message channel itself with a pipe! – AlastairG Dec 02 '10 at 15:19