123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <html><head>
- <meta http-equiv="content-type" content="text/html; charset=windows-1252">
- <title>pup_event_ipc</title>
- <meta content="Barry Kauler" name="author">
- <meta content="IPC mechanism for Puppy Linux" name="description">
- </head>
- <body>
- <table align="center" border="0" cellpadding="2" cellspacing="2" width="600">
- <tbody>
- <tr>
- <td valign="top">
- <h1>Puppy's InterProcess Communication</h1>
- <font color="#990000">Page updated June 29, 2013</font> <br>
- <b>pup_event</b> is the generic name that I have given to the underlying
- ...how to describe it... code that does everything "under the bonnet",
- in the background, that makes your pup run nice. <br>
- <br>
- This page describes an implementation of <b>InterProcess Communication</b>
- in Puppy, that falls under the pup_event umbrella. So, this can be
- known as the "pup_event IPC" technique, to give it a name when
- referenced or discussed elsewhere.<br>
- <br>
- The method chosen is server-less, that is, works peer-to-peer.
- Applications send and receive messages between themselves directly,
- without an intermediate server or daemon. However, some applications can
- provide information that other applications request, and I use the word
- <b>server</b> in reference to them. I also refer to applications as <b>clients</b> of the IPC mechanism.<br>
- <br>
- Puppy's IPC mechanism offers various services to client applications:<br>
- <ol>
- <li>IPC by synchronous message swapping.</li>
- <li>IPC by mailbox (asynchronous) message passing.</li>
- <li>Block hotplug events from the kernel.</li>
- <li>...more coming...<br>
- </li>
- </ol>
- There is a CLI
- (commandline) utility supporting IPC in Puppy, named 'pup_event_ipc', that can be used in
- shell scripts. Documentation is provided below to show how binary (compiled)
- applications can use IPC by means of library calls.<br>
- <br>
- <hr size="2" width="100%">
- <h2>pup_event_ipc</h2>
- This is a CLI (commandline) application named 'pup_event_ipc'. It is
- designed to be used in shell scripts, acting as an intermediary to the pup_event IPC mechanism,
- enabling scripts to pass messages between each other. It is located at /sbin/pup_event_ipc.<br>
- <br>
- Usage of pup_event_ipc is shown by examples in the rest of this
- document. You can also run it like this to see some usage information:<br>
- <pre># pup_event_ipc --help</pre>
- The source code is at /usr/local/pup_event/pup_event_ipc.bac in the
- latest Puppy, also reproduced below. It is also available online in the
- Woof Fossil VCS repository (also this document) after anonymous login,
- at: <a href="http://bkhome.org/fossil/woof2.cgi/index">http://bkhome.org/fossil/woof2.cgi/index</a> <br>
- <br>
- The code can be examined to see how any other application can access the IPC mechanism.<br>
- <br>
- The commandline format of pup_event_ipc is this:<br>
- <pre># pup_event_ipc "request:client[:message]" [-t <n>]</pre>
- <blockquote><b>-t</b> <n>: Specifies timeout in milliseconds. Timeout will return with value=1.<br>
- <b>request</b>: Name of another application to send the message to<b>*</b>. Or,<br>
- <b>request</b>: Keyword to request information from the server. <br>
-
- Supported keywords: block mailbox waitmail<br>
- <b>client</b>: Any single-word to identify client (usually sender) application<b>*</b>.<br>
- <b>message</b>: Any text string (that other side understands), up to 4000 bytes.<br>
- </blockquote>
- <b><big>*</big></b>The names for clients need to be unique. Choose
- anything you want, perhaps prefixing all names with your initials, for
- example John Smith could prefix with "js_".<br>
- <br>
- <hr size="2" width="100%">
- <h2>Message formats</h2>
- This section describes message formats. This is already introduced above, as:<br>
- <pre>"request:client[:message]"</pre>
- The various permutations of this are described below.<br>
- <h3>Synchronous message-swapping</h3>
- Demonstrating synchronous message-swap between two different applications.<br>
- In one terminal window I type this:<br>
- <pre># pup_event_ipc "js_app1:js_app2:some stuff from app2"</pre>
- In another terminal window I type this:<br>
- <pre># pup_event_ipc "js_app2:js_app1:data from app1"</pre>
- After launching both of them:<br>
- First window:<br>
- <pre># pup_event_ipc "js_app1:js_app2:some stuff from app2"<br>data from app1</pre>
- Second window:<br>
- <pre># pup_event_ipc "js_app2:js_app1:data from app1"<br>some stuff from app2</pre>
- This is a very simple mechanism that can be use by two applications to
- perform a synchronization, or to pass messages between each other.<br>
- <br>
- It is a simple swap, and both sides must post to the other. If only one
- side posts, the message will remain in the "mailbox" until the other side
- posts.<br>
- The utility 'pup_event_ipc' blocks, that is, waits, until the swap is completed, before exiting.<br>
- <br>
- Note, the CLI utility 'pup_event_ipc' does have a timeout option (-t n),
- so either side can terminate before the swap has completed.<br>
- <h3>Mailbox (asynchronous) message passing</h3>
- When a client posts a message to another client, it goes first into the
- IPC "mailbox", later it gets delivered to the other client.<br>
- <br>
- With asynchronous message passing, you don't send the message to the
- other client, you send it to the mailbox only, then the sending-client
- is free to do other stuff.<br>
- The other client, to which you would like your message to go, can at any
- time query "is there a message waiting for me?" and if so,
- fetch it.<br>
- <br>
- The format of messages is:<br>
- <pre>"mailbox:client[:message]"</pre>
- If a client posts a message with this format, with the third-field
- message-string, it gets posted, and the server acknowledges. For
- example:<br>
- <pre># pup_event_ipc "mailbox:js_app1:message string posted to app1"<br>Mailbox acknowledge</pre>
- A client, any client, can ask if there is mail waiting for "js_app1".
- This is done by having no third field. For example:<br>
- <pre># pup_event_ipc "mailbox:js_app1"<br>message string posted to app1</pre>
- However, if this is done again:<br>
- <pre># pup_event_ipc "mailbox:js_app1"<br>Mailbox empty</pre>
- That last example returns immediately, but if you want to wait until a message arrives at the mailbox, use this variant:<br>
- <pre># pup_event_ipc "waitmail:js_app1"</pre>
- The utility will not exit until there is a message delivered.<br>
- <br>
- But of course, the pup_event_ipc utility does support a timeout:<br>
- <pre># pup_event_ipc "waitmail:js_app1:" -t 4000</pre>
- Synchronous message-swapping and asynchronous mailbox message-passing,
- are the two peer-to-peer messaging and synchronization mechanisms.<br>
- There is another group, that is a bit more like a server-client
- arrangement, in which the 'request' field of the message requests
- something from another application. That other application will be
- serving a certain kind of information. Although I don't really want to
- consider these as servers, as they are just equal clients in the IPC
- mailbox system, for the sake of putting a name on them, I am referring
- to this group of applications as "server applications".<br>
- <br>
- Server applications are documented below. Currently only <b>block</b> server is offered.<br>
- <h3>Block hotplug events</h3>
- A client application may query the "kernel-event server application" for
- various information, such as detecting plugin/removal of USB or
- card drives.<br>
- <br>
- For now, only <b>block</b> is supported. For example:<br>
- <pre># pup_event_ipc "block:js_app1"<br>add:sdc add:sdc1</pre>
- The utility waits until a drive hotplug event occurs, such as a USB Flash stick plugged in, then returns with the information.<br>
- <br>
- The 'pup-event_ipc' utility is only designed as a one-shot query, so exits after detecting the events.<br>
- However, hotplug events are not lost. The first "block" request has
- registered "js_app1" (from above example) and hotplug events will
- accumulate.<br>
- <br>
- So, by having a loop, to receive and process the hotplug events, no events will be missed. Ex shell script:<br>
- <pre>while true; do<br> EVENTS="`pup_event_ipc "block:js_app1"`"<br> ...<i>process</i>...<br>done</pre>
- What needs to be understood about the above, is how simple the
- implementation is. The client application just creates a file (if it
- does not exist) named "/tmp/pup_event_ipc/block_js_app1" and waits for
- the server-application to put something into it. This inotify IPC
- technique is described in the next section.<br>
- <br>
- <hr size="2" width="100%">
- <h2>The inotify backend</h2>
- The IPC technique used is more than a little unusual. The established
- techniques such as D-Bus, named pipes, message queues and Unix Domain
- Sockets, were investigated and rejected for one reason or another.<br>
- <br>
- The inotify mechanism supported by the Linux kernel is not intended to
- be used for IPC, at least not to the extent that I have done. As it has
- turned out, however, it "ticks all the boxes" for what I want for Puppy
- -- it is very fast, low resources, extremely simple, and remarkably
- amenable to the particular uses that I wanted to put it to.<br>
- <br>
- The References Section below has links that introduce inotify, read those if you need to understand the fundamentals. <br>
- <br>
- There is a directory /tmp/pup_event_ipc, the "mailbox", that
- contains the files that have the messages to be transferred. When a file
- pertaining to a particular client changes, the client "wakes up" and
- handles it. Basically the steps are:<br>
- <table border="1" cellpadding="2" cellspacing="0" width="100%">
- <tbody>
- <tr>
- <td valign="top"><b>1</b><br>
- </td>
- <td valign="top"><b>2</b><br>
- </td>
- <td valign="top"><b>3</b><br>
- </td>
- </tr>
- <tr>
- <td valign="top">ClientA is waiting on fileA<br>
- </td>
- <td valign="top">ClientB writes to fileA</td>
- <td valign="top">ClientA wakes up and reads file<br>
- </td>
- </tr>
- </tbody>
- </table>
- <br>
- That is really all it is. From those three steps, a complete IPC system can be devised.<br>
- <br>
- Of course, there all kinds of caveats and gotchas in this mechanism,
- such as guaranteeing a complete message is written to a file before it
- is read, and that files do not contain garbled messages if two or more
- clients write to them simultaneously.<br>
- <br>
- The way that I have implemented it, does, I think, avoid these pitfalls.<br>
- Atomicity of read and write is important for this to work, and from
- reading online I got two different figures for this for Linux: 1KB or
- 4KB (kilobytes). I was optimistic and used the higher figure.<br>
- <br>
- A communication is between two clients, using two files, for each
- direction of transfer. As long as they choose unique names, there is not
- going to be a clash with other transfers. There will not occur the
- problem of two different clients simultaneously writing to the same
- file.<br>
- <br>
- Anyway, even if two or more clients were allowed to write to the same
- file "simultaneously", atomicity and the O_APPEND write mode (see
- below), will ensure that individual messages remain intact.<br>
- <br>
- The CLI utility is the first implementation of inotify-based IPC for
- Puppy Linux, though, it is generic and will work for all Linux
- distributions. The easiest way I think to explain how it all "hangs
- together" is to show the code for this utility.<br>
- <br>
- The utility 'pup_event_ipc' is written in BaCon (see: <a href="http://bkhome.org/bacon/">http://bkhome.org/bacon</a>) with embedded C, so is a binary executable, small and fast. This is the code as at June 29, 2013:<br>
- <table border="1" cellpadding="2" cellspacing="0" width="100%">
- <tbody>
- <tr>
- <td valign="top">
- <pre>REM (c) Copyright Barry Kauler, June 2013, bkhome.org<br>REM License GPL3 (refer: /usr/share/doc/legal)<br>REM InterProcess Communication for Puppy Linux, CLI utility using inotify.<br>REM 130628 first version.<br><br>DECLARE helpflg,milliseconds TYPE int<br><br>'parse the commandline...<br>helpflg=0<br>milliseconds=0<br>sendstr$=""<br>IF argc==1 THEN helpflg=1<br>FOR x=1 TO argc-1<br> arg$=argv[x]<br> IF arg$=="--help" THEN<br> helpflg=1<br> CONTINUE<br> ENDIF<br> IF arg$=="-h" THEN<br> helpflg=1<br> CONTINUE<br> ENDIF<br> IF arg$=="-t" THEN<br> INCR x<br> milliseconds=VAL(argv[x])<br> CONTINUE<br> END IF<br> sendstr$=arg$<br>NEXT<br><br>IF helpflg==1 THEN<br> PRINT "(c) Copyright Barry Kauler, June 2013, license GPL3 (/usr/share/doc/legal)"<br> PRINT "This is a CLI utility that may be used in scripts. Run like this:"<br> PRINT " pup_event_ipc \"request:client[:message]\""<br> PRINT " request: name of another application to send the message to*. Or,"<br> PRINT " request: keyword to request information. Supported keywords:"<br> PRINT " block mailbox waitmail"<br> PRINT " client: any single-word to identify client (usually sender) application*."<br> PRINT " message: any text string (that other side understands), up to 4000 bytes."<br> PRINT " any characters allowed, including \":\""<br> PRINT "ex: pup_event_ipc \"otherapp:myapp:some data for otherapp\""<br> PRINT "ex: pup_event_ipc \"mailbox:otherapp:some data for otherapp\""<br> PRINT "ex: pup_event_ipc \"mailbox:myapp\"" <br> PRINT "ex: pup_event_ipc \"waitmail:myapp\""<br> PRINT "ex: pup_event_ipc \"block:myapp\""<br> PRINT "pup_event_ipc has an optional timeout (milliseconds),"<br> PRINT "ex: pup_event_ipc -t 1000 \"otherapp:myapp:data for you\""<br> PRINT "Will exit with non-zero value if an error:"<br> PRINT " 1=timeout. 2=wrong msg format. 3-7=message-passing failure. "<br> PRINT "*Any unique names that both clients agree on."<br> PRINT "PLEASE SEE /usr/local/pup_event/pup_event_ipc-README.htm for more details."<br> END 0<br>END IF<br><br>PROTO close, ftruncate, inotify_init, inotify_add_watch, inotify_rm_watch<br>PROTO lseek, open, poll, read, sizeof, strlen, write<br>DECLARE fd1,len1,leni,size_buf,thiswatchfile,otherwatchfile TYPE int<br>DECLARE arr1,thisapp,otherapp TYPE char*<br>DECLARE thisdescr,otherdescr TYPE int<br>size_char=sizeof(char)<br>size_inbuf=size_char*4096<br>DECLARE inbuf,bufinotify TYPE char ARRAY size_inbuf<br><br>SUB exitsub(NUMBER i)<br> IF watchdir>0 THEN <b>inotify_rm_watch</b>(fd1,watchdir)<br> IF fd1>0 THEN <b>close</b>(fd1)<br> IF otherdescr>0 THEN <b>close</b>(otherdescr)<br> IF thisdescr>0 THEN <b>close</b>(thisdescr)<br> END i<br>END SUB<br><br>'struct pollfd, defined in asm-generic/poll.h...<br>RECORD pfd<br> LOCAL fd TYPE int<br> LOCAL events TYPE short<br> LOCAL revents TYPE short<br>END RECORD<br>'linux/poll.h, only includes asm/poll.h, which only includes asm-generic/poll.h...<br>CONST POLLIN=1<br>pfd.events = POLLIN<br><br>SUB waitsub()<br> 'there is very slight possibility of deadlocking, if reply between lseek & read/poll...<br> offt=<b>lseek</b>(thisdescr,0,SEEK_END)<br> IF offt==0 THEN<br> IF milliseconds==0 THEN<br> 'this will block until the file is modified...<br> leni=<b>read</b>(fd1,bufinotify,size_inbuf)<br> ELSE<br> pfd.fd=fd1<br> eventstatus=<b>poll</b>(&pfd.fd,1,milliseconds)<br> IF eventstatus==0 THEN exitsub(1)<br> IF eventstatus<0 THEN exitsub(7)<br> ENDIF<br> ENDIF<br> offt=<b>lseek</b>(thisdescr,0,SEEK_SET)<br> numr=<b>read</b>(thisdescr,inbuf,size_inbuf)<br> ft=<b>ftruncate</b>(thisdescr,0)<br> IF numr>1 THEN<br> 'get rid of carriage-return char...<br> inbuf[numr-1]=0<br> inbuf$=inbuf<br> PRINT inbuf$<br> ENDIF<br>END SUB<br><br>'parse the message...<br>field1$=""<br>field2$=""<br>field3$=""<br>field4$=""<br>message$=""<br>arr1=sendstr$<br>off1=INSTR(arr1,":")<br>IF off1=0 THEN exitsub(2)<br>arr1[off1-1]=0<br>field1$=arr1<br>off2=INSTR(arr1+off1,":")<br>arr1[off1+off2-1]=0<br>field2$=arr1+off1<br>IF off2>0 THEN<br> off3=INSTR(arr1+off1+off2,":")<br> 'the message-part can have ":" chars in it...<br> message$=arr1+off1+off2<br> arr1[off1+off2+off3-1]=0<br> field3$=arr1+off1+off2<br> IF off3>0 THEN<br> off4=INSTR(arr1+off1+off2+off3,":")<br> arr1[off1+off2+off3+off4-1]=0<br> field4$=arr1+off1+off2+off3<br> ENDIF<br>ENDIF<br>'need to extract names of this-app and other-app...<br>otherapp=0<br>thisapp=0<br>thiscreateflag=1<br>SELECT field1$<br>CASE "mailbox"<br> IF message$!="" THEN<br> otherapp=field2$<br> ELSE<br> thisapp=field2$<br> ENDIF<br>CASE "waitmail"<br> thisapp=field2$<br>CASE "block"<br> thisapp$=CONCAT$("block_",field2$)<br> thisapp=thisapp$<br> 'thisfile$ is not created here, it is created by daemon that monitors kernel uevents...<br> thiscreateflag=0<br>DEFAULT<br> otherapp=field1$<br> thisapp=field2$<br>END SELECT<br><br>'create the files...<br>otherdescr=0<br>thisdescr=0<br>watchdir=0<br>IF FILEEXISTS("/tmp/pup_event_ipc")==0 THEN MAKEDIR "/tmp/pup_event_ipc"<br>IF otherapp!=0 THEN<br> otherfile$=CONCAT$("/tmp/pup_event_ipc/",otherapp)<br> USEC<br> /*defined in /usr/include/asm-generic/fcntl.h & i386-linux-gnu/bits/fcntl-linux.h...*/<br> #define O_WRONLY 00000001<br> #define O_CREAT 00000100<br> # define O_SYNC 04010000<br> #define O_FSYNC O_SYNC<br> #define O_APPEND 00002000<br> otherdescr=<b>open</b>(otherfile$, O_WRONLY | O_CREAT | O_APPEND);<br> END USEC<br> IF otherdescr<=0 THEN exitsub(3)<br>ENDIF<br>IF thisapp!=0 THEN<br> closedflag=0<br> thisfile$=CONCAT$("/tmp/pup_event_ipc/",thisapp)<br> IF thiscreateflag=1 THEN<br> USEC<br> #define O_RDONLY 00000000<br> #define O_CREAT 00000100<br> #define O_RDWR 00000002<br> thisdescr=<b>open</b>(thisfile$,O_RDWR | O_CREAT);<br> END USEC<br> ELSE<br> IF FILEEXISTS(thisfile$)==1 THEN<br> USEC<br> #define O_RDONLY 00000000<br> #define O_RDWR 00000002<br> thisdescr=<b>open</b>(thisfile$,O_RDWR);<br> END USEC<br> ELSE<br> closedflag=1<br> ENDIF<br> ENDIF<br> IF closedflag==0 THEN<br> IF thisdescr<=0 THEN exitsub(4)<br> fd1=<b>inotify_init</b>()<br> IF fd1<=0 THEN exitsub(5)<br> CONST IN_MODIFY=2<br> watchdir=<b>inotify_add_watch</b>(fd1,thisfile$,IN_MODIFY)<br> IF watchdir<=0 THEN exitsub(6)<br> ENDIF<br>ENDIF<br><br>'now decide what to do...<br>SELECT field1$<br>CASE "mailbox"<br> IF otherapp!=0 THEN<br> 'need to post message to otherapp... format: "mailbox:otherapp:message"<br> outstr$=CONCAT$(message$,"\n")<br> wr=<b>write</b>(otherdescr,outstr$,strlen(outstr$))<br> PRINT "Mailbox acknowledge"<br> ELSE<br> 'need to check if waiting mail for thisapp...<br> offt=<b>lseek</b>(thisdescr,0,SEEK_END)<br> IF offt==0 THEN<br> PRINT "Mailbox empty"<br> ELSE<br> offt=<b>lseek</b>(thisdescr,0,SEEK_SET)<br> numr=<b>read</b>(thisdescr,inbuf,size_inbuf)<br> ft=<b>ftruncate</b>(thisdescr,0)<br> IF numr>1 THEN<br> 'get rid of carriage-return char...<br> inbuf[numr-1]=0<br> inbuf$=inbuf<br> PRINT inbuf$<br> ENDIF<br> ENDIF<br> ENDIF<br>CASE "waitmail"<br> 'need to wait for mail for thisapp... format: "waitmail:thisapp"<br> waitsub()<br>CASE "block"<br> 'need to wait for block-drive hotplug event, for thisapp... format: "block:thisapp"<br> IF FILEEXISTS(thisfile$)==0 THEN<br> PRINT "Not implemented"<br> ELSE<br> waitsub()<br> ENDIF<br>DEFAULT<br> 'post msg to otherapp, wait for reply to thisapp... format: "otherapp:thisapp:message"<br> outstr$=CONCAT$(message$,"\n")<br> wr=<b>write</b>(otherdescr,outstr$,strlen(outstr$))<br> waitsub()<br>END SELECT<br><br>exitsub(0)<br></pre>
- </td>
- </tr>
- </tbody>
- </table>
- <br>
- This is a remarkably small program to implement a complete IPC system. Essentially, it does this:<br>
- <ol>
- <li>Parses the message that has been passed on the commandline.</li>
- <li>Creates one or two files in /tmp/pup_event_ipc, and opens them.</li>
- <li>Based on the passed message, data will be written to one file, or data read from the other.</li>
- <li>Reading may or may not block, depending on the message.<br>
- </li>
- </ol>
- When a file is opened for writing, it is done with the 'O_APPEND' mode,
- meaning that writes to it always append to the end of the file, totally
- ignoring the file-pointer.<br>
- Messages are line-based, that is, one message per line. This allows
- messages to accumulate, while waiting to be read -- hence, most
- important, no messages get lost.<br>
- <br>
- Take the message "block:myapp" as an example. The name "myapp" is an
- arbitrary choice, anything unique is suitable. If this is posted by the
- CLI utility:<br>
- <pre># pup_event_ipc "block:myapp"</pre>
- If you were to trace through the above code, you would see that if file
- "/tmp/pup_event_ipc/block_myapp" is opened (or created if it does not
- exist), then there is a block on waiting for something to be written to
- the file.<br>
- When something is written to the file, it is read, and the file zeroised. The read contents are printed on stdout.<br>
- <br>
- The above scenario means that some other application must write to /tmp/pup_event_ipc/block_myapp. <br>
- In the very latest builds of Puppy, we do have a an application that
- detects drive hotplug activity, a daemon named <b>pup_event_frontend_d</b>, that performs this information server function.<br>
- <br>
- The function that such a server would have to perform can be show by a shell script:<br>
- <pre>for ONEFILE in `ls /tmp/pup_event_ipc/block_*`<br>do<br> echo $BLOCKINFO >> $ONEFILE<br>done</pre>
- That's it, done. All clients that are waiting on block-drive hotplug
- notification, will "wake up" and read the data. As mentioned before, it
- does not matter if a client is in a loop, doing other stuff:<br>
- <pre>while true; do<br> EVENTS="`pup_event_ipc "block:myapp"`"<br> ...<i>other stuff</i>...<br>done</pre>
- While executing "other stuff", any new block-drive events will append to
- /tmp/pup_event_ipc/block_myapp (that is, queue )until it is next read.<br>
- <br>
- Note: For the above example, the code in pup_event_ipc does not
- automatically create /tmp/pup_event_ipc/block_myapp. This is for usage
- in older puppies and other distros. In latest experimental Puppy builds
- however, the line "thiscreateflag=0" is commented out, we have the
- pup_event_frontend_d daemon that feeds kernel block-drive events (as
- described above).<br>
- pup_event_frontend_d is described further in the next section.<br>
- <br>
- There is a lot that can be said about the flexibility of this
- inotify-based IPC mechanism. Just one example: although the
- pup_event_ipc utility does have a timeout option, you can cause a
- timeout whenever you want -- say, for example that a shell script has
- executed "pup_event_ipc 'block:myapp'" and is blocked, waiting on a
- modification to file /tmp/pup_event_ipc/block_myapp. Well, if you just
- execute "touch /tmp/pup_event_ipc/block_myapp", the read() function that
- is waiting will return, with zero data of course -- but voila, a simple
- way to cause a timeout.<br>
- <br>
- <hr size="2" width="100%"><h2>
- Example code blocks</h2>
- I will add to this section. For now, I have included code to show how
- the "server" can be implemented to serve block-drive event
- notifications.<br>
- <br>
- <h3>Block-drive event notification</h3>
- It has been explained above, that a client application may request
- block-drive event notification by posting a message of format
- "block:myapp" to the IPC mailbox. <br>
- <br>
- Puppy Linux has a daemon, named <b>pup_event_frontend_d</b>, at
- /usr/local/pup_event (as well as the BaCon source file,
- pup_event_frontend_d.bac, and there is a wrapper script at /sbin). This
- daemon is started from /root/.xinitrc when X starts up. It does a lot of
- background stuff, such as manage the desktop drive icons. For that
- latter reason, it does have information about drive hotplug events.<br>
- <br>
- It was an easy matter to add a bit of extra code to pup_even_frontend_d,
- to post this information to clients that want it, via the IPC
- mechanism. Example shell script code is shown in the above section, how
- this can be done.<br>
- <br>
- The actual code inserted into pup_event_frontend_d is shown below.
- Basically, it looks for any files named /tmp/pup_event_ipc/block_*, then
- writes the drive hotplug information to them (string devevents$):<br>
- <table border="1" cellpadding="2" cellspacing="0" width="100%">
- <tbody>
- <tr>
- <td valign="top">
- <pre>PROTO opendir, readdir<br>DECLARE dir1 TYPE DIR*<br>DECLARE ent1 TYPE struct dirent*<br><br>dir1=<b>opendir</b>("/tmp/pup_event_ipc")<br>IF dir1!=NULL THEN<br> WHILE TRUE DO<br> ent1=<b>readdir</b>(dir1)<br> IF ent1==NULL THEN BREAK<br> off1=<b>INSTR</b>((*ent1).d_name,"block_")<br> IF off1!=0 THEN<br> clientfile$=<b>CONCAT$</b>("/tmp/pup_event_ipc/",(*ent1).d_name)<br> outmsg$=<b>CONCAT$</b>(devevents$,"\n")<br> USEC<br> #define O_WRONLY 00000001<br> #define O_APPEND 00002000<br> int clientdescr;<br> clientdescr=<b>open</b>(clientfile$, O_WRONLY | O_APPEND);<br> if (clientdescr>0) {<br> int wr=<b>write</b>(clientdescr,outmsg$,strlen(outmsg$));<br> close(clientdescr);<br> }<br> END USEC<br> ENDIF<br> WEND<br><br>ENDIF<br></pre>
- </td>
- </tr>
- </tbody>
- </table>
- <br>
- Note, BaCon is just a translator to C, which is then compiled using the
- Gnu C compiler. It is really just a thin translation layer, so many
- C-isms can be put into the BaCon code, and pure C can be embedded. I use
- BaCon as I prefer the syntax, plus it has many higher-level features,
- such as better string handling, and associative arrays. It is easy to read the above and translate to all-C if required.<br>
- <br>
- ...<i>more coming</i>...<br>
- <br>
- <br>
- <hr size="2" width="100%"><h2>Feedback welcome</h2>
- I will be posting about progress on pup_event to my blog, <a href="http://bkhome.org/blog2/">http://bkhome.org/blog2/</a> <br>
- <br>
- Feedback will be welcome. If you can think of anything that might
- compromise the integrity of data transfer with this technique, or code
- modifications that will add improvements (while still keeping everything
- simple, including simple and small code).<br>
- <br>
- Regards,<br>
- Barry Kauler<br>
- <br>
- <hr size="2" width="100%"><h2>References</h2>
- Reference on libc functions:<br>
- <a href="http://www.gnu.org/software/libc/manual/html_node/Function-Index.html">http://www.gnu.org/software/libc/manual/html_node/Function-Index.html</a> <br>
- Wikipedia:<br>
- <a href="http://en.wikipedia.org/wiki/Inotify">http://en.wikipedia.org/wiki/Inotify</a> <br>
- Intro to inotify:<br>
- <a href="http://www.linuxjournal.com/article/8478">http://www.linuxjournal.com/article/8478</a> <br>
- Monitor file system activity with inotify:<br>
- <a href="http://www.ibm.com/developerworks/library/l-ubuntu-inotify/">http://www.ibm.com/developerworks/library/l-ubuntu-inotify/</a> <br>
- Monitor Linux File System Events with Inotify:<br>
- <a href="http://www.developertutorials.com/tutorials/linux/monitor-linux-inotify-050531-1133/">http://www.developertutorials.com/tutorials/linux/monitor-linux-inotify-050531-1133/</a> <br>
- The inotify API:<br>
- <a href="http://linux.die.net/man/7/inotify">http://linux.die.net/man/7/inotify</a> <br>
- <br>
- <br>
- </td>
- </tr>
- <tr>
- <td valign="top"><small>(c) Copyright Barry Kauler, 2013. All reproduction rights of this page are reserved.</small> <br>
- </td>
- </tr>
- </tbody>
- </table>
- <br>
- <br>
- </body></html>
|