the requirements for message-mode named pipes semantics on top of unix / wine brings some... interesting limitations on how it can be implemented, and i believe that i have finally come up with something that would fit the requirements: the socketpair equivalent of "double-buffering".
as the implementation of this idea would involve changes to (doubling-up) of the wineserver namedpipe state machine, and after the significant amount of time and resources spent (resulting in loss of personal financial income somewhere in excess of £3,000) i'm happy to commit further time _with_ active cooperation and engagement from wine developers, in adding this ... rather strategically important and complex functionality.
so - here's a description of the idea and its background: your input into poking at it with a stick and discussing how it can be achieved greatly appreciated.
background -------------------
the first (successful) attempt at adding "technically correct" named pipes message-mode semantics brought up several issues:
1) due to multiple threads being able to read from the same pipe, receiving of messages cannot be atomically done by reading a "header" indicating the length of the message (unless there is a per-pipe mutex, which is a bit too much to be adding and would slow things down). one thread would read the header, indicating the beginning of the message; the other thread would read the beginning of the pipe data and _treat_ it as the header.
2) the data cannot be read inside wineserver itself due to the requirement to ensure that wineserver never blocks on read (which would be fatal). write really isn't ok, either, due to asynchronicity possibilities on EPIPE etc. would require a loop, thus delaying further responses, or it would require a state machine (messy).
3) breaking individual messages into separate socketpair() pipes is "technically correct" but quickly results in wineserver running out of filedescriptors!
4) changing the filedescriptor from BLOCKING to O_NONBLOCK in order to do a poll() inside wineserver (in order to do a read()) is mutually exclusively incompatible with having a userspace thread perform a blocking read operation on the same socket, waiting for a new message.
logical deduction of design ------------------------------------------
so, it was made clear by the socketpair()-queue experiment that messaging semantics _can_ be achieved - without any read/write operations being performed by wineserver itself, and so the next logical step is to limit the number of socketpairs used to just two.
i.e. four filedescriptors per named pipe: two for the server-side (CreateNamedPipe), and two for the client-side (NtCreateFile).
the use of this "double-buffering" will, i believe, make it possible for the "blocking on read" semantics to be achievable. effectively, the "first" socketpair replaces the "tail" of the socketpair()-queue experiment.
however, in order to make _that_ work (i.e. to preserve the message boundaries), writes to the "first" socketpair will require a header (4-byte length) to be prefixed to the message data.
BUT - and this is the really important bit - when the data is transferred from the first socketpair to the second, the header is NOT sent, for the recipient to read.
otherwise, exactly as is done in the current socketpair-queue experiment: the data structures are locked, marked with the "available data", unlocked, and _then_ the write to the secondary socketpair is done. on a read, the data structures are locked, a wineserver message sent requesting that the amount read is to be subtracted from "available data", and then unlocked.
when the "available data" reaches zero, that's the signal indicating that it's time to try reading from the first socketpair to fetch the next message (again, stripping its header).
the piper --------------
you may have noticed that there's nothing mentioned so far about _how_ the data is to be transferred between the pairs of socketpairs.
we've already established that it cannot be wineserver that does the transfer (because of blocking / nonblocking mutually exclusive issues and asynchronous issues, already outlined)
this is actually good news in disguise.
conclusion: a *SEPARATE APPLICATION* must be responsible for ferrying the data between the two socketpairs. for all named pipes.
a diagram outlining this all together is here:
http://lkcl.net/namedpipes/wine-piper-design.pdf
exactly how the client and server "signal" to the piper that a new message is required is yet to be determined, but the simplest way it could be achieved would be by instead of sending <length-header> <data> you send:
<2-byte command> <length-header> <data>
where in the case of "i want piper to wake up!" you send <0x0001> <0x00000000> (no more data)
and in the case of "i want to write a message" you send <0x0002> <0x0000NNNN> <data>
a ping, effectively.
The Good News ------------------------
here's the good bit about using the piper to transfer data in userspace: you don't _have_ to have the client-side (or the server-side) come _exclusively_ from wine.
in other words, you have an opportunity to put in "break-out" mechanisms! yippeee, the piper is the perfect place to put in SMB Client library usage, or links to SMB IPC$ "proxy" pipe mechanisms for communication with SMB servers :)
and the even _better_ news is that it doesn't have to be done straight away. all that the "first version" of the piper need to is "data in, data out. data in, data out". nothing more.
the even better news than _that_ is that the "first version" of the piper can be utterly, utterly, simple, single-process, not even any threading. one message at a time. this simple implementation provides absolute guaranteed avoidance of race conditions, overlaps between reads and writes by the client or server threads, and more.
_later on_ the possibility can be investigated to provide a more sophisticated version of the piper that is multi-threaded and has per-pipe mutexes to ensure that it is _per pipe_ that there is guaranteed avoidance of race conditions etc.
Another Possibility ----------------------------
once the need for the piper is made clear, there exists a potential solution, providing named pipe message-mode on top of the _existing_ infrastructure with very little changes to ntdll, kernel32 and wineserver. it goes something like this:
* make the existing namedpipe infrastructure the "layer below" NamedPipes
* utilise the existing infrastructure, creating pipe-pairs (one for client, one for server) where the piper makes the back-to-back connection between the two
* i.e. "Real" Named Pipes are *only* allowed to connect to the piper; the piper is the *only* application that is allowed to send data onwards to "real" clients.
* the provision of "Real" message-mode Named Pipes, on top of this infrastructure, can then be done by doing a (very) mini RPC system over the pairs of NamedPipes.
the reason for doing a mini RPC system is that this method is a proven entity, by principle of implementing MSRPC on top of the existing namedpipes infrastructure, when that infrastructure has no support for MessageMode!
the reason _why_ it works is because DCE/RPC has the PDU as its fundamental "synchronisation" system, thus doing away with the need for messaging boundary encapsulation, but hey, that's what MS implemented, that's what we get.... *sigh*.
so - what do people think? would you agree that a user-space pipe "proxy" is an effective solution?
l.
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
so - what do people think? would you agree that a user-space pipe "proxy" is an effective solution?
No, you are on the wrong track. That solution is ugly, inefficient, and it doesn't help anything since the wineserver constraints that you are trying to avoid obviously apply just as well to your proxy process.
On Wed, Mar 4, 2009 at 2:23 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
so - what do people think? would you agree that a user-space pipe "proxy" is an effective solution?
No, you are on the wrong track. That solution is ugly, inefficient, and it doesn't help anything since the wineserver constraints that you are trying to avoid obviously apply just as well to your proxy process.
how would you envisage doing client-side SMB named pipes?
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
On Wed, Mar 4, 2009 at 2:23 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
so - what do people think? would you agree that a user-space pipe "proxy" is an effective solution?
No, you are on the wrong track. That solution is ugly, inefficient, and it doesn't help anything since the wineserver constraints that you are trying to avoid obviously apply just as well to your proxy process.
how would you envisage doing client-side SMB named pipes?
By doing the I/O through the wineserver. It has all the necessary mechanisms already.
how would you envisage doing client-side SMB named pipes?
By doing the I/O through the wineserver. It has all the necessary mechanisms already.
ok - great. whereabouts? which ones? any existing examples? which existing code in wineserver utilises the existing mechanisms to which you refer?
the reason i ask is because such mechanisms could also be used, if they are filedescriptor-based, to do communication with samba franky unix-domain-sockets.
but, also, i need to know, to evaluate the mechanisms you mention, and work out how to use them.
l.
p.s. if they're asynchronous mechanisms, i can't stand asychronous designs, i had it up to ^here^ spending nearly 18 months implementing a single-process asynchronous nmbd (which is basically a DNS server and client, rolled into one). i didn't know any better so i cheerfully did it. so i'd be happy to help design an asynchronous message-mode namedpipe design but would in no way want to be part of its actual implementation.
p.p.s. that's why i did a synchronous design for "the piper".
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
how would you envisage doing client-side SMB named pipes?
By doing the I/O through the wineserver. It has all the necessary mechanisms already.
ok - great. whereabouts? which ones? any existing examples? which existing code in wineserver utilises the existing mechanisms to which you refer?
Look at the ioctl support.
On Wed, Mar 4, 2009 at 10:14 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
how would you envisage doing client-side SMB named pipes?
By doing the I/O through the wineserver. It has all the necessary mechanisms already.
ok - great. whereabouts? which ones? any existing examples? which existing code in wineserver utilises the existing mechanisms to which you refer?
Look at the ioctl support.
ok - great. will do. i'll come back with further questions when i have worked out what you're hinting at.
anyone else who is also interested in seeing a "better" design: i trust that they will also be looking at the ioctl support in wineserver with a view to being in a good position to contribute to the better design.
l.
On Wed, Mar 4, 2009 at 2:23 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
so - what do people think? would you agree that a user-space pipe "proxy" is an effective solution?
No, you are on the wrong track. That solution is ugly, inefficient, and
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
No, in many cases efficiency needs to be taken into account in the design phase. You can't just add it later.
On Wed, Mar 4, 2009 at 6:10 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
No, in many cases efficiency needs to be taken into account in the design phase. You can't just add it later.
sure you can. by redesigning.
and because the functionality is encapsulated, fulfilling the requirements behind a well-documented immutable API, other teams can move forward (even if they're complaining about speed) opening up entirely new areas of functionality and opportunities for Wine, bringing in more interested developers, one of whom _might_ be skilled enough and interested enough to go "that design - it's crap! i can do better!" and thus you get a better, more efficient and much more acceptable ...
_incremental_ improvement.
so by shutting the door on an idea because it's "inefficient" and "not nice" you risk losing my input, and an opportunity to get the ball rolling.
i'm not interested at this stage in making a "nice or efficient" design, i'm interested in getting a "technically correct" design - and a reliable, working implementation.
l.
2009/3/5 Luke Kenneth Casson Leighton lkcl@lkcl.net:
On Wed, Mar 4, 2009 at 6:10 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
No, in many cases efficiency needs to be taken into account in the design phase. You can't just add it later.
sure you can. by redesigning.
So you're saying that your original design is wasted effort? If it CAN be redesigned to be efficient, nice, sensible and correct, it's worth doing that from the start, especially in a big project such as Wine.
On Thu, Mar 5, 2009 at 3:06 AM, Ben Klein shacklein@gmail.com wrote:
2009/3/5 Luke Kenneth Casson Leighton lkcl@lkcl.net:
On Wed, Mar 4, 2009 at 6:10 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
No, in many cases efficiency needs to be taken into account in the design phase. You can't just add it later.
sure you can. by redesigning.
So you're saying that your original design is wasted effort?
no, i'm saying that it opens up the doors to the next level for wine - networked msrpc interoperability.
If it CAN be redesigned to be efficient, nice, sensible and correct, it's worth doing that from the start, especially in a big project such as Wine.
yes it would be nice, wouldn't it.
however, if there's a nicer design that would involve _more_ effort on my part rather than less, then offers of money should accompany the requests to implement the better design, to compensate me for the additional time spent.
if however the nicer design turns out to involve _less_ effort on my part, i'm very very happy.
l.
2009/3/5 Luke Kenneth Casson Leighton lkcl@lkcl.net:
On Thu, Mar 5, 2009 at 3:06 AM, Ben Klein shacklein@gmail.com wrote:
2009/3/5 Luke Kenneth Casson Leighton lkcl@lkcl.net:
On Wed, Mar 4, 2009 at 6:10 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
No, in many cases efficiency needs to be taken into account in the design phase. You can't just add it later.
sure you can. by redesigning.
So you're saying that your original design is wasted effort?
no, i'm saying that it opens up the doors to the next level for wine
- networked msrpc interoperability.
But if you already admit that your original design needs a complete redesign, what makes you think Wine should even consider your first design?
If it CAN be redesigned to be efficient, nice, sensible and correct, it's worth doing that from the start, especially in a big project such as Wine.
yes it would be nice, wouldn't it.
however, if there's a nicer design that would involve _more_ effort on my part rather than less, then offers of money should accompany the requests to implement the better design, to compensate me for the additional time spent.
You seem to be confusing "opensource developed by volunteers" with "commercial project developed by employees".
You mention "incremental improvements" several times, but there have already been objections to your design *from the project leader*. This means that if you do go through with an implementation based on this design, you will be wasting your time and effort, as it will never be accepted upstream.
if however the nicer design turns out to involve _less_ effort on my part, i'm very very happy.
More effort is required in researching and developing the design (because you already have a rejected design). But if the "nicer" design is done well, it will be _less_ effort to implement, and a lot less effort for other people to interpret and maintain should they need to. This is not *your* project; it's opensource, and AJ has strict rules on quality of code that anyone contributing patches has to deal with.
I'm not trying to discourage you from presenting and/or implementing a good design, just trying to address some misconceptions you seem to have about the Wine project and software development in general.
Luke Kenneth Casson Leighton wrote:
On Wed, Mar 4, 2009 at 6:10 PM, Alexandre Julliard julliard@winehq.org wrote:
Luke Kenneth Casson Leighton lkcl@lkcl.net writes:
i would imagine that inefficient is the _last_ thing on the list of priorities. "technically correctly fulfilling the semantics" i would imagine would be the highest priority.
"efficient" and "nice" can always be done later, yes?
No, in many cases efficiency needs to be taken into account in the design phase. You can't just add it later.
sure you can. by redesigning.
Since I deal with that on a daily basis, I'll step in. A great design is one that does EVERYTHING right the first time. What you are proposing goes counter to this and is unacceptable. Do it right the first time and you don't have to revisit, revisit and revisit some more.
In other words: AJ is right, you are just looking for the easy way out. Not a good idea and others end up cleaning up when the users start whining.
James McKenzie
sure you can. by redesigning.
Since I deal with that on a daily basis, I'll step in. A great design is one that does EVERYTHING right the first time.
have you heard of incremental improvements?
What you are proposing goes counter to this and is unacceptable.
have you heard of incremental improvements?
Do it right the first time and you don't have to revisit, revisit and revisit some more.
have you heard of incremental improvements?
In other words: AJ is right, you are just looking for the easy way out.
yes. don't like it, pay me money. problem solved.
Not a good idea and others end up cleaning up when the users start whining.
ok.
1) you are confusing a "faulty" implementation with a "technically incorrect" implementation. "revisit more and more and more" has implicity within it the assumption that there will be "something wrong" with The Piper design, such that it will require more and more and more work to make it work.
in this regard, you are dead wrong.
i expect someone else to RIP OUT the ENTIRE design, replacing it with a quotes better quotes one.
replacing it with one that identically fulfils the requirements.
and you will have the advantage, in the mean-time, of being able to "move on". "move forward". admittedly with a few whiners but they can be silenced with "if you don't like it, fix it".
2) if you would like me to spend more of my personal time on something that would take more effort, you need to accompany such requests by offers of payment, to compensate me for the additional work.
so.
moving on: would anyone like to provide details on an alternative design proposal for message-mode named pipes that involves an implementation inside wineserver (using the infrastructure that alexandre hinted could be used - the ioctl infrastructure)?
l.