Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2012-07

Inter-process communication, a cautionary tale

21 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Mark Morgan Lloyd

I was reminded of this when somebody was asking about portable signalling APIs the other day, but I think it's also relevant to discussion of e.g. how to pass a keyword to a help viewer.

I am obviously aware of the fact that FPC has an IPC unit which uses a temporary file, although I have always assumed that that was more to support targets like DOS that had absolutely no concept of pipes or sockets. But perhaps it really is the safest choice in all cases.

A couple of years ago I wrote an experimental library that used a unix-domain socket to ensure that only a single copy of a program was running, and to pass a command line from any subsequent copy to the original. In general, it worked well; and unlike TCP etc. it was inherently protected from external interference.

A couple of weeks ago, out of curiosity rather than necessity, I started looking at whether the library could be ported to Windows using MS-style named pipes. However I seem to have hit a snag since it appears that Windows can't both create a named pipe (for reading) and open the same named pipe (for writing) in the same process, something that gives unix sockets no 'm not particularly looking for sympathy, and I'm not really expecting anybody to point out that I've overlooked something obvious (although suggestions would, of course, be appreciated). I'm simply outlining this as an illustration that the complex semantics of the Windows API can, at times, bite.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

OBones
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 6 lines
A couple of weeks ago, out of curiosity rather than necessity, I started looking at whether the library could be ported to Windows using MS-style named pipes. However I seem to have hit a snag since it appears that Windows can't both create a named pipe (for reading) and open the same named pipe (for writing) in the same process, something that gives unix sockets no you show us some code here?

And what return values do you get?
I'm asking because I have distinct memories of doing just that a while back without any issue.

Reply by email

Unknown author
to Mark Morgan Lloyd: I was reminded of this when somebody was asking about portable signalling APIs the other…
Mark Morgan Lloyd wrote 8 lines
I was reminded of this when somebody was asking about portable signalling APIs the other day, but I think it's also relevant to discussion of e.g. how to pass a keyword to a help viewer. I am obviously aware of the fact that FPC has an IPC unit which uses a temporary file, although I have always assumed that that was more to support targets like DOS that had absolutely no concept of pipes or sockets. But perhaps it really is the safest choice in all cases.

In which unit did you find this ?

The IPC unit in FPC uses a unix socket on unix, and on windows a Windows window handle to copy data.

Michael.

Reply by email

Mark Morgan Lloyd
to Unknown author
Show quoted text 15 lines
On Wed, 18 Jul 2012, Mark Morgan Lloyd wrote: > I was reminded of this when somebody was asking about portable > signalling APIs the other day, but I think it's also relevant to > discussion of e.g. how to pass a keyword to a help viewer. > > I am obviously aware of the fact that FPC has an IPC unit which uses a > temporary file, although I have always assumed that that was more to > support targets like DOS that had absolutely no concept of pipes or > sockets. But perhaps it really is the safest choice in all cases. In which unit did you find this ? The IPC unit in FPC uses a unix socket on unix, and on windows a Windows window handle to copy data.

I believe I'm thinking of TSimpleIPC etc. My apologies if I've got this wrong, or if what I read was outdated "Ignorance of the law is no defense").

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Unknown author
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 19 lines
wrote: > On Wed, 18 Jul 2012, Mark Morgan Lloyd wrote: > >> I was reminded of this when somebody was asking about portable signalling >> APIs the other day, but I think it's also relevant to discussion of e.g. >> how to pass a keyword to a help viewer. >> >> I am obviously aware of the fact that FPC has an IPC unit which uses a >> temporary file, although I have always assumed that that was more to >> support targets like DOS that had absolutely no concept of pipes or >> sockets. But perhaps it really is the safest choice in all cases. > > In which unit did you find this ? > > The IPC unit in FPC uses a unix socket on unix, and on windows a Windows > window handle to copy data. I believe I'm thinking of TSimpleIPC etc. My apologies if I've got this wrong, or if what I read was outdated "Ignorance of the law is no defense").

No need to apologize, I'm just curious where you got your info from. The implementation has been the same since day 1, which means your statement puzzles me.

So instead of re-inventing the wheel, maybe have a closer look again at the standard IPC mechanisms.

Michael.

Reply by email

Mark Morgan Lloyd
to OBones: And what return values do you get? I'm asking because I have distinct memories of doing…
OBones wrote 11 lines
Mark Morgan Lloyd wrote: > A couple of weeks ago, out of curiosity rather than necessity, I > started looking at whether the library could be ported to Windows > using MS-style named pipes. However I seem to have hit a snag since it > appears that Windows can't both create a named pipe (for reading) and > open the same named pipe (for writing) in the same process, something > that gives unix sockets no problems at all. Could you show us some code here? And what return values do you get? I'm asking because I have distinct memories of doing just that a while back without any issue.

I've certainly done it to communicate between separate processes, but the difference in the current case is that the first time the program is loaded I'm enqueueing its own parameters rather than passing them via an in-memory "shortcut"... works fine in unix and seemed like a good idea at the time :-) It's strange though just how many people on StackOverflow etc. say things like "using a named pipe to communicate inside a single process is utterly pointless", it's almost as though they're parroting some doctrine the origin of which is now lost.

Basically, what I was trying to do was this. In the main thread:

     fIpcPipe:= CreateNamedPipe(PChar(fIpcName), PIPE_ACCESS_INBOUND,
                         PIPE_TYPE_MESSAGE + PIPE_READMODE_MESSAGE,
                                 1, 0, 0, 1000, NIL (* @sa *) );

That works. Fire up a background reader thread, and make sure that the main thread doesn't proceed...

     fThread:= TSphinxThread.Create(false);
     while fThread.fSyncParam = DEADBEEF DO (* Until thread has called

ConnectNamedPipe() *)

       Sleep(10);
     fThread.Suspend

..until after the Execute in the reader thread has done:

   fSyncParam := '';                     (* Let main process see that
we've started *)
{$ifndef UNIX }
   IF NOT ConnectNamedPipe(Phix.Pipe, NIL) THEN
     EXIT;
{$endif UNIX  }
   WHILE NOT Terminated DO BEGIN

I'm keenly aware of the deprecated status of calling Suspend from outside the thread, but what I'm showing there is just one attempt from many.

Finally, once the main thread is confident that the background reader has got to the point of being connected to the named pipe:

   sendPipe:= CreateFile(PChar(fIpcName), GENERIC_WRITE,
FILE_SHARE_WRITE + FILE_SHARE_READ,
                                 NIL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
   IF sendPipe = INVALID_HANDLE_VALUE THEN BEGIN
     fSlaveInitErrorNum:= GetLastError; (* 230: bad pipe. 231: pipe
busy.        *)

That invariably fails with an error 231, at which point after quite a lot of tinkering and comparison against my older code I gave up.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mark Morgan Lloyd
to Unknown author: No need to apologize, I'm just curious where you got your info from. The implementation…
Show quoted text 6 lines
No need to apologize, I'm just curious where you got your info from. The implementation has been the same since day 1, which means your statement puzzles me. So instead of re-inventing the wheel, maybe have a closer look again at the standard IPC mechanisms.

I will do, but I do note that
http://lazarus-ccr.sourceforge.net/docs/rtl/ipc/index.html explicitly says that "It works only on the linux operating system". Where's the source- I can only see ./fpcsrc/rtl/unix/ipc.pp

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

OBones
to Mark Morgan Lloyd: I've certainly done it to communicate between separate processes, but the difference in…
Mark Morgan Lloyd wrote 8 lines
Basically, what I was trying to do was this. In the main thread: fIpcPipe:= CreateNamedPipe(PChar(fIpcName), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE + PIPE_READMODE_MESSAGE, 1, 0, 0, 1000, NIL (* @sa *) ); That works. Fire up a background reader thread, and make sure that the main thread doesn't proceed...

So you are not creating the "read" pipe in the context of the thread that actually reads from it?
I'm not sure that this is actually supported, maybe you should try to create it in the context of the reading thread.

Further to this, I don't see the usage for Suspend. I mean, why suspend the reading thread? Or maybe I misunderstood what TSphinxThread is. And yes, Suspend is deprecated, but for VERY good reasons, as it can actually suspend your thread in the middle of an API call, and that is VERY dangerous.

And last, I would not use the sleep look but a simple TEvent to notify the main thread that the reader thread is ready. Much more efficient.

Reply by email

Unknown author
to Mark Morgan Lloyd: I will do, but I do note that http://lazarus-ccr.sourceforge.net/docs/rtl/ipc/index.html…
Mark Morgan Lloyd wrote 13 lines
wrote: > No need to apologize, I'm just curious where you got your info from. The > implementation has been the same since day 1, which means your statement > puzzles me. > > So instead of re-inventing the wheel, maybe have a closer look again at the > standard IPC mechanisms. I will do, but I do note that http://lazarus-ccr.sourceforge.net/docs/rtl/ipc/index.html explicitly says that "It works only on the linux operating system". Where's the source- I can only see ./fpcsrc/rtl/unix/ipc.pp

I meant the SimpleIPC unit from the FCL:
http://lazarus-ccr.sourceforge.net/docs/fcl/simpleipc/index.html

Michael.

Reply by email

Mark Morgan Lloyd
to OBones: So you are not creating the "read" pipe in the context of the thread that actually reads…
OBones wrote 13 lines
Mark Morgan Lloyd wrote: > Basically, what I was trying to do was this. In the main thread: > > fIpcPipe:= CreateNamedPipe(PChar(fIpcName), PIPE_ACCESS_INBOUND, > PIPE_TYPE_MESSAGE + PIPE_READMODE_MESSAGE, > 1, 0, 0, 1000, NIL (* @sa *) ); > > That works. Fire up a background reader thread, and make sure that the > main thread doesn't proceed... So you are not creating the "read" pipe in the context of the thread that actually reads from it? I'm not sure that this is actually supported, maybe you should try to create it in the context of the reading thread.

I agree, but ever since threads were introduced (OS/2 v1 or perhaps even earlier) doctrine has had it that ownership (of memory, handles and so on) was by process while state (stack content and runability) was by thread.

Other points noted, in particular that my problem might be that I can't distribute certain types of activity over threads rather than (as I initially assumed) that things had to be distributed over multiple processes.

In any event, I can get away without having this working. If I do manage to hack it at some point I'll try to remember to report back.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mark Morgan Lloyd
to Unknown author: I meant the SimpleIPC unit from the FCL: http://lazarus-ccr.sourceforge.net/docs/fcl/simpl…
Show quoted text 19 lines
On Wed, 18 Jul 2012, Mark Morgan Lloyd wrote: > wrote: > >> No need to apologize, I'm just curious where you got your info from. >> The implementation has been the same since day 1, which means your >> statement puzzles me. >> >> So instead of re-inventing the wheel, maybe have a closer look again >> at the >> standard IPC mechanisms. > > I will do, but I do note that > http://lazarus-ccr.sourceforge.net/docs/rtl/ipc/index.html explicitly > says that "It works only on the linux operating system". Where's the > source- I can only see ./fpcsrc/rtl/unix/ipc.pp I meant the SimpleIPC unit from the FCL: http://lazarus-ccr.sourceforge.net/docs/fcl/simpleipc/index.html

Because I was exploring various unix-domain socket aspects including mtu, where they're put, how to recover if an inactive one's already there (e.g. gdb failure) and so on. And in particular I was exploring naming issues that were being fouled up by things like Mozilla, trying to find some balance between the name of the project (known at compilation time) and the name of the executable after this sort of thing had caused a lot of local hassle.

So I think you've done better having something that is portable and is coded fairly elegantly, but I don't think that I've gratuitously reinvented the wheel.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Michael Van Canneyt
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 31 lines
wrote: > On Wed, 18 Jul 2012, Mark Morgan Lloyd wrote: > >> wrote: >> >>> No need to apologize, I'm just curious where you got your info from. The >>> implementation has been the same since day 1, which means your statement >>> puzzles me. >>> >>> So instead of re-inventing the wheel, maybe have a closer look again at >>> the >>> standard IPC mechanisms. >> >> I will do, but I do note that >> http://lazarus-ccr.sourceforge.net/docs/rtl/ipc/index.html explicitly says >> that "It works only on the linux operating system". Where's the source- I >> can only see ./fpcsrc/rtl/unix/ipc.pp > > I meant the SimpleIPC unit from the FCL: > http://lazarus-ccr.sourceforge.net/docs/fcl/simpleipc/index.html Because I was exploring various unix-domain socket aspects including mtu, where they're put, how to recover if an inactive one's already there (e.g. gdb failure) and so on. And in particular I was exploring naming issues that were being fouled up by things like Mozilla, trying to find some balance between the name of the project (known at compilation time) and the name of the executable after this sort of thing had caused a lot of local hassle. So I think you've done better having something that is portable and is coded fairly elegantly, but I don't think that I've gratuitously reinvented the wheel.

I never meant to imply that; I just hoped that by pointing you to some existing code, I could stop you from spending time on something which already exists.

Of course, time spent learning APIs is never wasted :)

Michael.

Reply by email

Mark Morgan Lloyd
to Michael Van Canneyt
Michael Van Canneyt wrote 20 lines
>> I meant the SimpleIPC unit from the FCL: >> http://lazarus-ccr.sourceforge.net/docs/fcl/simpleipc/index.html > > Because I was exploring various unix-domain socket aspects including > mtu, where they're put, how to recover if an inactive one's already > there (e.g. gdb failure) and so on. And in particular I was exploring > naming issues that were being fouled up by things like Mozilla, trying > to find some balance between the name of the project (known at > compilation time) and the name of the executable after this sort of > thing had caused a lot of local hassle. > > So I think you've done better having something that is portable and is > coded fairly elegantly, but I don't think that I've gratuitously > reinvented the wheel. I never meant to imply that; I just hoped that by pointing you to some existing code, I could stop you from spending time on something which already exists. Of course, time spent learning APIs is never wasted :)

I'll certainly take a close look at that if I come back to this problem- if nothing else to see whether it works in the context of a single process :-)

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mark Morgan Lloyd
waldo kitty wrote 17 lines
On 7/18/2012 08:48, Mark Morgan Lloyd wrote: > I was reminded of this when somebody was asking about portable > signalling APIs > the other day, but I think it's also relevant to discussion of e.g. > how to pass > a keyword to a help viewer. > > I am obviously aware of the fact that FPC has an IPC unit which uses a > temporary > file, although I have always assumed that that was more to support > targets like > DOS that had absolutely no concept of pipes or sockets. But perhaps it > really is > the safest choice in all cases. FWIW: DOS does have and has had pipes... otherwise things like DIR | MORE would not work... maybe you mean named pipes? ;)

Yes, I do. And I'm obviously aware that there are plenty of addons that graft named pipes (and mailslots etc.) onto DOS. However I always think of named pipes, threads etc. as being primarily OS/2 v1 innovations, although some might have been introduced by the obscure Microsoft OS usually referred to as "European MS-DOS v4.0".

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

OBones
to Mark Morgan Lloyd: I agree, but ever since threads were introduced (OS/2 v1 or perhaps even earlier)…
Mark Morgan Lloyd wrote 19 lines
OBones wrote: > Mark Morgan Lloyd wrote: >> Basically, what I was trying to do was this. In the main thread: >> >> fIpcPipe:= CreateNamedPipe(PChar(fIpcName), PIPE_ACCESS_INBOUND, >> PIPE_TYPE_MESSAGE + PIPE_READMODE_MESSAGE, >> 1, 0, 0, 1000, NIL (* @sa *) ); >> >> That works. Fire up a background reader thread, and make sure that >> the main thread doesn't proceed... > So you are not creating the "read" pipe in the context of the thread > that actually reads from it? > I'm not sure that this is actually supported, maybe you should try to > create it in the context of the reading thread. I agree, but ever since threads were introduced (OS/2 v1 or perhaps even earlier) doctrine has had it that ownership (of memory, handles and so on) was by process while state (stack content and runability) was by thread.

Yes, I agree, that's the basic principle with threads. But that's Win32 we are talking about here, and more often than not, things only work withing the context of the same thread, especially when it comes to resource handles.

Reply by email

waldo kitty
to Mark Morgan Lloyd: Yes, I do. And I'm obviously aware that there are plenty of addons that graft named pipes…
Mark Morgan Lloyd wrote 16 lines
waldo kitty wrote: > On 7/18/2012 08:48, Mark Morgan Lloyd wrote: >> I was reminded of this when somebody was asking about portable signalling APIs >> the other day, but I think it's also relevant to discussion of e.g. how to pass >> a keyword to a help viewer. >> >> I am obviously aware of the fact that FPC has an IPC unit which uses a temporary >> file, although I have always assumed that that was more to support targets like >> DOS that had absolutely no concept of pipes or sockets. But perhaps it really is >> the safest choice in all cases. > > FWIW: DOS does have and has had pipes... otherwise things like DIR | MORE > would not work... maybe you mean named pipes? ;) Yes, I do. And I'm obviously aware that there are plenty of addons that graft named pipes (and mailslots etc.) onto DOS.

i never used any of that... didn't need to AFAIK... just regular pipes worked fine for the times i needed them but yes, they a much different animals than named pipes...

However I always think of named pipes, threads etc. as being primarily OS/2 v1 innovations, although some might have been introduced by the obscure Microsoft OS usually referred to as "European MS-DOS v4.0".

for some reason i was thinking that unix and xenix had named pipes back then... either way, i'm out and apologize for the diversion ;)

Reply by email

Mark Morgan Lloyd
to waldo kitty
waldo kitty wrote 11 lines
>> FWIW: DOS does have and has had pipes... otherwise things like DIR | >> MORE >> would not work... maybe you mean named pipes? ;) > > Yes, I do. And I'm obviously aware that there are plenty of addons > that graft > named pipes (and mailslots etc.) onto DOS. i never used any of that... didn't need to AFAIK... just regular pipes worked fine for the times i needed them but yes, they a much different animals than named pipes...

I used mailslots in a DOS (VB for DOS?) program, they're the API that underlies MS-style networking's NET SEND command.

Show quoted text 8 lines
> However I always think of named > pipes, threads etc. as being primarily OS/2 v1 innovations, although > some might > have been introduced by the obscure Microsoft OS usually referred to as > "European MS-DOS v4.0". for some reason i was thinking that unix and xenix had named pipes back then... either way, i'm out and apologize for the diversion ;)

If you were using the very early MS networking for unix (mentioned in the Samba entry on Wp IIRC, but I think I've also got other references) then they probably had both.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Marco van de Voort
to waldo kitty: i never used any of that... didn't need to AFAIK... just regular pipes worked fine for…

In our previous episode, waldo kitty said:

Show quoted text 7 lines
> However I always think of named > pipes, threads etc. as being primarily OS/2 v1 innovations, although some might > have been introduced by the obscure Microsoft OS usually referred to as > "European MS-DOS v4.0". for some reason i was thinking that unix and xenix had named pipes back then... either way, i'm out and apologize for the diversion ;)

Unix typically calls them "FIFO" and they were a System V (or thereabouts) invention, circa 1982-1983. Though they might not been bidirectional till they were reimplemented on top of SysV streams subsystem (86-87).

Xenix was mostly SysV afaik.

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 11 lines
On Wed, 18 Jul 2012 17:15:20 +0200 (CEST) wrote: > [...] > I meant the SimpleIPC unit from the FCL: > http://lazarus-ccr.sourceforge.net/docs/fcl/simpleipc/index.html Is there a simple two way IPC? It seems the '/tmp' directory is always used by simpleipc under unix. How can I change this directory?

You can't, currently, but patches to customize this are definitely welcome. I had at least one extension in mind, where a user-specific directory would be used.

Michael.

Reply by email

Mark Morgan Lloyd
to Michael Van Canneyt
Michael Van Canneyt wrote 17 lines
On Sun, 22 Jul 2012, Mattias Gaertner wrote: > On Wed, 18 Jul 2012 17:15:20 +0200 (CEST) > wrote: > >> [...] >> I meant the SimpleIPC unit from the FCL: >> http://lazarus-ccr.sourceforge.net/docs/fcl/simpleipc/index.html > > Is there a simple two way IPC? > > It seems the '/tmp' directory is always used by simpleipc under unix. > How can I change this directory? You can't, currently, but patches to customize this are definitely welcome. I had at least one extension in mind, where a user-specific directory would be used.

If you'd like to pick through the stuff I wrote for myself you'd be welcome. There's quite a lot in there, in particular it uniquely-names and cleans up orphaned sockets... but I suspect that you'd throw your hands up in horror at my code since I'm sure that in a lot of places I've hardcoded stuff that by now exists in a standard library.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email