A model of leader election in the Firewire protocol

Adapted from:

[DG+01] M.C.A. Devillers, W.O.D. GriAEoen, J.M.T Romijn, and F.W. Vaandrager. Verification of a leader election protocol — formal methods applied to IEEE 1394. Technical Report CSI-R9728, Computing Science Institute, University of Nijmegen, December 1997. Also, Formal Methods in System Design, 2001.

This model describes a leader election protocol used in Firewire, an IEEEstandard for connecting consumer electronic devices. The model is a straightforward translation into Alloy of a model [DG+01] developed in Lynch’s IO Automata which has been analyzed using PVS, a theorem prover, but which, as far as we know, has not been subjected to fully automatic analysis. We are able to express the key correctness property — that exactly one leader is elected — more directly, as a trace property rather than a refinement property, and can check it without the need for the 15 invariants used in the more traditional proof. And the analysis does not hardwire a particular topology, so would be tricky to do with a standard model checker.

The network is assumed to consist of a collection of nodes connected by links. Each link between a pair of nodes is matched by a link in the other direction. Viewing a link and its dual as a single, undirected edge, the network as a whole is assumed to form a tree. The purpose of the algorithm is to construct such a tree; in the model, this is achieved by labelling some subset of the links as parent links (each pointing from a node to its parent), and by marking a single node as the root.

The algorithm, described in detail elsewhere [DG+01], works briefly as follows. When a node detects that all of its incoming links (or all but one) has been marked as a parent link, it sends a message on each outgoing link, either an acknowledgment (indicating its willingness to act as parent), or a request (indicating its desire to be a child), according to whether the dual of the outgoing link has been marked or not. Leaf nodes (with only one incoming link) may thus initiate the algorithm by sending requests to their adjacent nodes. Performing this action changes a node’s status from {\em waiting} to {\em active}. A node that is still waiting, and which receives a message on a link, may label that link a parent link. Once active, a node that receives an acknowledgment on a link may also label the link, but if it receives a request, instead changes its node status to {\em contending}. The resolving of contentions is modelled simplistically by a single action that arbitrarily
labels one of the two links a pair of contending nodes. Finally, a node all of whose incoming links are parent links designates itself a root.

The specification is given below. Each signature introduces a basic type and some relations whose first column has that type:

\begin{itemize}

\item {\em Msg} represents the type of messages. {\em Req} is the request message and {\em Ack} is the acknowledgment message; these are actually declared as singleton (keyword {\em static}) subsets of {\em Msg}, the set of all messages, that form a partition (keyword {\em part}).

\item {\em Node} represents the nodes of the network. The relations {\em to} and {\em from} associate each node with a set of incoming and outgoing links
respectively.

\item {\em Link} represents the links. The relations {\em target} and {\em source} map a link to its end nodes; {\em reverse} maps a link to its dual. The
facts in the signatures {\em Node} and {\em Link} ensure that all these relations are consistent with one another: that the incoming links of a node are those whose target is that node, etc.

\item {\em Op} introduces a set of names for the operations of the protocol. This is merely for convenience; it allows us to ask for an execution in which named operations occur, or example.

\item {\em State} represents the global states. Each state has a partition of the nodes into one of four statuses: {\em waiting} to participate, {\em active} (having sent messages on outgoing links), {\em contending} (having sent a request on a link and received a request on its dual), and {\em elected} (having designated itself as a root). A set of links are labelled as parent links. There is a message queue associated with each link. Finally, the state is associated with the operation that produced it.

\item {\em Queue} represents the message queues. Each queue has a slot that optionally contains a message; the relation {\em slot} is a partial function from queues to messages. In our first attempt at a model, we represented a queue as a sequence (a partial function from a prefix of the integers to messages), but having checked that no queue ever contained more than one message, we simplified the model. The {\em overflow} field is included just in case this was a mistake; a write to a queue that already contains a message puts an arbitrary value there, which is easily detected.

\end{itemize}

The {\em facts} record the assumptions about the topology. The one named {\em Topology} says that there is some partial function on nodes and some root such
that (1) every node is reachable from the root ({\tt *r} being the reflexive transitive closure of the relation {\tt r}); (2) there are no cycles (expressed by saying that the transitive closure has no intersection with the identity relation on nodes); and (3) the relation obtained by following the {\em source} relation backwards (from a node to the link for which it is a source), and then the {\em target} relation forwards (from the link to its target) is this relation, plus its transpose (so that each tree edge becomes two links). Although the quantifier appears to be higher-order, it will be skolemized away by the analyzer.

The {\em functions} of the model are parameterized formulas. The function {\em Trans} relates a pre-state {\tt s} to a post-state {\tt s’}. It has a case for each operation. Look at the clause for the operation {\em WriteReqOrAck}, for example. If this operation is deemed to have occurred, each of the constraints in the curly braces must hold. The first says that the labelling of links as parent links is unchanged. The second constraint (the quantified formula) constrains with respect to the node at which the operation occurs. The subformulas, from first to last, say that the node belongs to the waiting set before and the active set afterwards; that there is at most one ({\em sole}) link that is incoming but not a parent link in the pre-state; that there are no changes to node status except at this node; that a message is queued onto each outgoing link; and that queues on all other links are unchanged.

An ‘invoked’ function is simply short for the formula in its body with the formal arguments replaced by the actual expressions. {\em WriteQueue}, for example, says that if the queue’s slot is not filled in the pre-state, then the new queue in the post-state (given the local name {\tt q}) contains the message {\tt m} in its slot, and has no message in its overflow. Otherwise, some message is placed arbitrarily in the overflow, and the slot is unconstrained. In {\em WriteReqOrAck}, the arguments {\tt s} and {\tt s’} are bound to the {\tt s} and {\tt s’} of {\em Trans}; {\tt x} is bound to one of the outgoing links from the set {\tt n.from}; and {\tt msg} is bound either to the acknowledgment or request message.

The function {\em Execution} constrains the set of states. It makes use of a library module that defines a polymorphic ordering relation. The expression {\tt Ord[State]} gives an ordering on all states. The two formulas of the function say that {\tt Initialization} holds in the first state, and that any pair of adjacent states is related by {\tt Trans}. The function {\em NoRepeats} adds the constraints that there are no equivalent states in the trace, and that no stuttering occurs.

The three assertions are theorems for which the analyzer will search for counterexamples. They assert respectively that: in every state of the trace, there is at most one node that has been elected; that there is some state in which a node has been elected; and that no queue overflows.

The rest of the model is a collection of commands executed to find instances of the functions or counterexamples to the theorems. We started by presenting a variety of functions as a sanity check; here, only one is given, that asks for an execution involving 2 nodes, 4 links, 4 queues and a trace of 6 states. The standard semantics of these {\em scope} declarations in Alloy is that the numbers represent an upper bound, so an instance may involve fewer than 4 queues, for example. The ordering module (not shown here), however, for technical reasons, constrains the ordered set to match its scope, so a trace with fewer than 6 states will not be acceptable.

We then established some bounds on the diameter of the state machine for various topology bounds. For 2 nodes and 2 links, for example, there are no non-repeating traces of length 4; checking traces of length 3 is thus sufficient in this case. The number of queues was limited to 5, to accommodate the empty queue, a queue containing an {\tt Ack} or {\tt Req}, and each of these with overflow. For 3 nodes and 6 links, a trace length of 8 suffices.

We then checked that for these various topology bounds, the queues never overflow. Finally, we checked the correctness properties, taken advantage of the earlier results that justify the short traces and queues. We are thus able to verify the properties for all topologies involving the given number of nodes and links, without any assumptions about trace length, queue size or the particular topological structure.

*/

module firewire_leader_election
open models/ord

sig Msg {}
static part sig Req, Ack extends Msg {}

sig Node {to, from: set Link} {
 to = {x: Link | x.target = this}
 from = {x: Link | x.source = this}
 }

sig Link {target, source: Node, reverse: Link} {
 reverse::source = target
 reverse::target = source
 }

– at most one link between a pair of nodes in a given direction
fact {no disj x,y: Link | x.source = y.source && x.target = y.target}

– topology is tree-like: acyclic when viewed as an undirected graph
fact Topology {
some tree: Node ?-> Node, root: Node {
 Node in root.*tree
 no ^tree & iden [Node -> Node]
 tree + ~tree = ~Link$source.Link$target
 }
}

sig Op {}
static disj sig Init, AssignParent, ReadReqOrAck, Elect, WriteReqOrAck,
ResolveContention, Stutter extends Op {}

sig State {
 part waiting, active, contending, elected: set Node,
 parentLinks: set Link,
 queue: Link ->! Queue,
 op: Op — the operation that produced the state
 }

fun SameState (s, s’: State) {
 s.waiting = s’.waiting
 s.active = s’.active
 s.contending = s’.contending
 s.elected = s’.elected
 s.parentLinks = s’.parentLinks
 all x: Link | SameQueue (s.queue[x], s’.queue[x])
 }

fun Trans (s, s’: State) {
 s’.op != Init
 s’.op = Stutter => SameState (s, s’)
 s’.op = AssignParent => {
  some x: Link {
   x.target in s.waiting & s’.waiting
   NoChangeExceptAt (s, s’, x.target)
   ! IsEmptyQueue (s, x)
   s’.parentLinks = s.parentLinks + x
   ReadQueue (s, s’, x)
   }}
 s’.op = ReadReqOrAck => {
  s’.parentLinks = s.parentLinks
  some x: Link {
   x.target in s.(active + contending)
    & if PeekQueue (s, x, Ack) then s’.contending else s’.active
   NoChangeExceptAt (s, s’, x.target)
   ! IsEmptyQueue (s, x)
   ReadQueue (s’, s, x)
   }}
 s’.op = Elect => {
  s’.parentLinks = s.parentLinks
  some n: Node {
   n in s.active & s’.elected
   NoChangeExceptAt (s, s’, n)
   n.to in s.parentLinks
   QueuesUnchanged (s, s’, Link)
   }}
 s’.op = WriteReqOrAck => {
  – note how this requires access to child ptr
  s’.parentLinks = s.parentLinks
  some n: Node {
   n in s.waiting & s’.active
   sole n.to – s.parentLinks
   NoChangeExceptAt (s, s’, n)
   all x: n.from |
    let msg = if x.reverse in s.parentLinks then Ack else Req |
     WriteQueue (s, s’, x, msg)
   QueuesUnchanged (s, s’, Link – n.from)
   }}
 s’.op = ResolveContention => {
  some x: Link {
   let contenders = x.(source + target) {
    contenders in s.contending & s’.active
    NoChangeExceptAt (s, s’, contenders)
    }
   s’.parentLinks = s.parentLinks + x
   }
  QueuesUnchanged (s, s’, Link)
  }
}

fun NoChangeExceptAt (s, s’: State, nodes: set Node) {
 let ns = Node – nodes {
 ns & s.waiting = ns & s’.waiting
 ns & s.active = ns & s’.active
 ns & s.contending = ns & s’.contending
 ns & s.elected = ns & s’.elected
 }}

sig Queue {slot: option Msg, overflow: option Msg}

fun SameQueue (q, q’: Queue) {
  q.slot = q’.slot && q.overflow = q’.overflow
 }
 
fun ReadQueue (s, s’: State, x: Link) {
– let q = s’.queue[x] | no q.(slot + overflow)
 no s’.queue[x].(slot + overflow)
 all x’ != x | s’.queue[x'] = s.queue[x']
 }

fun PeekQueue (s: State, x: Link, m: Msg) {
 m = s.queue[x].slot
 }

fun WriteQueue (s, s’: State, x: Link, m: Msg) {
        let q = s’.queue[x] |
 no s.queue[x].slot =>
  ( q.slot = m && no q.overflow),
  some q.overflow
 }

fun QueuesUnchanged (s, s’: State, xs: set Link) { 
 all x: xs | s’.queue[x] = s.queue[x]
 }

fun IsEmptyQueue (s: State, x: Link) {
 no s.queue[x].(slot + overflow)
– let q = s.queue[x] | no q.(slot + overflow)
 }
 
fun Initialization (s: State) {
 s.op = Init
 Node in s.waiting
 no s.parentLinks
 all x: Link | IsEmptyQueue (s, x)
 }

fun Execution () {
 Initialization (Ord[State].first)
 all s: State – Ord[State].last | let s’ = OrdNext(s) | Trans (s, s’)
 }

fun NoRepeats () {
 Execution ()
 no disj s, s’: State | SameState (s, s’)
 no s: State | s.op = Stutter
 }

fun NoShortCuts () {
 all s: State | — remove this to speed up analysis – Ord[State].last – OrdPrev (Ord[State].last) |
  ! Trans (s, OrdNext(OrdNext(s)))
 }

assert AtMostOneElected {
 Execution () => all s: State | sole s.elected
 }

assert OneEventuallyElected {
 Execution () => some s: State | some s.elected
 }

assert NoOverflow {
 Execution () => all s: State, x: Link | no s.queue[x].overflow
 }

run Execution for 1 Ord[State],  7 Op, 2 Msg,
 2 Node, 4 Link, 4 Queue, 6 State

– solution for 3 State but not for 4 State
run NoRepeats for 1 Ord[State],  6 Op, 2 Msg,
 2 Node, 2 Link, 2 Queue, 4 State

– solution for 8 but not 9 State
run NoRepeats for 1 Ord[State],  6 Op, 2 Msg,
 3 Node, 6 Link, 6 Queue, 9 State

– only 5 queues needed: just count
– no solution: establishes at most 3 queues needed
check NoOverflow for 1 Ord[State],  6 Op, 2 Msg,
 3 Node, 6 Link, 5 Queue, 9 State

check AtMostOneElected for 1 Ord[State],  6 Op, 2 Msg,
 3 Node, 6 Link, 3 Queue, 9 State

check OneEventuallyElected for 1 Ord[State],  6 Op, 2 Msg,
 3 Node, 6 Link, 3 Queue, 9 State

OpenOffice – no go on Mac OS X

Today I received an email with some technical specs I was supposed to review, but the document came in OpenOffice Write format (.odt), and since on my MacBook I only had Office installed, there was no way to open it.

Checking the OpenOffice.org site, it appeared a version was available for OS X, but in the traditional open source way, I was met with thinks like:

“en-US builds for Intel based Macs will be listed here as soon as they passed QA. In the meantime please” (The phrase really ends like this, I am quoting vervatim!)

…please…what? What am I supposed to do in the meantime? Ask the guy who sent me the document to re-send it in Word format? Oh, wait, here is the solution:

“The builds use X11 and are meant for the user who doesn’t care that much about look but functionality and cross plattform integration and usability. Other prospects are the Darwin community and the Unix-savvy MacOS X user community and forming a platform for us to build the Quartz and Aqua tracks for the traditional Mac user.”

I thought Intel Macs had only been around for a few months, so how can there be a tradition? Last, but not least, the list of mirrors for the english version were empty. No problem for German or French users, so congrats to you, lucky people! The fact it was empty explained the “in the meantime” statement.

What is this rant all about? The discussion I had the other day with a diehard opensource defender – the type that scream “Linux will conquer the desktop next year, really, this time” any chance they get. I think it is really great that people are willing to donate their time to contribute to opensource projects, some as large as Linux or OpenOffice, but they have to think in terms of reality, not utopia. To think Linux will take over Windows on the desktop, or that OpenOffice will replace Office, at least in the short or medium term, is wishful thinking.

I expect to be beaten to death by the diehard Linux fans, but there is no way my mother would know how to “vi your X86 configuration file to change the video adapter so that it works”. Until Linux or OpenOffice offer similar experiences than Windows or Office, there will stay in niche or very specific target groups. Companies are migrating to these operating systems and office suites, yes, but they usually have the resources to implement the transition, both from technical and training standpoints.

So, good luck with the project, I honestly wish it every success, and I am sorry that I am not a competent UNIX programmer so I can contribute. But from a user’s perspective, it has some way to go.

TechCrunch needs a new Wiki – the old one burned up!

It was frustrating to see the TechCrunch Wiki continuously locked out by people signing up to Mike Arrington’s TechCrunch party #7, so it seems that in the 20 minutes I managed to be offline, it has been locked completely, and people have turned to RSVPing on the blog’s comments. I trust this proves a Wiki is not the best method to sort an RSVP list – RSVPr.com anyone?

I hope my entry on the blog, #115, makes it to the final list! Looking back at past events, it will be a blast. Oh, and that guy that kept locking the Wiki for 15 minutes, then again, and again, and again….I have your IP… (just kidding!)

This time around the party will be at August Capital in Menlo Park – plenty of space to schmooze and talk about or projects.

How can FON expect to win?

Today I decided to attempt a second round at configuring the router FON sent me a few days ago, since my first out-of-the-box experience hadn’t been that good. Emails to tech support unanswered, which seems to be an endemic problem, as can be seen on FON’s forums, I finally gave up.

After plugging in the WRT54GS router as briefly described in the brief manual supplied with it (a third of one side of an A4 sheet of paper), I connect to the FON_HotSpot SSID detected by the MacBook. Fire up Firefox, and I’m promptly greeted with a welcome page that states the router could not configure itself, and thus has no connection to the Internet. It shows a few scenarios that one can check for problems, also suggesting one should consult again the third-of-a-page-handbook, and, failing all this, to try manual configuration of the router.

After about an hour of changing IP addresses of the WAN and LAN interfaces (and where is the WiFi interface? or is it linked to the LAN or WAN?), I have finally given up again. I’m not a networking überguru, but I know a bit about routing and setting up IP interfaces, and this thing just managed to get on my nerves. You cannot find a clear manual with diagrams of network connectivity, setups and scenarios, a description of the theory of operation of the hotspot, and as it has been shown, sending emails to FON support is usually futile. The forums are more helpful, but not because there is a healthy bunch of FON staff there, but because a number of talented and skilled individuals have taken upon themselves the task of helping others through the ordeal.

I’m sure that a lot, if not most, users that plug in the FON router can simply connect to it, register and start surfing, but in cases like mine, where I simply have a DSL router to which I plug in the FON router and it’s supposed to work – but doesn’t – a blank void is all there is left to stare at.

Maybe a last attempt will be to flash the new release of the firmware, once they have fixed the problems in v.0.6.6

Bottom line is that FON cannot expect to create a WiFi planet with people roaming for free on the 1 million routers they are going to distribute, once they get their logistics right, based on complex hardware that requires from either skilled operators, or very good tech support and clear setup and troubleshooting guides. A couple of days ago, someone posted on the forum that FON was a beta company. How can a company class itself in beta? It can have a service in beta, but the company must be running, if not totally smooth, at least with agility and responsiveness, fixing its problems quickly and providing first-class customer service.

The reason why WiFi USB adapters suck

People use USB WiFi adapters for a number of reasons, maybe their laptop doesn’t have built-in WiFi, or like me, there are no cards yet available that fit the tiny pseudo-PCMCIA slot of the MacBook Pro. Yes, I know the MBP has built-in WiFi, but my personal interest and professional activity involve using WiFi in alternative ways, so I need to test antennas, adapters, software and so on.

A few weeks ago, I bought a D-Link DWL-G122, the thought being that since it could be connected to a long USB extension cable, there wouldn’t be any of the RF losses associated to coaxial cables – and so I could go wardriving with a potentially better setup than the usual PCMCIA card with a pigtail and coax running to a roof-mount antenna. And I was wrong. The results were appaling – even the Vaio’s internal IPW2200 card was much better, detecting over twice as many access points as with the D-Link.

How could this be? Logically, having the antenna attached directly to the RF port of the WiFi adapter should reduce loss considerably – but it wasn’t the case. To be sure, I went shopping again, and this time bought a Conceptronic C54RU. One would think that the D-Link, costing around 39$, would have better performance, since the Conceptronic only cost me 25$ – there just had to be something there to justify the price difference. To my surprise, performance was almost identical. This prompted me to pry open the two adapters, and this is what I found:

181730312_9f9b647046
No, I didn’t just photoshop a clone of the first PCB. It is the same PCB for both adapters – which means that some OEM/ODM company is manufacturing these devices, and selling them in customized plastics to whoever wants them. Paying attention to quality? Probably not their very first priority.

The next two photographs show a little explanation on the structure of the RF section of these adapters. Do not confuse the PCB antenna as a diversity arrangement, it is basically a center-fed dipole. The designer paid no attention to the large mass of grounding material right next to the large pads of the antenna, and the matching circuit could probably not do much to alleviate the poor design. Here is the actual stripline [click the image for a larger version]:

181730309_4ffed07273

And the test connector:

181730313_8376d519b7

Bottom line: if you are close to your access point, and don’t really care about the range and quality of the link, this may be the adapter for you. But, if your intention is to take these devices for a wardrive, well, don’t.

Unix Course: The Shell, and Shell Programming – Lecture 2

The inside of Athena Unix

Today we will continue discussing the shell.  We will start by covering the differences between the different shells which are available.

There are 4 shells available on the various Athena machines:

. sh    . csh      . ncsh     . tsh

Actually, when you run csh on Athena, you are really running ncsh. The major difference between the two is that ncsh allows you to use command completion (esc) to complete program names or file names. In the rest of this lecture, when I refer to csh, I am really talking about both csh and ncsh.

sh is the “standard” shell used under UNIX (but not Athena UNIX).  You will often hear it refered to as the bourne shell.  The bourn shell does pretty much what you would expect a shell to do.  You will find that most shell scripts are written in using the bourne shell. 

csh is the shell that most of you probably use if your use of UNIX is on Athena. We discussed some of the builtin commands for that shell.  Of course, you can also issue the usuall UNIX commands (which are actually programs) from the c-shell too (just as you can from the bourne shell).  Let me list some of the differences between the c shell and the bourne shell.

. history

The c shell has a history mechanism.  If you set the history variable to a number, it will remember that number of previous commands, and you can use the history to reissue the commands, even make changes to them before reisuing them, or fixing mistakes.  Another difference brought about by the use of ! for history is that if you really want to use an ! in the command line, it has to be quoted.   

. use of ~

The c shell allows you to specify a users directory as ~user.  The ~user is actually expanded by the shell to the full path of his/her login directory. The c shell reads .login when you log in instead of the file .profile which is ready by the bourne shell.  Similarly, the shell init file is .cshrc instead of .shrc.

. alias

Last I mentioned how the alias command could be used to declare a synonym for another command (or sequence of commands).  It too is one of the differences between the c shell and the bourne shell.

 TSH

The last shell I mentioned was the t shell.  tsh is similar to ncsh except it has a few (more) added features.  One of the added features is an emacs like history mechanism.  To edit previous commands emacs editing commands can be used.  I don’t think that tsh is available on any of the Athena machines except Charon. Use the man command to find out more about each of the shells I mentioned.

Environments and Variables

There are two commands in the c shell that can be used to set variables.  They are

set and setenv

set is relatively straight forward.  You can set the value of a variable to be a string.  These variables can then be used later in the shell by preceeding its name by $.  For example, if I said

set var1 /mit/b/c/bcn/file1

I could later edit that file by saying

emacs $var1

Some variables are used by the shell itself.  For example, the value of the “history” variable specifies how many lines of history are to be kept.  A few other variables used by the shell are

notify = immediatly tell of changes in process states
noglob =
time   = if a command user more than time cpu seconds, it gives stats on usage upon completion
prompt = your prompt

It is important to note that the values of the variables set by the set command are not available to programs which you run under the shell.  In order to have the values visible to the programs you run it is necessary to use the setenv command.  When a variable is set using the setenv command, its name and value is added to a string (usually quite long) which is automatically available to programs running under the shell.

A few useful variables in your environment are:

HOME
EDITOR
TERM
PRINTER
ROGUEOPTS

Variables can be unset using the unset and unsetenv commands.  You environment can be seen using the printenv command.
History

As I mentioned before, the c shell provides a history mechanism whereby you can repeat previous commands, and or change them or correct them and then reissue them.  The variable “history” should be set to the number of lines of history that you wish the shell to maintain. 

The command “history” will list those commands that are remembered. In order to reuse a command, the shell uses the “!” character.  By far the simples form of this is the “!!” command which is replaced by the last command.

!word is replaced by the last command line beginning with that word.
!number is replaced by the command line whose number (listed by
 history) is number.
!$ is replaced by the last word of the previous command

There are many more commands which can be used to modify previous commands.  For instance,  !mv:s/foo/bar/ will find the line beginning with mv, and it will replace foo by bar, and then execute the command. I refer you to the c shell manual page for more commands.

.history file

If you have a .history file, the shell will remember your previous commands between logins.  In other words, you can log out, and back in, and it will remember the command you typed in you previous login session.

I should also mention here that the command editing in the t shell uses emacs like editor commands.

Process Control

How is it that the shell runs other programs.  A little background is in order first. Under UNIX, the only way to create a new process is with the “fork” system call.  What the fork system call does is it creates a new process which is a copy of the current process.

Another uaseful system call is the “execute” system call.  The execute system call takes as arguments a filename, and a list of arguments. It then replaces the current program with the contents of the filename specified as the program, passing it the arguments which were specified. 

When a shell wants to run a new process, the fist thing it does is it tries to open the standard output and standard input if either has been redirected.  It then forks.  Each fork then checks to determine if it was the parent process or the child.  The parent process then waits for the child to finish (or for the user to type ^Z), while the child uses the execute system call to replace itself with the desired program.

Pipes-

When a sequence of programs are specified in a pipeline, the shell starts the first process as described above.  For the standard output, it opens pipe pretty much as it would open a file.  The process created by fork then has access to the pipe as the standard output. The next thing the shell does is it changes the descriptor for the pipe from the standard output (file 2) to the standard input (file 1), and starts the second program in the pipe as it would do so normally. Becuase of the way open files are passed to child processes, the standard input for the second program is in fact, the same file descriptor (or pipe) as the standard output to the first program.

Expending this mechanism to a three program pipeline should be failry straightforward.

Stoping and starting programs-

The shell keeps track of those processes which are running under it. The jobs command can be used to list them.  The shell commands stop, fg, bg, and a few other commands can be used to start and stop these processes.  bg tells the shell to start a child process in the background. Background processes are unable to read from the terminal, but they can write to it.  The fg command tells the shell to run the process in foreground.  A foreground process (often considered the current process) has control of the terminal.  Hence, when a process is running in forground, the shell waits for it to finish before returning you to the shell.

No A2DP in OSX – maybe if Apple made a Bluetooth stereo headset…

Last night I was watching a DVD on my MacBook Pro, and remembered that I still kept a Motorola Bluetooth stereo headset from the time I was working at SouthWing and we designed such devices.

Bluetooth stereo headsets use a profile called Advanced Audio Distribution Profile (A2DP), which allows them to receive medium-quality audio at 16kHz from compatible devices. Most USB Bluetooth dongles sold recently have the profile in their drivers, and there are some mobile phones from Nokia, Samsung and Motorola that also feature this profile. The advantage is that you can listen to music wirelessly, and also control the player from the headset, as they feature the usual forward, back, play and pause controls.

Once I found the headset, I switched on Bluetooth on the Mac, and started the pairing process. The headset was recognised just fine, and pairing completed, but I noticed that it had been connected as a Handsfree device, with A2DP nowhere to be found. Since there doesn’t seem to be a method of connecting the headset permanently, so the audio is always routed from the Mac to it, the attempt was frustrated – I couldn’t even listen to the DVD in low-quality audio.

Why has Apple left out this profile, is it a blunder, or a calculated approach? As to this date, Apple doesn’t manufacture or resell any Bluetooth wireless headsets (only one can be found at their store, and it comes with a dongle for the iPod, so it doesn’t count). So, why would they have an interest in adding the A2DP profile, so that we could use any other headset? If they are in the process of designing their own, they might want to keep the profile away from Macs until they launch it.

Then again, if we give Apple a vote of confidence that they are not that insidious, it could be a blunder. And a big one. Windows has been able to work with A2DP headsets since late 2005, so they have had plenty of time to add the profile to their Bluetooth stack.

A few myths and facts about Bluetooth, versions and profiles for the curious:

1. Profiles are mostly independant of the Bluetooth version. It is perfectly possible to have A2DP in a V1.2 Bluetooth device, just the same as a V2.0 + EDR can have just two profiles and miss many of the usual ones – the mix is up to the manufacturer and driver supplier.

2. EDR stands for Enhanced Data Rate – this does not increase the range, just increases data throughput from around 700kbps to around 2.1kbps, by using a different modulation scheme. The Bluetooth protocol and profiles stay just the same – the advantage is that since data takes almost 1/3rd of the time to send compared to non-EDR devices, there is a considerable power consumption reduction.

3. “Device Y doesn’t support profile Z”. Again, this is up to the manufacturer, and it’s hard to add new profiles, specially in embedded devices. Some chipsets use masked ROM, which means that the Bluetooth stack, profiles and other settings are burned at the time the silicon is printed – so, no software updating on these. Masked ROM is considerably cheaper, although has an initial setup cost of $100.000, so it’s only good for high-volume production runs. The chips can drop $1 to $2 compared to the flash EEPROM counterparts.

As an example of a very poorly implemented Bluetooth solution we can find the Logitech MX5000 keyboard and mouse combo – it sucks. A lot. I am preparing a review that will try to investigate why it does the stupid things it does, such as repeating the first letter you type when it wakes up a dozen times, or why the mouse starts wondering around the screen as if it was possessed by a poltergeist.