Be Newsletter
Issue 94, October 8, 1997
Table of Contents
BE ENGINEERING INSIGHTS: Help! I Think I Might Have Bought an NC
By Erich Ringewald
Ever interested in broadening my understanding of the world
around me, I recently checked into the web sites of IBM,
Sun, and NCI (the subsidiary of Oracle which incorporated
Navio and is dedicated to producing network computers under
the benevolent and watchful eye of Larry Ellison) to have a
look at their NC offerings.
An NC, as far as I can tell, is a computer designed to run a
web browser, has a convincing Java implementation, can't be
screwed up by the user, has no local storage, can be booted
from a server and configured remotely by an all-knowing
authority. Also, it should be cheap. And most people seem to
think it would be a good idea if it did all this without any
Microsoft software whatsoever, although that's mostly coming
from manufacturers, not end users.
Some quick perusals of the web sites quickly yield a fairly
traditional profile: a slim box with a non-Intel processor,
no IDE, serial, parallel, or any peripheral connectors to
speak of, an SVGA connector, keyboard and a mouse. Usually
they're packaged in a handsome black design, and carry price
tags around $700 (to start, monitor not included).
Of course, the value of these things is lower cost of
ownership, and we're not just talking about purchase price,
because we all know the real price comes from operational
costs after the machine has been bought.
What I don't quite understand is the reason for a whole new
computer to run this new software. I actually just bought a
machine down the street (for which purpose I'll not
disclose) which on closer inspection was a lot like the
machine I just described. I saw it advertised in a not very
elegant ad in Microtimes:
166 MHz Pentium MMX
32 MB RAM
1.44 MB Floppy
S3 Accelerated Graphics (2MB RAM)
Case/Power Supply
Keyboard/Mouse
Price: $495.
It needs a monitor, but as it stands, it seemed like it
would make a pretty powerful NC. But what it needs is
software.
You see, if I forget about all that fancy NC hardware which
people want to sell me, and focus on the software which might
make the machine I mention above an easily and remotely
configurable NC, I realize that the NC argument is and
should be a software argument. The computer above, relieved
from the worries of a previous life imposed by Windows '95,
could remotely (DHCP/BootP) retrieve a nice, simple and fast
OS designed for web based computing and be as cost-effective
an NC as anything in a fancy box from a NC
hardware manufacturer.
I guess it's just more fun to build your own hardware. Or
maybe it's easier to disguise your real intent. Never
underestimate the possible manifestations of that less
talked about Freudian condition, "Bill Gates Envy."
To paraphrase an old saying, if you're a hardware company,
everything looks like a hardware problem, even a software
problem.
News from the Front
By William Adams
So, is a spinlock a good thing? Last week when I went over
what might be a typical spinlock implementation, astute
readers immediately pointed out the flaws in the
implementation, which is a good thing. I'll get back to
that.
Why would you bother trying to implement such things in the
first place? Well, many times you might think system
resources are limited and must be preserved at all cost, and
that system overhead must be minimized wherever possible.
This sometimes leads developers to try and optimize areas
they believe to be piggish before looking at their own
algorithms.
Why did I use spinlocks as an example? Because, there is
often times an assumption by speed demons that any function
that calls into the kernel must be slow, and therefore is
subject to optimization. Spinlocks are often thought of as a
mechanism that provides a faster fine grain locking
mechanism than semaphores.
The BeOS is a awesome system to work with, and very
efficient at many things. If you have experience with other
operating systems that do multi-threading, you might think
it would be piggish doing certain things.
Multithreading from the bottom to the top is truly our
motto. This has been the case from the first Hobbit-based
BeBox to the multi-Pentium systems we run on today. If there
is one thing we do right and efficiently, it's dealing with
multiple threads running on multiple CPUs. That includes
scheduling, locking critical areas, managing interrupts,
etc. I think the BeOS handles these features much better
than many other operating systems I have used in recent
history.
One feature of programming in a new environment is that
there are not shelf loads of books of the "Undocumented"
variety available yet. Although this form of book tends to
be a bit tedious at times, they do offer one very useful
insight. You can typically find out the things that the
standard documentation didn't tell you. That is, patterns of
usage, and boundary cases.
The BeOS documentation is wonderful in explaining how things
work, and although we try to tell you every minute detail of
using every function, we may not meet your needs in all
instances. But, being the industrious, inquisitive undaunted
programmer that you are, you've taken to reading through
headers to supplement your knowledge as much as you can. Of
course this process is not ideal and in certain areas you
must deduce certain behavior, and sometimes those deductions
can be wrong.
If you are interested in how to control a thread's access to
critical data, or interested in controlling the order of
processing that occurs in your application, you absolutely
must read the documentation on semaphores, which can be
found on your BeOS disk at:
file:///boot/beos/documentation/Be%20Book/kernel/sems.html
If you are new to multithreaded programming, but you love to
do experiments with programming, you might do some reading
on semaphores and come to the conclusion that you can do
better. Last week's sample code is a typical example of how
you might try to implement it on your own.
For instance, if you're coming from the UNIX/Solaris/Linux
world, you might have read "UNIX Systems for Modern
Architectures" by Curt Schimel and come across section 9.2
Spin-Locks. It seems like a good idea. A fine grained
locking mechanism that doesn't do too much other than waste
CPU cycles. So you start to implement...
First you see that you need a test_and_set() function. It
needs to flush caches and test and set a value in an atomic
way. Using swap_atomic is what is advocated, so you go
traipsing through the Be documentation looking for such a
function. Not finding it directly, you start looking through
headers and come across SupportDefs.h which has nifty things
like atomic_add , atomic_and , write_32_swap , and the like.
You take a gamble and come up with:
long test_and_set(volatile long *addr)
{
long old_value;
old_value = write_32_swap (addr, 1);
if (old_value == 0)
return 0;
return 1;
}
It's close, but not quite. First, the write_32_swap()
doesn't return a int , but your compiler doesn't complain, so
you think you're safe.
The code that will call this function wants to do one thing.
If the value is 0, then set it to one atomically and return
the fact that it was 0. If it is 1, then return the fact
that is a one.
The proper way of doing this is to use the atomic_or
function. The atomic_xxx functions return the value that was
in the variable before it was changed. Thus, if it were
already a 0, it would return that and the current value
would now be a 1. If it were a 1 to begin with, it will
return that, and it will remain a 1. Ahhh... perfect.
long test_and_set(volatile long *addr)
{
return atomic_or(addr, 1) ? 1 : 0;
}
But you're not done. There may be multiple CPUs in the system.
Do you need to flush caches explicitly so that the other CPUs
will know that the memory address changed? Do you even know how
to get to the caches? Or did that happen for you automatically
when you used the atomic_or function? And how costly is that
spinning anyway?
In the BeOS, and any other system for that matter, the
atomic_xxx operations are supposed to be guaranteed by the
OS vendor to do all those things. Flush caches if necessary,
and utilize the proper CPU instructions to achieve the
desired action while disallowing other actions from
interfering.
The critical method of the ASpinLock class is the Lock() method
itself. It does the test_and_set forever until it actually gets
a hold of the "lock." Is this a good thing to do in user space?
Not necessarily. Since the BeOS is preemptive, your process is
subject to rescheduling. That means the kernel gets involved and
does some context switching, which is what you might have been
trying to avoid in the first place.
int ASpinLock::Lock()
{
while (test_and_set(&fLockStatus) == 1)
;
return 0;
}
What does that leave you with? Back to the Benaphore? Yes,
of course. A Benaphore as explained in a previous newsletter
article is a very fast, efficient locking mechanism. It has
been written, debugged, and presented for your usage in the
documentation. It does a quick test on a atomic variable,
and then uses a semaphore if necessary. Yes, you make a trip
to the kernel, but you were probably headed there anyway.
Spinlocks are still a very useful locking mechanism, when
implemented correctly and in the right places. If you are
writing kernel device drivers, spinlocks are your best
friend for protecting critical sections of code. You will
find drivers/KernelExport.h provides you with the
appropriate function calls for your device driver to handle
spinlocks. The following header file comment gives you a
good idea of proper spinlock usage:
/* ---
spinlocks. Note that acquire/release should be called with
interrupts disabled.
--- */
That right there is your clue the spinlocks aren't quite as
easy to implement as they seem.
In short, we do the work, so you don't have to. We speak to
CPU vendors and find those special commands that make atomic
actions work on 603, 604, x86 and other CPUs. They aren't
always obvious, and usually require assembly coding. Fine
grained locking is typically something you do in the kernel
space; in user space, you're better off with the semaphore
and Benaphore techniques.
Armed with a locking mechanism, what can you do? What good
are they anyway? It seems they will just slow down your
application.
Locking mechanisms are the most fundamentally useful
techniques to use in a multi-threading, multi-CPU
environment. If you are new to all this, then I would
recommend some reading: "Object-Oriented Multithreading
Using C++" by Cameron Hughes and Tracy Hughes (Wiley). This
is not a book on doing multi-threaded programming on the
BeOS, but it does cover many of the features, concepts and
techniques common to any multithreading environment.
Major or Minor?
By Jean-Louis Gassée
This refers, of course, to our latest BeOS release, DR 9.1,
also known as Preview Release 2 (or PR2). If we go by the
conventional wisdom of numbering conventions, since the "1"
numeral is on the right hand side of the decimal point, this
is a minor release. We know how this very convention keeps
being abused for obvious marketing reasons, or more tortuous
contractual ones, but, in our case, we don't mind the label.
One could summarize PR2 as the product of things we
shouldn't have done, bugs, or things we should have done,
features that didn't quite make it into the original Preview
Release (PR1), such as, but not limited to, better handling
of HFS volumes or the 3D kit. This doesn't mean we're not
happy and proud of this latest release, we feel indeed it is
a nice ".1" release, but, on the other hand, we're just
doing what we're supposed to do.
The Preview Release was a risky effort, entailing many
internal changes in the foundation of our OS, the new 64-bit
file system being the most visible one. As a result, we were
late by about 6 months, not an uncommon occurrence, but not
an excuse either. With this in mind, one piece of good news
regarding PR2 is we're back on track, correcting problems
and adding features on a more regular basis.
As always, what we think of our work matters only very
little. The verdict is in the hands of developers and early
adopters. With PR1, we saw the beginning of commercial BeOS
applications being shipped and sold. We hope PR2 will make
life easier for our partners and customers and will generate
the most precious commodity in our business, positive
word-of-mouth.
Speaking of which... We owe thanks to all developers and
users who gave us feedback after PR1 came out. Their
comments, positive and negative, have given us information
and motivation for the improvements, visible or not, you'll
find in PR2.
As usual, we're nervous when a new release comes out: Have
we overlooked some obvious problem, are we causing
incompatibility grief to our developers, in our eagerness to
correct problems have we caused more damage? We'll know very
soon and, if need be, we'll post updates on our site.
From now on, our focus is on the Intel release and on
helping BeOS developers test that version as soon as
practical in order to open the gates to this bigger market
in the most effective fashion for all of us. This is a new
set of challenges. We realize there is more to the Intel
world than a new instruction set, but we look forward to the
task nonetheless.
BeDevTalk Summary
BeDevTalk is an unmoderated discussion group that's a forum
for the exchange of technical information, suggestions,
questions, mythology, and suspicions. In this column, we
summarize some of the active threads, listed by their
subject lines as they appear, verbatim, in the group.
To subscribe to BeDevTalk, visit the mailing list page on
our Web site: http://www.be.com/aboutbe/mailinglists.html.
-
Subject: Searching for an example for
fs_create_index()
The initial request, as described by the Subject line, led
to a discussion of the nature of attributes, the BFS Btree,
and the speed of the file system. Be's Dominic Giampaolo ran
some tests that stressed the file system's ability to update
its indices, posted his findings, pointed out the system's
shortcomings, and vowed to improve the situation. Other
listeners called in with their own benchmarks and a few
questions:
- Since it's not possible to have "invisible" files, what
should you do to protect attribute-only files from being
deleted by a curious user?
A number of listeners suggested that attribute-only files
sounds like a database -- and the BFS isn't meant for
industrial-strength database support.
- Will multi-user support change the way attributes are
stored/protected/accessed?
Some listeners objected to the practice of storing user-info
(configurations, protections, etc.) as attributes of a file.
The popular opinion is that files should be protected by
uid/gid and the permission flags -- files shouldn't be
selectively shared based on the value of an attribute.
- How many files within a single directory are "too many"?
Some difference of opinion, here. There was some consensus
that once you get in the 10,000 file range, you'll start to
lose performance. But is it the file system or the Tracker
that's the culprit?
It was offered that displaying (and Node Monitoring) 10k
files takes a significant bite -- but, then again, a window
that contains that many files isn't a great user experience
at any speed.
-
Subject: Networking woes
Subject: restarting networking
- Do you need a hub to get a BeBox to talk to another
computer?
Nope, (says Stephen Beaulieu), all you need is a "cross-over
cable." Want more info? Ken Causey pointed out this URL:
http://wwwhost.ots.utexas.edu/ethernet/10quickref/ch5qr_5.html#HEADING4
- How do you restart networking programmatically?
The simple answer: You can't.
A longer discussion ensued: Is there any reason to restart
networking? It would be better if changes to network
settings were propagated as they occur, rather than dropping
connections and demanding that the net daemon be
re-launched. It was agreed that while the current
implementation isn't ideal, it's considerably nicer than
demanding a reboot. Or is it? Osma Ahvenlampi says...
"For a server, it's the same thing. Who cares if the machine
[is rebooting] or not, if all the network connections go
down, it's down."
-
Subject: libraries and source code
An old friend re-visited: Should a developer use a library
that doesn't include source code? To a library developer (as
is Jeff Abrahamson, who re-started the ball rolling), the
issues are these:
- If the source code is included, piracy is more likely.
- If you don't include source, developers are less likely to
use the library for fear of not getting adequate support
(they'd like to be able to patch the code themselves).
Mr. Abrahamson continued with a proposal:
"Does it suffice to have the *option* of purchasing the full
source code for, say, twenty times the cost of the
library... You don't need to buy it unless you have a
problem, but if you do you can always spend the money to buy
the source."
Ed Musgrove modified the "no source, no service" attitude:
"We developers are interested in debugging -- we do not need
the source code for any other reason. A sophisticated
solution might be to create a #ifdef DEBUG block and ship
two versions of the library."
This was seconded by a number of entrants. An additional
thought, that all library developers should place their
source code in escrow in anticipation of belly up day, was
also heartily cheered.
Jon Watte didn't disagree, but that didn't stop him:
"...anything starting with two underscores is the SOLE
property of the compiler vendor. You should not use it. It
is not ANSI, it is not portable, with the exception of the
__cplusplus constant (and other well-defined constants such
as __STDC__ )"
and
"...#ifdef is a left-over from the first version of K&R C
that should not be used in modern production code, because
it is inflexible and there is a better variant: #if
defined(x) "
This led to another topic: Should bad code be forced to
crash? Two schools:
- It's bad for the user if a program crashes. Better to give
the app the benefit of the doubt (and the user a more
pleasant experience) by not
assert() ing argument formats
and types.
- It's bad to write sloppy code. And sloppy programmers are
probably also sloppy testers. We should force the bums to
eat their own code.
-
Subject: Compatibility vs. "The Right Way"
Is binary and API compatibility worth maintaining at the
cost of lost improvements and features? Relatedly, does the
impending Intel release have anything to be compatible with?
A number of listeners phoned in to say that breaking the API
between PPC and Intel is not a good thing -- they may not
affect each other directly, but maintaining two sets of API
is never desirable.
This led to the broader question of cross-compiles and
testing: Should a developer cross-compile to a platform that
isn't sitting on the other side of the room? Some folks think
that "absentee" development is prone to bugs. But Bill
Morris has a slightly different attitude:
"Strangely enough I code Java on the Mac using CodeWarrior
and Netscape 3.0 just to avoid having to do that [test on
each platform]. The basic theory is that since Java on
Netscape 3.0 for Mac is absolutely horrible if it works
there it will work better everywhere else..."
One of our more frequent contributors suggested that a
cross-compile panacea is a pipe dream. Another frequent
contributor objected, citing a known, if defunct, example.
Fur flew a bit.
-
Subject: BeOS security
A follow-up to the recent "BeOS as a Server" thread. This
week: Security. If, as some people hold, the BeOS is to be a
credible server OS, it needs to have tighter security.
Thoughts?
Encryption schemes, security authentication methods and
levels, network protocols, user authorization... There was
no end to the topics. Michael Crawford lightened this
acronymically-inclined thread with a story about Navy
security:
"One thing they had to do was install a power line filter
because the inspector thought that spies could read the data
off the power line from across the harbor. They found a
filter in a surplus yard that my dad described as costing
tens of thousands of dollars when new... Another thing they
do in secure installations -- you _can_ use a network, but
you have to ensure no one taps into the net. The way they do
that is to run the wire through a pressurized pipe. If
someone drills into the pipe, then the pressure loss sets
off alarms."
|