|
dxd - dynax driver framework 2.7.0d222
cross platform open source driver development framework
|
pipe - Windows named pipes A dx::pipe is a bidirection, multi-client, multi-threaded communication channel between a pipe client and a pipe server. Both pipe sides feature a dedicated read thread to receive data from the opposite side notifiying installable listener std::functions. On the service side, a pipe server is instantiated for each pipe client connection. Until a new client connects, the pipe::server::instance remains waiting in pipe::server::instance::connect within its dedicated pipe read thread. If a client disconnects the pipe::server::instance terminates its read thread and is joined and released by the next pipe::server::run() or pipe::server::stop(). The pipe::server::instance super class can be template-parameterized to allow mimicking user client behaviour. Windows arbitrarily serializes operations on synchronous pipe handles, limiting it's named pipe concurrent synchronous operation capabilities to exactly one synchronous pipe per process (i.e. exactly one per process), effectively forcing both the pipe::server and the pipe client to be implemented using asynchronous OVERLAPPED I/O — introducing a whole host of unnecessary pitfalls and awkward behaviors. However, the MSDN documentation here apparently describes a different piece of software. Though dx::pipes can be used for any communication between user space software its purpose is to allow Windows service communication. A service itself runs with elevated privileges, whereas the clients typically run in the normal user context. Therefore, the pipe servers have defined their default ACLs for non-privileged access. More...
#include <dx_pipe.h>
Classes | |
| struct | access |
| class | server |
| server - accepts multiple concurrent pipe client connections Each accepted connection is served by its own pipe::server::instance, running on a dedicated read thread. run() keeps exactly one instance listening for the next client at all times: once ConnectNamedPipe() accepts a connection, that instance's own thread calls server::run() again - reaping already-concluded instances and spawning the next listener - before servicing its own connection. A concluded instance (client disconnected) therefore joins only at the start of the next run(), on a different thread: a std::jthread cannot join itself, so reaping cannot happen from within the concluding instance's own read thread. An otherwise idle server thus keeps its most recently used instance around until either the next connection or stop(), which unconditionally joins every instance - connected or not - synchronously before returning. More... | |
| class | status |
Public Member Functions | |
| dx_catchall_rethrow () virtual void free() noexcept | |
| operator const os_event () const noexcept | |
| operator os_event () noexcept | |
| operator::HANDLE () const noexcept | |
Protected Member Functions | |
| dx_catchall_rethrow (, "%s: handle:%llx access:%x:%x:%x:%x", id.c_str(), handle, access[0], access[1], access[2], access[3]) void free() noexcept override | |
| template<typename snd_t> | |
| const snd_t & | operator<< (const snd_t &snd) |
| pipe (const std::string &id, decltype(listen)::listeners &&listeners={}, const ::DWORD(&access)[4]=access::dflt) | |
| virtual void | read (std::stop_token stop_token) noexcept try |
| void | run () try |
| ::ULONG | session () const |
| template<typename rcv_t> | |
| dx::pipe::status promoted | this (const os_result &value) |
| ~pipe () override | |
Protected Attributes | |
| ::DWORD | access [4] {} |
| shared::event | attach {id} |
| overlapped | connect |
| dx::pipe::status | ERROR_PIPE_BUSY |
| ::HANDLE | handle = invalid_t |
| std::string | id |
| overlapped | in |
| dx_catchall(, "%s: handle:%llx", id.c_str(), handle) public listen< std::function< void(const rcv_t &)> > | listen |
| overlapped | out |
| bool | overlapped {} |
| ::HANDLE | process = ::GetCurrentProcess() |
| event< user > | read_thread_started {} |
| std::stop_callback< std::function< void()> > | stop_callback {this->get_stop_token(), [this](){this->free();}} |
| class dx::pipe::server | this |
pipe - Windows named pipes A dx::pipe is a bidirection, multi-client, multi-threaded communication channel between a pipe client and a pipe server. Both pipe sides feature a dedicated read thread to receive data from the opposite side notifiying installable listener std::functions. On the service side, a pipe server is instantiated for each pipe client connection. Until a new client connects, the pipe::server::instance remains waiting in pipe::server::instance::connect within its dedicated pipe read thread. If a client disconnects the pipe::server::instance terminates its read thread and is joined and released by the next pipe::server::run() or pipe::server::stop(). The pipe::server::instance super class can be template-parameterized to allow mimicking user client behaviour. Windows arbitrarily serializes operations on synchronous pipe handles, limiting it's named pipe concurrent synchronous operation capabilities to exactly one synchronous pipe per process (i.e. exactly one per process), effectively forcing both the pipe::server and the pipe client to be implemented using asynchronous OVERLAPPED I/O — introducing a whole host of unnecessary pitfalls and awkward behaviors. However, the MSDN documentation here apparently describes a different piece of software. Though dx::pipes can be used for any communication between user space software its purpose is to allow Windows service communication. A service itself runs with elevated privileges, whereas the clients typically run in the normal user context. Therefore, the pipe servers have defined their default ACLs for non-privileged access.
Each of the following states covers a distinct scope; none is derivable from another: handle no pipe open status last OS result; drives connection and requests the read thread's stop on connection loss connection connected/disconnected, awaitable by users of the pipe attach cross-process: a server instance exists, so a pending CreateFile() retry may proceed read_thread_started run() returns only once its read thread entered stop_token this read thread is to end - one connection ending, not the server server::stopping the server as a whole is shutting down and suppresses instance respawn instance::concluded read() returned holding no lock, so the instance joins without blocking
Windows "design" oddities If the pipe client connects and disconnects before the overlapped GetOverlappedResult() is called a waiting GetOverlappedResult() will hang and cannot be canceled via CancelIoEx(). https://learn.microsoft.com/en-us/windows/win32/fileio/canceling-pending-i-o-operations
|
inlineprotected |
|
inlineoverrideprotectednoexcept |
|
inlinenoexceptinherited |
|
inlinenoexceptinherited |
|
inlinenoexceptinherited |
|
inlinenoexceptinherited |
|
inlineprotected |
|
inlineprotectedvirtualnoexcept |
a client connect/disconnect racing the overlapped completion leaves it unwakeable by CancelIoEx(), hence polled against the stop token
|
inlineprotected |
|
inlineprotected |
|
inlineprotected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protectedinherited |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protectedinherited |
|
protected |
|
protected |
| (c) copyright 2009 dynamic acoustics e.U. | generated on |