anon
anon

Reputation: 641

Windows Named Pipe Problem

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...

Upvotes: 2

Views: 2555

Answers (5)

Sergey Podobry
Sergey Podobry

Reputation: 7189

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

Upvotes: 1

Dale
Dale

Reputation: 13024

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.

Upvotes: 7

Wilson F
Wilson F

Reputation: 1260

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.

Upvotes: 1

Stephen Nutt
Stephen Nutt

Reputation: 3306

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.

Upvotes: 0

ephemient
ephemient

Reputation: 204778

Pipes are generally taken to be uni-directional communications channels.

I believe that the easiest solution for you would be to create two pipes: one for application→driver messages, and one for driver→application messages.

Upvotes: 3

Related Questions