Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Serial port arbitration (UUCP device locking protocol?)



Thanks! It doesn't get any better than a detailed reply from an Apple
engineer that includes sample code and doesn't include "please file a
bug" :-)

One question, though. When you say 

>      // At this point you have the port exclusively and non-preemtibly
>      // so now is a good time to program up the modem or do any other
>      // equipment initialisation you desire.

How do I do that? Can I just write to the dialin device or should I
open the dialout?

-- Dan

On Sat, 12 Feb 2005 11:47:00 -0800, Godfrey van der Linden
<email@hidden> wrote:
> G'day Dan,
> 
> I'll use this email to write up IOSerialFamily arbitration then I'll
> add a man page, probably ioss(4).
> 
> The traditional UNIX arbitration has some serious limitations.  One of
> which is that it is very difficult to have a port open waiting for a
> fax or data connection and then allow the computer to dial out.
> Traditionally this problem was solved with lock files that often
> contain PIDs.  However there are so many different types and
> implementations of the lock file method it is rarely reliable,
> especially in an opensource environment.
> 
> So when I studied the various different implementations around when
> asked to work on the NeXT serial ports I felt that the tty.*/cu.*
> mechanism was the cleanest.  In those days the modem cable could be
> relied upon to correctly wire the carrier detect line.  The semantic
> was clean that is the getty could open the tty.* line and it would
> block until carrier was raised.  While the getty was blocked in open
> the cu.* line could be opened arbitrarily.  The worked very well.
> 
> The problem came with fax modems which do not raise the carrier and
> Mac's which don't usually wire carrier into their serial cables.  When
> this happens the enitire NeXT/BSD arbitration model breaks down.  Yet I
> still liked the basic model.  A couple of years ago (yes it has taken a
> long time to document this hasn't it, my only excuse is that I have
> been busy ;-) I had a hard look at serial arbitration and did a bit of
> comparative research and it seemed that the state of the art was to use
> UUCP style lock files. I just hated that solution.  So I chose to stick
> with the basic design of the NeXT/BSD model but implement the concept
> of preemptable ports.
> 
> One other thing before I go into the details.  Traditionally UNIX will
> allow multiple clients to open the same serial port.  It provided the
> TIOCEXCL flag as a mechanism to fail future opens of the same port but
> TIOCEXCL had the problem of not being atomic.  Hence it was possible
> for 2 processes to successfully open the port then both attempt to
> promote it to exclusive access, they would both succeed.  I changed the
> implementation of TIOCEXCL to provide for a true atomic test.  If one
> process attempts to lock exclusively and another process has beaten it
> then the ioctl will fail.
> 
> Finally there had to be a mechanism to work out whether an exclusive
> port became idle.  I couldn't use a blocking open() statement as it was
> supposed to return failure if the port was set to be exclusive.  And I
> didn't like the idea of creating another minor device to exclusively
> for blocking a port and I obviously couldn't use an ioctl (you need an
> open port to do that).  Being an IOKit architect I decided to use the
> IOKit model to control this behaviour.  To the end I have created a new
> "property" called waitForIdle that will block, interruptibly, till the
> serial port goes idle, i.e. neither the cu.* nor the tty.* line is
> currently open.
> 
> So putting all of this together to reliably open a serial port on
> MacOSX use the following procedure, note there are still race
> conditions involved but you can be reasonably certain that you have a
> port reliably.
> 
> To open a dialin device (getty/efax), NB this is code I have written of
> the top of my head and hasn't been compiled, I make no promises that it
> works as written you may need to fix minor errors in spelling.
> 
> #include <IOKit/serial/ioss.h>
> #include <IOKit/serial/IOSerialKeys.h>
> 
>      // iterate over I/O registry to find desired node and keep your
>      // registry entry node (See DTS docs for a write up on how to do
> this)
>      io_registry_entry_t portre = <do the search>
> 
>      int fd;
>      int preempt;
> 
> tryAgain:
>      for (;;) {
>          do {
>              fd = open(<tty.dialindevice>, O_NONBLOCK);
>              if (-1 == fd)
>                  if (EBUSY == errno)
>                      continue;
>                  else
>                      exit(1);    // Fatal error
> 
>              // clear O_NONBLOCK flag
>              if (-1 == fcntl(fd, F_SETFL, 0))
>                  exit(1);        // fatal error
> 
>              if (-1 == ioctl(fd, TIOCEXCL, 0))
>                  if (EBUSY == errno) {
>                      close(fd);
>                      fd = -1;
>                      continue;
>                  }
>                  else
>                      exit(1);    // Fatal error
>          } while(false);
> 
>          if (-1 != fd)
>              break;
> 
>          // We must have had an EBUSY error to be here so wait for idle
>          if (kIOReturnSuccess != IORegistryEntrySetProperty(portre,
>                  CFSTR(kIOTTYWaitForIdleKey), kCFBooleanTrue)
>              exit(1);            // Fatal error
> 
>      };
> 
>      // At this point you have the port exclusively and non-preemtibly
>      // so now is a good time to program up the modem or do any other
>      // equipment initialisation you desire.
> 
>      preempt = 0;`
>      if (-1 == ioctl(fd, IOSSPREEMPT, &preempt))
>          exit(1);        // Fatal error
> 
>      // Now the port is in the preemptible - blocking state
>      // time to issue a blocking read or a select as needed
>      // waiting for whatever event you are want.
>      if (-1 == read(fd, buf, sizeof(buf))        // Pseudo code
>          if (EIO == errno) {
>              close(fd);        // We have been preempted.
>              goto tryAgain;
>          }
>          else
>              exit(1);            // probably fatal
> 
>      // We have a connection and it is time to say we are no longer
>      // preemptible
>      preempt = 1;
>      if (-1 == ioctl(fd, IOSSPREEMPT, &preempt))
>          exit(1);        // Fatal error
> 
>      // That's it while we are running non-preemtibly/exclusive further
>      // attempts to open the port on either cu.* or tty.* will fail with
> EBUSY
> 
> That is about it, I should note that the callout line is much simpler
> but if it gets EBUSY returned from the open it should also spin around
> kIOTTYWaitForIdleKey property.
> 
> Hope this helps
> 
> Godfrey van der Linden
> IOSerialFamily (for my sins)
> 
>
 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/darwin-dev/email@hidden

This email sent to email@hidden

References: 
 >Re: Serial port arbitration (UUCP device locking protocol?) (From: Mike Smith <email@hidden>)
 >Re: Serial port arbitration (UUCP device locking protocol?) (From: Dan Bernstein <email@hidden>)
 >Re: Serial port arbitration (UUCP device locking protocol?) (From: Godfrey van der Linden <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.