views:

352

answers:

5

I'm writing a driver that communicates with a userland application through a named pipe. The userland application creates the named pipe by calling CreateNamedPipe() and then passes the pipe name to the driver by invoking an IOCTL. The driver then opens the pipe by calling ZwCreateFile().

The userland application then hits a loop that reads requests from the pipe, processes the requests and writes back the result to the pipe i.e.:

while(1) {
ReadFromPipe
ProcessRequest
WriteToPipe
}

The driver basically writes requests to the pipe and then directly reads back the answer:

WriteRequestToPipe
ReadAnswerFromPipe

My problem is that if the ReadAnswerFromPipe happens in the driver before the WriteToPipe happens in the application, ReadAnswerFromPipe never returns. So basically doing

WriteRequestToPipe
Sleep(10 seconds)
ReadAnswerFromPipe

fixes the problem.

Why am I seeing this?

Clarification: I'm using two different unidirectional pipes and the ReadAnswerFromPipe call is never returning although the application eventually successfully calls WriteToPipe...

+2  A: 
ephemient
that does not answer my question
anon
A: 

ephemient is correct. You could stick with a single pipe but then you'd have to synchronise reads and writes between the two ends. The added sleep appears to be working for you as it is allowing the request to be read before the answer is read - but this is error prone as a delay on one end could cause errors.

Stephen Nutt
that does not answer my question
anon
+1  A: 

Not knowing what version of Windows you're writing for, or what development environment you're in, I'm not sure this will necessarily help, but it might.

If you're guaranteed to get a response from your user app every time you send the request from your driver, you might consider using the API function TransactNamedPipe() (see this page in the MSDN for full usage documentation).

It is specifically meant to do a send/receive and will wait until a response comes back before returning.

Alternatively, you can use this function in 'overlapped' mode, in which case it will return immediately, after which you wait on an event - that you have to pass in as part of a 'TransactionOverlapped' structure in the original call - to know that you've received your answer.

Wilson Fowlie
I've tried doing it async in the driver, calling ZwWaitForSingleObject on the File handle but I still get the same issue (ZwWaitForSingleObject never returns...)Thanks anyways
anon
+10  A: 

Since named pipes support one-way communication at any given time, you will have to either use 2 pipes (as already suggested) for true asynchronous acces, or synchronize access to a single pipe (like a walkie-talkie). A semaphore object should work well for that. If you just set the Maximum Count parameter of CreateSemaphore() to 1 it will act as a binary semaphore. You can then ZwWaitForSingleObject() on that semaphore inside your while(true) message loop on both your client and server and you will have synchronized access.

Edit: Just remembered you are writing a driver as the server component of this, so you will need the kernel-specific functions and structs, the KSEMAPHORE struct on the driver side.

Dale Halliwell
Named pipes are bi-directional if you specify `PIPE_ACCESS_DUPLEX` at creation! I use that myself, too.
Anton Tykhyy
+2  A: 

It is better to use IOCTL for communication with userland. Why do you need pipes?

Sergius