Dear DDJ,
In his "Swaine's Flames," February 1995, Michael is correct. The Supreme Court must absolutely avoid any deviation from the Constitution, legislated or not.
Further, it would be criminal if even the Supreme Court ruled in a way that violated the Constitution. Thus even the Supreme Court must always cite legal or historical precedent whenever it rules. If not, it would be the duty of every American to oppose any ruling that unilaterally diverged from our Constitution. And thus has it always been--except once.
In Engel v. Vitale when the (infamous) Warren court ruled to remove prayer from the public schools, it cited zero historical precedents and zero legal precedents. No court has done that before or since. Historical note: That was just a few months before the court obstructed justice in the Kennedy assassination.
Michael would do well to remember Plato: "The rejection of a dogma itself implies a dogma." Next thing to happen is that dogmatists like Michael will remove our freedom of expression.
Stephen Lindner
lindner@m-net.arbornet.org
Dear DDJ,
I liked John Ridley's article, "Identifying Serial Port IRQs" (DDJ, February 1995), but couldn't get the listing to work until changing a port write in Which IRQ(). Setting bit 1 needs all the other bits unchanged. For example, Example 1(a) should be changed to Example 1(b).
Ken Lagace
Baltimore, Maryland
John responds: Thanks for your note, Ken. I have received a lot of e-mail regarding PORTINFO. As a result of some research into some problems a few people have been having with it, I have come up with the following changes. As a result, it is much more reliable; I haven't been able to break it so far with these changes in place. In addition, operation under Windows seems to be much improved (though still not perfect). In particular, IsUART has problems with some serial ports. Specifically, some internal modems use a microcontroller to emulate a UART, and it does not respond quickly enough in loopback mode for IsUART to identify it correctly. To remedy this situation, I've added the timing loop in Example 2(a).
Apparently, the enable/disable right next to each other don't always allow all pending interrupts to be processed. To remedy this, the relatively slow output statements that normally happen just before and after this pair are moved inside; see Example 2(b).
As a result of this slowdown, however, quite often two IRQs are generated. Since multiple interrupts are going to happen anyway, you can omit the first enable/disable pair, if you want. Their only purpose was to try to eliminate duplicate IRQs.
To avoid printing of duplicate IRQs, the calling program should count bits in the return value, and loop until only one bit comes back. You may wish to limit the looping to 10 or 20 iterations, since a defective COM port may actually generate multiple interrupts; see Example 2(c). Also, since the IsUART routine is now immensely slow, you may wish to remove the IsUART call from the beginning of the WhichIRQ routine. Just be sure not to call it unless you know there is a UART on the port.
Dear DDJ,
Part of Michael Swaine's "Programming Paradigms" (DDJ, January 1995) concerning the use of a portable radio to give voice to the loops in an executing program on an early Altair machine brought back memories.
About a decade before the time being referred to in Michael's column, I was completing a Fortran program as part of a master's thesis in mathematics. This was at a small midwestern university at which the available computing facility was an IBM 1620; this was a hands-on situation in which you signed up for time on the machine. My original plan was to have the program produce a fairly large number of orbital coordinates, the final step for each point being the evaluation of a series to a sufficient level of convergence.
When my results began to appear at a dismayingly slow rate, I stopped the program, and on a reexecution, listened to the portable radio sitting on the computer, with the frequency selector at the low end of the AM range. The sounds produced by the radio helped me understand where the real crunching was taking place. I wound up changing the program to output a pair of parameters which could be plugged into a table to obtain the final results I needed.
David Moxness
Fremont, Nebraska
Dear DDJ,
In his February 1995 "Editorial," Jonathan Erickson made reference to ronald@macdonalds.com. An expanded version of the story was reported in Wired magazine (October, 1994). In fact, McDonalds has had a registered domain name for several years, mcd.com.
That McDonalds is not particularly interested in trying to soak up all possible variations of its name, deserves praise and not the implied criticism that it and other corporations are not paying attention to the Internet. According to the Wired story, there was no extortion attempt by the macdonalds.com registrar towards McDonalds.
Also, regarding that joke about Intel Pentium processors a couple of pages later--that is quite out of place as well. Instead of the joke, a little research into the problem and a paragraph or two regarding the types of software affected or an analysis of Intel's 27,000-year claim might be in order. Just how did Intel arrive at that number anyway ?
Bill England
Redmond, Washington
DDJ responds: Sorry you didn't like the Intel joke, Bill. How about this one: Q: How many Pentium engineers does it take to screw in a light bulb? A: 2.9999999. In all seriousness, we did take the Pentium's fdiv problems to heart, witness this month's "Undocumented Corner" article by Tim Coe on page 129. Likewise, you might want to refer to the February 1995 issue of our Dr. Dobb's Developer Update, which had two articles on the Pentium problems, one by senior editor Ray Valdés and another by Bill Jolitz. And finally, McDonalds has indeed been very aggressive in soaking up variations of its trademark.
Dear DDJ,
The bit in Jonathan Erickson's February 1995 "Editorial'' about Microsoft going after somebody who posted a beta version of Windows 95 on the Internet was rich. Has there ever been a more widely distributed "secret" in history? Microsoft has sent me no less than three copies (to H. Helms, Harry Helms, and Harry L. Helms) of the latest beta version. It seems like Microsoft would thank the guy for saving a lot of time and distribution costs.
Harry Helms
Solano Beach, California
Dear DDJ,
Regarding the discussion and code on ring buffers in Bill Wells's article, "Writing Serial Drivers for UNIX" (DDJ, December 1994), I am pleased to see further work with 386BSD ring buffers. After reading the article, however, I think Bill missed some of the reasons why I added ring buffers to 386BSD in the first place (in Release 0.0 in March of 1992). Since Bill's ring buffers appear to be an extension of this work, knowing some of the background may allow even more enhanced operation of the concept.
Prior to 386BSD Release 0.0, UNIX character lists (or clists) were used in BSD systems to buffer terminal I/O. This abstraction dated back to the earliest Bell Labs UNIX system and was perfectly adapted for its original use in a timesharing system with limited memory resource (for example, a PDP 11/45 with a maximum of 252 Kbytes of memory running 15--30 users each on a terminal). Blocks of 16 characters (32 on VAX systems) were maintained on a single shared-free list, totaling 5--32 Kbytes in size. Primitive functions allocated/freed blocks in the course of implementing FIFO queues of single characters. Memory utilization was quite high, since all of the terminals could use the shared-buffer resource.
However, in 386BSD, we determined that memory utilization of terminal buffers was not interesting. The average PC used with 386BSD (a console, two serial ports, and more than 4 Mbytes of memory) supported only a handful of users (typically, one). We could thus afford to allocate resources permanently to terminals, and interrupts did not have to be masked across the set of devices sharing the buffer pool. (Altering the interrupt mask on x86 PCs is considerably more expensive than on PDP-11s or VAXen, where it can be made into a single inline instruction. This is true across many other architectures besides the x86.) While in hindsight this may appear obvious, at the time we replaced the old encumbered clists code this was considered controversial. In fact, some derivatives of 386BSD Release 0.0 and 0.1 went well out of their way to reimplement clists (even though ring buffers were in other real-time operating systems) merely because they were being used in a BSD system in a "new" way. Although current versions of 386BSD have yet to take advantage of this, we intend to comprehensively replace shared interrupt masks and other exclusion mechanisms (for example, program-visible spin locks) with a new mechanism for exclusion that works well in multiprocessing environments.
Bill also states that interrupt blocking between the top and bottom halves of the driver is no longer necessary, given that characters will just fall into additional consecutive storage. This is again a consequence of isolated buffer pools and can be used to great advantage in the terminal-driver implementation, which currently uses interrupt masking in sections no longer critical. But when are the terminal input queues really empty? Since the length of the queues can always increase, we may need to recheck the queue for characters to resolve the race multiple times (for instance, ring-buffer length is now "volatile"). Continuing on, what if we have the pathologic case of a character arriving exactly every loop interval? Then, the top half of the discipline waits indefinitely!
While this may seem trivial, this has important implications for POSIX/UNIX terminal-driver implementations dealing with pending I/O during mode shifts that require the queues to be emptied prior to transition between modes (for instance, certain ioctl requests). The subtlety of this problem is that the interpretation of pending characters is now at risk--they may be incorrectly interpreted if a race occurs between the top and bottom halves of the terminal driver. In these cases, you still must mask interrupts.
In a sense, you might even say that one set of critical sections has been exchanged for another set in the terminal driver. This and other subtle dilemmas in preserving the correct POSIX semantics caused us to adopt a conservative track in 386BSD versions.
Another major consideration was the need to migrate the kernel to use dense storage for buffers instead of the sparse storage used in lists. With sparse storage, overhead in parceling up storage is endured as another price of increased memory utilization. Worse, sparse buffer storage has no locality of reference (for example, buckets of characters are not guaranteed to be consecutive)--thus, a memory-storage hierarchy may have unpredictable access timing. As a consequence, 386BSD Release 0.1 took advantage of dense storage to implement costly operations on a list as inline operations on a single segment in the ring buffer (two segments in the case of overlapping the end of the ring). Yet another consideration was to reduce unnecessary copy operations by redirecting the pointers of the buffers at will. As an example of this, Serial Line IP (SLIP) could transfer directly to a packet memory buffer in certain common cases, avoiding a copy entirely (this makes use of other mechanisms in BSD message buffers, of course).
Another concern was the need for "wide" characters of 16 or 32 bits. In 386BSD Release 1.0, the structure of the line disciplines was rewritten to allow transparent use of the ring-buffer headers with internal implementations (within, say, a UNICODE terminal driver "wtermios" and corresponding serial/console drivers capable of implementing wide characters) different than the default 8-bit character size. We felt that the terminal driver should bear the burden of work, and that above the level of the terminal driver, the de facto view of buffer contents should only be a queue-item count This avoids duplicating knowledge of queue structure for 8, 16-, and 32-bit character implementations.
One limitation of ring buffers occurs when stackable protocol modules replace the current line disciplines. In this case, one needs to "switch" ring-buffer contents further up the level-of-abstraction stack of the kernel. This then reintroduces many of the problems incurred with clists. As such, we decided that a single, comprehensive mechanism used for high-speed networking was better than ring buffers, and have been working in that direction with our internal 386BSD development. Ring buffers have been left in until SIGNA (the Simple Internet Gigabit Network Architecture) can encompass terminal drivers and disciplines.
Another interesting aspect of ring buffers which is ripe for exploitation is that of "chunking" I/O to FIFO serial cards. As this article correctly points out, ring buffers cannot be completely filled--a single element must be free. However, if you change the quantization from byte to the size of the FIFO (in determining rollover and "full" state), the FIFO can conceivably be unloaded using a single I/O-port string instruction, since one would always be guaranteed contiguous buffer space. On VAXen in the "old" days of 4BSD, it was found that stuffing FIFOs in this manner was the most efficient way of handling serial I/O, beating out both pseudo-DMA and real DMA.
Bill Jolitz
Oakland, California
(a) _disable(); /* Ready for the real thing now */ IRQ_Happened = 0; /* Clear bitmap */ outp(CurPortBase+IER,0x02); /* enable xmt empty int. */ (b) _disable(); /* Ready for the real thing now */ IRQ_Happened = 0; /* Clear bitmap */ outp(CurPortBase+IER,(HoldIER | 0x02)); /* enable xmt empty int. */
(a)
/* routine IsUART(): code added between outp and if statements */
_outp(PortAddr+MCR, 0x0a | LOOPBIT); /* Turn on RTS */
{
long oldtick, far *ticks=0x0040006c; /*points to timer ticks area*/
oldtick = *ticks+2; /*wait for ~1 or 2 ticks */
while (oldtick != *ticks) ;
}
if ((_inp(PortAddr+MSR) & 0xf0) == 0x90) /* If CTS is on, there's a UART */
(b)
/* routine WhichIRQ(): move outp statements to between second enable/disable
pair */
enable(); /* BANG! */
_outp(CurPortBase+IER, 0x02); /* enable xmt empty int. */
_outp(OCW1, (_inp(OCW1) & (~IRQbit)) | /* Restore 8259 */
(HoldOCW1 & IRQbit));
disable(); /* OK, we're done. */
(c)
(In module PORTINFO.C, added function:)
--begin--
short NumBits(unsigned short IRQ_bitmap)
{
short x,bits;
for (x=8,bits=0; x; x--,IRQ_bitmap >>=1)
if (IRQ_bitmap & 1)
bits++;
return bits;
}
/* in function main(), put the call to WhichIRQ() in a loop */
do
IRQ_bitmap = WhichIRQ(PortAddr);
while (NumBits(IRQ_bitmap) > 1);
Copyright © 1995, Dr. Dobb's Journal