On Wed, 26 Sep 2001, Stephen D. Cohen wrote: > Mr. Calianu, > > > Let's say the RT Kernel thread is writing into an rtf as fast > > or slightly > > faster than the user process can consume the data. > > If slightly faster, the fifo will fill and you will lose data. > Period, end of story. As a RT systems designer, making sure your user space > process can consume the data faster than it is generated is a big part of > your job.
Of course. > > > There are no > > guarantees that the user process won't hiccup on the data, are there? > > None at all. > > > Let's say the rt kernel task keeps writing the string: > > > > "realtime" into a fifo of precisely 8 bytes, every, oh i dunno, 100ms. > > > > Now let's say my user process tries to read those 8 bytes. > > But after the > > 4th byte was interrupted. He just gets the word 'time', and 'real' > > is left in the fifo. > > No no no... He gets the word "real" and "time" is left in the FIFO. > They are FIFOs - First In First Out, so the real in realtime would come out > first. No reversing necessary. > Ehh.. never mind. I kind of braind farted on that one. Sorry :( > > Now, the rt-task runs before the user task and > > pushes in the word 'realtime' again, clobbering the word 'real' that > > was left. > > Hang on a second, let me browse the source... Your description is > incorrect. The next time the RT process tries to write "realtime" to the > buffer, it will succeed in writing "real" and the "time" portion will end up > on the floor in a sticky mess of bits. Unless, of course, your RT task > recognizes this fact by examining the return from rtf_put and acts > accordingly. > Ok, this is where my knowledge was lacking. I didn't realize that in the kernel the rtf_put() would actually partially fail. My assumption was that it would go ahead and clobber anything that's already in the fifo. However now that I know it does this, I am much helped. I only wish flow control was on option for me. Unfortunately it really isn't and I have to accept the theoretical possibility of losing data no matter how hard I try to avoid that fact. > > The user process tries to read in what he thinks are the > > remaining 4 bytes from the fifo, but he gets the word 'time' again. > > Nope, he gets the word "time" that he expected. The problem comes > when he tries to read the next eight and only gets four "real" and then gets > four more and gets "real" again. It would go something like this: > Again, I didn't know that the kernel rtf_put() would partially fail and only write in the first 4 bytes of the word 'realtime', I assumed it would write the whole word and clobber what was alrady in the fifo. > The RT Process writes: "realtime" > The FIFO contains: "realtime" > The user process reads: "real" and gets interrupted > The FIFO contains: "time" > The RT Process tries to write "realtime", only four characters succeed > The FIFO contains: "timereal" > The user process reads: "time" - the last four characters it was expecting > last read > The FIFO contains: "real" > The RT Process tries to write "realtime", only four characters succeed > The FIFO contains: "realreal" > Things go down hill from here. Yes, the above thought experiment is correct.. :) However, someone else told me that if you do a read() for N bytes in user land on an RTF you will actually get that contiguous chunk of N bytes (if it's available at the time) without being interrupted. Is this true? > > > (Ok, so in reality the word would be written into the fifo > > backwards as: > > 'emitlaer' and read in forwards as 'realtime' but you get my point, > > right?). > > I get your point and I also get that you do not seem to understand > FIFOs. They are FIFOs, not LIFO stacks. The first thing written is the > first thing read, not the other way around. > I understand fifos. You don't need to get condescending. I was simply tired and made a mental error. Of course the situation you described above is completely clear and correct, and yes, I understand FIFOs, I just was tired.. > > My question is this: What steps should a programmer take to > > at least be > > able to discard erroneous or hiccupped data coming from the rt-thread? > > Avoid the erroneous or hiccupped data altogether by following these > three simple steps: > > 1) Make sure your user space process can consume much more data than your > realtime process can generate. You can't be sure of that, really, though. The problem is that if you really don't want to throw away data, you can't stand around waiting for userland to read your data. Because you have no guaratnees that userland will get to your data before you run out of memory (assuming you do things like dynamically allocate more and more memory as your queue fills). :/ Basically what I am saying is that flow control is not an option in my application... because ultimately the real-world source of my data cannot stop and wait for it to be consumed.. it is just producing data at a steady rate with no regard for things such as task schedulers, machine load, CPU speed, etc... Flow control is only as good as the ultimate producer of the data, which in this case has no regard for flow control. In my application it's the human heart, which really can't stop beating because your machine isn't ready for the data!! > 2) Avoid any unnecessary interruptions to your user space process. Again, can't guarantee that either. > 3) Make your FIFOs much larger than required. Yes, that is true... however that only cures the symptoms for a time.. doesn't cure the 'disease' of data loss. > > One and two should be obvious. For three, I simply refuse to have > any FIFO smaller than 16384. If you are really talking high-volume data, > then larger sizes are appropriate. Unless you are on an extremely memory > starved machine, huge FIFOs are the simplest solution to your problem. > > > More specifically, I plan on writing structs into the fifo and reading > > them in userland. > > Then you are already dooming yourself to a great deal of pain. > Avoid simply using rtf_put on a struct and expecting the same thing in user > space. That is, of course, unless you are willing to sort through every > compiler option and optimization setting to make absolutely certain that the > structs will be aligned exactly the same way in RT space and user space. It > would be much better to simply define your own format for the data in the > FIFO and copy out of the struct to a buffer, send the buffer, then copy out > of the buffer into your struct. This also assures that your code is > maximally portable across platforms, etc. This is not an issue. Whenever you use a library that takes a pointer to a struct.. or compile a module that works with kernel structs, you may run into exactly the same issue. But you don't. I really think this is a non-issue. Think about it. There's no difference between copying around structs in memory and passing references to them around to libraries that you didn't compile. The latter, noone ever warns you about.. but somehow there is concern here about the former. I think the real reason people don't like to copy structs into transient, volatile, and otherwise untrustworthy things like fifos is that if you get a hiccup in the producer/consumer relationship you end up with bad structs which for some reason always make developers uncomfortable, as it's not trivial to detect/test the integrity of a struct. > > > I was thinking of delimiting these structs > > with a few > > bytes that would never appear in the structs themselves, that > > way the user > > process can synchronize its reads somewhat to those > > delimiters, as well as > > use magic numbers in the structs to identify the need to synchronize. > > You could do something like that. To tell you the truth, I have > been getting lazy lately. My current system writes ASCII format hex data > into the FIFO and reads it at the other end. I use carriage returns at the > end of each record to do blocking. It's real easy to tell if I get partial > records, it's real easy on the human trying to debug things, it works great. > On the downside, there is a little overhead on both processes. Given modern > processors, this isn't a problem for me. Your mileage may vary. > > > Is this overkill? Is there a simpler approach to this > > dilemma? Should I > > not be worrying about this as the rtf driver is smarter than I give it > > credit for? > > Nope, it is every bit as dumb as you expect. The simple solution is > to use big FIFOs and never have a blocking / overflow problem. If you write > it in there from the RT space, it will be there on the non-RT side. > Alternatively, take my lazy approach and format everything as hex strings > with carriage returns at the end. > > Please don't expect to rtf_put C structures at one end and get > exactly the same thing at the other without some work and gcc man page > browsing. Expect this to break with each future release of gcc as well. Not true. By that token then you should never use structs in C programs unless you compiled every binary that references those structs yourself. But people do it all the time (use structs in programs that depend on libraries that they didn't compile). And noone ever complains. Once and for all I would like to settle this 'structs should not be copied around' issue by contacting some compiler designers and having them clarify matters. > > > Please help me overcome my fears, > > I expect that I've helped by giving you a whole new set of fears. > Sorry about that - it is a cruel world this RT work. > Heh. :) > > PS: I feel kind of uncomfortable writing structs in the fifo > > in the first > > place, but am too lazy to textualize the data and then > > re-parse it later. > > :/ > > You will be amazed to find that it is *much* easier to textualize / > bufferize it yourself and disassemble the buffers at the other end, rather > than simply writing structs. You will find this the first time the darned > compiler bites you in the rear end and you spend two days tracking down why > something that obviously works doesn't. You may not find this until your > version of gcc changes or some such. By then you won't remember that you > might have a problem. In that case, expect to spend the whole week tracking > this down. Creating the buffers properly, on the other hand, will only take > an hour of your life and you will have the pleasure of the knowledge of a > job done properly. Your choice. :-) Well, I would agree with you completely here, except that really I don't buy that fear programmers have about struct member order being changed around randomly by compilers. I am no expert on compiler design, but I think that if compilers went about randomly re-ordering structs across release versions, you would notice that right away. Many, MANY library routines take pointers to structs as arguments and those would ALL break under the new compiler. Surely compiler designers probably have some standard with respect to ordering structs. Like, oh, maybe ordering them exactly as you declared them? :) While its true that on some architectures struct order can make a difference with respect to memory utilization, I think most compilers default to very conservative, standard, compatible settings. I mean, even C++ compilers have no problems talking to binaries compiled by C compilers when it comes to structs! While this doesn't prove anything.. it really leads me to suspect that struct ordering is more standardized than you might think in the world of C compiler implementation. At any rate, Steve, I appreciate your help. Again I apologize for brain farting on the order of things with FIFOs, and I thank you for clarifying that rtf_put() can (partially) fail if the FIFO doesn't have enough space. I guess I should have had the patience to read the docs.. :) -Calin > > Regards, > > Steve Cohen > > -------------------------- > Stephen D. Cohen > Xybion Sensor Positioning Systems > 11528 53rd Street North > Clearwater, FL 33760 > Voice: (727) 299-0150 > Fax: (727) 299-0804 > [EMAIL PROTECTED] > www.xybion.com > > -- [rtl] --- > To unsubscribe: > echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR > echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED] > -- > For more information on Real-Time Linux see: > http://www.rtlinux.org/ > -- [rtl] --- To unsubscribe: echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED] -- For more information on Real-Time Linux see: http://www.rtlinux.org/
