Issue 2-10, March 12, 1997

Be Engineering Insights: By The Node Monitor

By Cyril Meurillon

The Node Monitor is a new service that will accompany the DR9 file system. It lets your application ask to be notified when certain changes are made to a file or directory. For example, you can "watch for" the creation and deletion of files within a directory, for the modification of a specific file's attributes or name, and so on.

As a built-in feature of the file system, the Node Monitor is part of the kernel: It's always there. However, it's anticipated that most applications won't need the Node Monitor; watching the state of the file system is important to servers and to navigational applications like the Tracker, but your Tetris killer—or even your Excel insulter -- probably isn't going to care.

The Node Monitor is, in our estimation, an advanced feature; the API for the Monitor is, suitably, rather low level—it's not downright unfriendly, but it does have a somewhat more mechanical view of the identity of files, as we're about to see.

CAVEAT: The API that we'll be looking at throughout this article isn't set in stone. Although the general concepts should remain valid, some of the names may change before DR9 is released.

To tell the Node Monitor that you want to watch for changes, you use the global watch_for() function:

watch_for(ulong flags, dev_t device, ino_t inode,
  constBHandler *handler, constBLooper *looper);

The file or directory (or "node") that you're watching is represented by the combination of the function's device and inode arguments. (Conversion between device/inode and the entry_ref structure/C++ objects, which were described in last week's Newsletter, will be provided by the Storage Kit.)

The activities that you're interested in watching are represented by the constants that you pass through the flags argument:

The special flag B_STOP_WATCHING can be passed to stop watching the node.

When a change is detected, the Node Monitor generates a BMessage and sends it to the "watcher" (a BHandler object) that's specified in the watch_for() call. The watcher receives the message in its MessageReceived() function. (The Node Monitor divines the target from the handler and looper arguments through a series of logical steps that are really not very interesting.)

Each of the watched-for flags corresponds to a particular type of message: B_WATCH_NAME generates a B_ENTRY_MOVED message, B_WATCH_STAT generates B_STAT_CHANGED, and so on. We'll look at an example of the Monitor's messaging later in this article.

Monitor Vs. Live Queries

Tres bien, you dit to yourself, mais, comment c'est en mieux a la 'Querie Vif!' en DRHuit? ("How is this better than DR8's live queries?")

True, you could "watch" changes to files and directories in DR8 by installing a live query with the Storage Server—this is how the Browser kept its folder windows in synch with the file system, for example. But a live query can (or could) only watch for changes to fields in the database tables that represent the items in the file system. In other words, this sort of monitoring worked because certain file system parameters (file names, creation dates, and so on) were stored in the database. But in DR9 we're going start supporting foreign file systems, and these file systems (HFS and DOS, for starters) don't know anything about Be-native database facilities. Thus, a live query can't work on a foreign file.

This is where the Node Monitor can be useful: It's a "universal" service for spying on files and directories in any file system. Some file systems may not provide complete snoopage; it's likely that you won't be able to monitor attribute changes in DOS simply because DOS doesn't know about attributes. But one of the line items in the contract for becoming a "File System Handler" is that stat and directory-content information MUST be emulated. In other words, the DOS file system handler knows how to fake a stat structure. Thus, you'll be able to, at least, watch for changes to the arrangement of files in any mountable file system.

Note that the Node Monitor isn't a replacement for live queries. But neither are live queries going away: In DR9, you'll have the best of both worlds.

Example (Print Server)

Let's consider an application that uses the Node Monitor: the Print Server. When you print, the data that you're printing is written to a "spool file." It's the Print Server's responsibility to:

  • Detect the presence of a new spool file.

  • Wait for the file's "status" attribute to change to "waiting" (this indicates that the file is ready to be printed).

  • Change the status to "printing" and print the file.

Spool files are always written to a known spool directory; to detect new spool files, the Print Server asks the Node Monitor to inform it of new entries in this directory:

PrintServer::PrintServer() : BApplication('PRNT')
{
  dev_t spoolDevice;
  ino_t spoolInode;

  // Get the device and inode of the spool directory
  get_inode_for_path("/boot/system/spool", &spoolDevice, &spoolInode);

  // Start watching for new files in that directory.
  // The final two arguments tell the Monitor to send
  // notifications to this object's preferred handler.
  watch_for(B_WATCH_DIRECTORY, spoolDevice, spoolInode, NULL, this);

  // We're also going to need another looper later.
  fStatusWatcher = new StatusWatcher();
  ...
}

When a spool file is created, a B_ENTRY_CREATED message is sent to PrintServer's main loop. The what for Node Monitor messages is always B_FS_NOTIFICATION. The Monitor message type is in the opcode field:

long PrintServer::MessageReceived(BMessage *msg)
{
  dev_t fileDevice;
    ino_t fileInode;

  switch (msg->what) {
  . . .

  case B_FS_NOTIFICATION:
    switch(msg->FindLong("opcode")) {

    case B_ENTRY_CREATED:
      // Get the device and inode for the file;
      // these are stored in the message.
      fileDevice = msg->FindLong("device");
      fileInode = msg->FindLong("node");

At this point, the Server knows the identity (as a device/inode) of the new spool file. Now it waits for the "status" attribute to change to "waiting" by asking for an attribute-has-changed notification. Obviously, the Server has to find a different watcher for these notifications -- that's why we defined the fStatusWatcher object:

      watch_for(B_WATCH_ATTR, fileDevice, fileInode, NULL, fStatusWatcher);
      . . .
    }
  }
}

(Note: There's a race condition in this code: What happens if the spool file is already "waiting" when the first notification is processed? The solution is left as an exercise for the reader.)

Over in the StatusWatcher handler, we find...

long StatusWacher::MessageReceived(BMessage *msg)
{
  dev_t fileDevice;
  ino_t fileInode;
  BFile spoolFile;
  char buf[16];

  switch (msg->what) {
  case B_FS_NOTIFICATION:
    switch(msg->FindLong("opcode")) {

    case B_ATTR_CHANGED:
      // make sure this is the status attribute
      // that has changed.
      if (strcmp(msg->FindString("attr"), "status") != 0)
        break;

      // Again, convert the msg into a
      // device/inode and thence to a BFile...
      fileDevice = msg->FindLong("device");
      fileInode = msg->FindLong("node");
      spoolFile = BFile(fileDevice, fileInode);

      // ...and read the "status" attribute.
      spoolFile.ReadAttr("status", buf, sizeof(buf));

      /* if the status isn't "waiting", get out. */
      if (strcmp(buf, "waiting") != 0)
    break;

      /* Set the status to "printing" */
      /* and print the file. */
      spoolFile.WriteAttr("status", "printing", strlen("printing")+1);
      SendToPrinter(spoolFile);
      . . .

Again, remember that the file system API is still subject to change, so don't start porting your code on the basis of the names shown here.


News From The Front

By William Adams

The early adopters and developers on a new OS platform exhibit behavior that might be considered obsessive and irrational. When I first received my BeBox™ last year, I couldn't help but read every shred of information available in the newsgroups, and I hungered for e-mail exchanges with like-minded folks. I longed for new web sites and new software on any ftp site.

This hunger and desire reaches a fevered pitch as a 'release' date approaches. DR5, DR6, DR7... Well, it's been a long time since a release, and DR8.2 for many has been the first release. Not wanting anyone to burst a blood vessel waiting for their next fix, we've decided to release DR8.3. This is really just a maintenance release and doesn't offer any new functionality. You'll find all the details about this release on our Web site this week. The general gist is, this release is for the Power Mac only, not for the BeBox (BeOS for BeBox does not have the limitations that DR8.3 removes).

In DR8.2, the font renderer had a limited license that required us to have a termination date, past which the OS wouldn't operate. We've changed font providers, and this requirement has been removed.

Serial support wasn't included in the DR8.2 CD that shipped with MacTech. This release includes it.

There may also be a few more bug fixes, but that was not the purpose of this release. The long and short of it is, IF YOU'RE RUNNING DR8.2 ON A POWER MAC, YOU SHOULD DEFINITELY INSTALL THIS UPGRADE!!

You don't want to interrupt your endless stream of BeOS fun, so get this thing and install it immediately!!

Since we're the digital content creation platform of choice for discriminating artists, I thought I'd throw up some more code of the digital content variety. There have been quite a few MPEG encoders and decoders in the air for the BeOS. I thought I'd add the code for the Berkeley decoder just for fun.

ftp://ftp.be.com/pub/Samples/mpeg_lib.tgz

This library isn't the fastest, or smartest, or highest quality thing in the world. But the code is understandable, easy to make into a shared library, and it's free. It should be useful to those who endeavor to do similar things in the BeOS.

We will continue to provide innovative fresh fertile ground upon which you can program your heart away. And in the long run, you'll be satisfied with a job well done, until the next release.


Who's Stupid?

By Jean-Louis Gassée

We are, of course, not the programmer, or the user of our software. Making your customer feel stupid should be prohibited by the Constitution, and in any case, generating such feelings is always harmful to business. Put another way, while we can sometimes be forgiven for embarrassing mistakes, we won't make friends by generating feelings of inadequacy, especially if they're followed by a realization that the mistake was ours in the first place. Hence our decision to post our bugs on our Web site. Starting with developers, we want to get in the habit of mapping the minefield as accurately as we can. This will save everyone time and energy, a good reason to start with. Then, as more eyes see the range of reported problems, some pattern recognition might take place, meaning one or more individuals will pick up on a bad habit, or a regular trap, and share their knowledge with the community. In the same vein, our example might encourage BeOS application developers to do the same for their customers—and for the rest of us—with similar benefits.

This is all nice and good, but what about disadvantages? For instance, will the competition use this against us? Possibly. We might save their harried Competitive Studies people some time. But nasty bugs end up reported one way or the other, so we might as well do the reporting ourselves, thus minimizing distortion. Another possible criticism leveled at us for posting our bugs is you don't show customers the inside of the sausage factory. They don't want to know. To this, my answer is that if I start a sausage factory, I have to make a much better sausage than the established industrial meat processors. And, assuming I actually make a better product, I then make a point of seeking out sausage connoisseurs and taking them through the kitchen. They see the ingredients coming in, they watch the mixing process... I sense some problems with this kind of metaphor, the penalty, I guess for venturing out of my usual range. Still, many great restaurants feature a visible kitchen. For us, letting light in on our OS-making process is a healthy constraint. We'll be embarrassed on a regular basis, always good for the product and the soul. And we'll also get more helpful suggestions along the way than if we didn't open our doors.

Of course, as the bug reports show, we still have a lot to do and a lot to prove. Ironically, a maturing OS will mean even more bugs reported, not fewer, as our system gains more flesh and is stressed by more applications and more users.


BeDevTalk Summary

BeDevTalk is an unmonitored discussion group in which technical information is shared by Be developers and interested parties. In this column, we summarize some of the active threads, listed by their subject lines as they appear, verbatim, in the mail.

To subscribe to BeDevTalk, visit the mailing list page on our web site: http://www.be.com/aboutbe/mailinglists.html.

WEEK 2

Subject: Time is running out!

AKA: Streams

More suggestions and discussion of features that are essential—or, at least, desirable—for a baseline (future backwards-compatible) release. This week:

  • Intelligent versioning

  • Coalesce view update messages from the app_server (when requested)

  • STREAMS support

  • Networked BMessages

  • UNIX-style man pages

  • A well-defined system directory tree

There was some debate over STREAMS. Some folks think that BSD sockets are not only better, but that having two network port models is confusing.

Obviously, not all of the requests are essential to a baseline customer release.

NEW

Subject: endian-ness

AKA: Intel port == bad!
AKA: Dave's Raves

Was Brad Taylor's article in last week's Newsletter, in which he described the pitfalls that one should avoid when sending data between machines that are, potentially, differently byte-ordered, a hint of ports to come?

This speculation led to a discussion of the history of the little-endian/big-endian battle of the (byte) sexes. The history lesson then followed its own logic into the future, which led to general crystal ball gazing and a fantasy about little brown men that, frankly, I had trouble following.

We also heard arguments over the desirability of an Intel port. On the pro side is the thought that general proliferation of the BeOS is a Good Thing. Con has it that an alliance with Intel would be (for now) an unnecessary, resource-guzzling distraction. No it wouldn't. Yes it would.

THE BE LINE: As many of you pointed out, Brad Taylor's article was a sincere tutorial on good network programming practice. No "hints" were intended.

Subject: Overclocking your BeBox?

This thread, which sprang from the endian-ness discussion, discussed the benefits/detriments of "overclocking" (or, more accurately, "undertiming") the CPU.

Overclocking increases the speed of the CPU beyond its rated limit; typical overclocking techniques involve soldering a faster oscillator onto the motherboard (think of it as dangling a bigger carrot in front of the hamster). It works—but does it decrease the life expectancy of the chip? Some folks say, "You bet it does."

Subject: Funky networking apps

Various listeners volunteered descriptions of their personal programming projects (whether actually implemented or not). Among other things, we heard about...

  • A socket server that could be used as the basis for networked scripting [Jon Ragnarrson]

  • A port of socket++ [Howard Berkey]

  • A network-playable Stratego game [Ficus Kirkpatrick]

Other network ideas:

What about moving the network layer into the kernel? This idea met some amount of horrified resistance.

Some old favorites, such as picking up an entire executable and sending it down the wire, were trotted out and banged around.

Subject: On stability of APIs

Looking ahead to subsequent customer releases, will BeOS 2.0 break all 1.0 applications? Would modular libraries (rather than the monolithic libbe.so) help?

This led to a discussion of relative pathnames in #include directives and whether "greg" is "bill". Slow week.

THE BE LINE: In DR9, libbe WILL be broken into separate libraries. The divisions will primarily follow the kits.

Subject: Who's buried in Grant's Tomb?

Some possibilities: Grant, Lee, Lee Grant, Grant Tinker, Lee Tucker, John Smiley, "smileys," Liam Neeson, Neil Sedaka, Otis Redding, Marvin Gardens, Marvin Hamlisch, Ham, Shem, H.C. Earwicker, Gomer, Homer, Onan, Conan, Robert Donat, the Donner Party, Guess Who's Coming to Dinner?, Sidney Poitier, Sidney Greenstreet, On Green Dolphin Street, Where's Someone I Can Meet, Flipper, Ishmael, Billy Budd, Peter Grimes, Jon Vickers, Vic Damone, Joey Ramone, Patti Lupone, Lucille Ball, Bud Cort, Cary Grant, Grant's Kills Ants.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.