Displaying Newsletter
Issue 34, 22 Jan 2003


  In This Issue:
 
VM2 Design by Michael Phipps 

VM2 is a newly designed virtual memory system designed specifically for OpenBeOS. It is completely object oriented and designed for easier maintenance.

The question of the need for this project has frequently been asked - because there are many tuned VM systems already. While this is certainly true, there has only been one tuned for the usage that OBOS would place on a VM system - the BeOS VM system. There are many reasons that the BeOS VM system can not be used, but the most obvious is that the source is not available.

VM2 is designed around delegation, as one would expect in an OO system. Objects know only about themselves and their children (and, occasionally, their parents where this makes sense). With one small exception - the vmHeaderBlock. This structure is global to the VM2 system and contains pointers to some of the objects that need to be used by everyone.

Starting from the most abstract, we have the areaManager class. This class is the manager for the areas under it. One areaManager is constructed per team, on team construction. This class is responsible for handling findArea calls. Its' fault method should be called on page fault. It will determine which area is responsible and call its' fault method. Any operation that is invoked on an area comes through this class.

An area is the single unit of allocation for memory allocation for the outside world; they are often called "regions" in other VM systems. An area can be considered to be made up of three types of values:

1) Its' own identity - a name, an ID and statistics about what has happened to it
2) A list of vpages - these are where the memory is stored
3) Information that is common to all of the vpages - this is a memory usage optimization. Fields like pageState, protectType and finalWrite fit this description.

The API for an area is fairly short and simple. There are numerous accessors which will be ignored here. From the outside, there is a setup method which *** and a freeArea method which frees the individual vpages and deallocates associated memory. createArea, createAreaMappingFile and cloneArea are all the "meat" of this class.

createArea is for anonymous regions - not backed by a specific file or by another area. The heap would be a good example. These pages are backed by the swap file. createAreaMappingFile is for mmap and for shared executable files (i.e. anything loaded by the ELF loader). These methods are thin wrappers around "createAreaGuts". This method does the actual allocation of vpages.

cloneArea is a special case. It finds a pre-existing area, specified by the caller, and "clones" it - makes a whole series of vpages that are backed by the same backing store and physical memory as the original.

vpages are the heart of the system. They map a physical page and backing store to a virtual page, tying the three together. They are the only holders of this knowledge. They are constructed "empty"; a setup function sets the address, the physical page (if any), the vnode and the protectionType. There are methods (flush, refresh) for reading and writing the vpage to backing store. Finally, there are the "interesting" methods - fault, pager and saver.

Fault is the method invoked by the area when this vpage's virtual memory span is causing a page fault. Fault has two main paths to follow - is this a write that is already backed by physical memory or not. The first case can happen for two reasons - to mark the page as "dirty" or to perform copy on write. Copy on write very simply allocates a new physical page, copies the data from the original to the new page, allocates swap file space for that page, then returns. For "regular" page faults, a physical page is allocated, the backed data is loaded into that new page, and the fault ends.

Pager determines if this vnode can and should be paged. It depends on a value called "desperation", levels of need from 1 to 5, with 5 being the most needy. On a 1, the page is not paged. On a 2, the page is only paged if it is read only and present. On a 3, the page is paged if the page is present and not dirty. On a 4 or a 5, the page is paged if it is present. To page out a page, the data is written to the backing store and the physical page is returned to the pageMan pool.

Saver is a daemon which saves pages to disk periodically. This helps to keep pages available for swapping.

page is a class designed to represent a physical page. It has only one interesting method - zero, which zero fills the page.

The Pools

areaPool, vnodePool and vpagePool are all memory allocation pools. They hold a stock of "free" objects. They can add to this stock, when necessary, by allocating a physical page (page) of memory and dividing it into objects. They are wrapped in semaphores to protect them from becoming corrupted by multiple processes at once.

vnodeManager is the class that tracks which vnodes are allocated to which vpage. This is used for multiple mappings of one vnode to different vpages (i.e. with caching or with mmap).

swapFileManager is the class that manages the swapfile. It works much like a pool, of swap file space, but uses a different interface and handles more details than the simple pools.

pageManager is the class that manages physical page allocations. It, too, works much like a pool, but also has the "smarts" to allocate from the clean list first, then from the unused list (with cleaning), then to fail.

vmInterface is the front end for VM2. All calls from user land should go through vmInterface. Arguements should be checked, etc.

The Basics

list is a singly linked list, with all of the classic API to match. olist is an ordered linked list. hashTable is a hashTable (a list of lists of nodes).

And that's about it. Obviously, there's a lot more to actually doing it than that, and it takes time to implement it right - and right for OpenBeOS. But we will arrive there soon.

 
Beatrice: Coordinates, Views and Messages by Niels S. Reedijk 

Welcome back! Last time we made a start on our installer! Guess what: it won't be an installer anymore! In search of a good project, I have decided to make Beatrice the graphical frontend for CVS in BeOS. This is actually good for everyone, because working in a nice graphical environment when doing programming is lovely! But before we can even think of doing anything, we will have to get our knowledge of the BeOS API sharpened, so get ready for the real work!

This time we will dive a bit deeper under the hood of the interface kit. You know that the BeOS API is actually divided into separate kits that all have their own 'goal'. We will use the Interface kit this time. You can read more about it in your local copy of the Be Book in the documentation directory of your BeOS partition, or at the mirror of the old BeOS site, here:
http://www.beatjapan.org/mirror/www.be.com/developers/developer_library/interface_kit.html. [Editor's note: Sorry, still no hyperlinks]

The source code referred to in this article is also available for download here: http://www.openbeos.org/samples/beatrice-t2-1.zip.

Coordinates

In order to start GUI programming, you must master a very important concept, called coordinates. Pixels, those little dots on your screen, need to be addressed somehow in order to give them contents, and to track pixels we use coordinates. Coordinates in BeOS are in a two dimensional system where the y-coordinate value is higher when you go down, and the x-coordinate is higher when you go to the right. The distances are measured by floating point types, the type float. What you should remember is that one whole unit represents one pixel, so the y-value 2 represents two pixels down, and the x-value 300 represents 300 pixels to the right.

Each point on the screen is represented by two values, the first being the x-value and the second being the y-value. So, point ( 25.0 , 15.0 ) is higher than the point ( 30.0 , 2.0 ), but the latter is more to the right (look at the picture in the BeBook for more on this). The lowest coordinates in the top left position of the screen are (0.0 , 0.0). Remember this.

To work with the coordinate system and coordinates, you should remember three different types of specific coordinate systems. The first one is the global coordinate system, with its origin (0.0 , 0.0) at the left top corner of the screen. The second is the window coordinate system, with its origin at the left top corner of the window, and last, the view coordinate system, with the origin at the left top corner of a view (what views are, will be told later).

Coordinates are abstract things, and you will understand them better, when we start working with views in the next section.

Views

A BView is a containter of a particular rectangular area in a window. The BView has the means to work with the contents of that area. For example, a BView that implements a button, paints that button in the window. But it also handles any user clicks that may be on that button. Why is that good? Let's look at that first.

Imagine there wasn't something like a BView. Imagine that if you wanted to draw things in a window, like a button, and you would have to draw it yourself. And every other place you want to use a button, you will also have to draw that button and implement the functionality. A BView is an encapsulation of some functionality: it is a compact reusable class that you can use over and over again in different windows. In our new CVS frontend, we need to display a list of files, but we also need to display a list of revision numbers. So what we have is actually the 'list view' encapsulated in a BView, so we can use it over and over again.

So if we want to make a button class, we need to make it ourselves, right? Wrong! The Be API comes along with quite a few derivations from BView that implement particular functionality. For example, we have ready-made BButtons, BCheckBoxes, BMenus, etcetera. This is easier for us, but it will also make our programs look more alike. Imagine if we all had to implement these visual controls ourselves. It would make the whole user interface a mess, especially across different applications made by different developers, now wouldn't it?

As I said before, all visual controls in the interface kit inherit BView, either directly, like BStringView, or indirectly like BButton. So if we would write our own application we would only have to get a piece of paper and sketch the elements we want to use in it. So I did. Now we can move on from the theory to practise. The main elements of the main window of Beatrice should be a menu bar, a listview that shows the files, and perhaps something like the statusbar. From the previous article, we already have the BeatriceMainWindow class, and we will implement the building of the window in the constructor.

But before we can do that, we first need to see what classes we will need to implement for all of this. For the menu bar we need the BMenuBar class. For the list view we have two choices: a BListView and a BOutlineListView. The first one is an unindented list view, and it is not what we want, because CVS deals with directories as well, so to represent a directory structure we will use BOutlineListView.

On To The Code

The place to prepare and set up the code is in the window that needs to display it. As we have already overridden BWindow in BeatriceMainWindow, we can change the constructor to create the interface elements. In the header file BeatriceMainWindow.h we put the following code:

class BMenuBar;
class BMenu;
class BMenuItem;
class BOutlineListView;

class BeatriceMainWindow : public BWindow
{
public:
	BeatriceMainWindow();
	~BeatriceMainWindow() {};
	virtual bool QuitRequested();
private:
	BMenuBar *m_menubar;
	BMenu *m_filemenu;
	BMenuItem *m_quitaction;
	BOutlineListView *m_filelist;
};

Have a look at the members declared in the private section. Our menu bar is called m_menubar. We will also add a file menu of the type BMenu with name m_filemenu. In that menu we will add a Quit action. (Please note that action is the name I got from programming in Qt, it merely implies that it is a menu item). Also the list view is present. Look at the m_filelist variable and its type.

BeatriceMainWindow::BeatriceMainWindow()
                  : BWindow( BRect( 100 , 100 , 800 , 300 ), 
                    "BeatriceWindow",
                    B_TITLED_WINDOW,
                    B_NOT_RESIZABLE | B_NOT_ZOOMABLE )
{
	//Construct UI: menubar
	m_menubar = new BMenuBar( BRect(0,0,0,0), "menubar" );
	AddChild( m_menubar );
	//File Menu
	m_filemenu = new BMenu("File");
	m_menubar->AddItem( m_filemenu );
	m_quitaction = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q');
	m_filemenu->AddItem( m_quitaction );
	m_quitaction->SetTarget(this);
	
	// OutlineListView
	BRect r;
	r = Bounds(); //Assign the size of the window to the rect
	r.top = m_menubar->Bounds().Height() + 1; //Substract the height of the menu
	m_filelist = new BOutlineListView( r , "listview" );
	AddChild( m_filelist );
}

The code above is the actual implementation of the interface part. It is located in the BeatriceMainWindow.cpp file. So how do we build an interface? It's easy. A BWindow can have multiple BView's as children. So you basically create the views, add these to the window, and have fun!

In the code example above, we create two BViews: one for the menu bar and also one for the file list. The standard constructor of a BView is:

BView(BRect frame,
	const char *name,
	uint32 resizingMode,
	uint32 flags);

A BView always demands its screensize, and you need to set a name. It also requires a resizingMode and flags. However, many of the BView subclasses have their own standard settings. We've used BMenuBar, which has the constructor:

BMenuBar(BRect frame, 
	const char *name, 
	uint32 resizingMode = B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 
	menu_layout layout = B_ITEMS_IN_ROW, 
	bool resizeToFit = true) 
.

You see that both the frame and name items are mandatory, and that the resizingmode is already set. Also, the flags aren't even present (the BMenuBar class itself determines which flags it needs). As we'll probably be using standard BView deratives, I won't go deeper into the BView class itself (we'll save that for later).

Looking at the code above you can see how BViews work. However, if you look more closely to the allocation of BMenuBar, you'll see that I've given it a size of 0,0,0,0. This may look weird, and I can only explain it by saying BMenuBar is an exception. In the constructor described above, you can see that the constructor argument resizeToFit is automatically set to true, thus this means that BMenuBar determines its own size. This is actually easy, because it means that we won't have to do this ourselves. I have named the BMenuBar "m_menubar".

The constructor of the BOutlineListView is quite long and you can find it in the BeBook. Also BOutlineListView needs only two arguments to construct, and thus naturally I keep it simple by only doing these two. However, this BView derative doesn't set its own size and we should do it for it. In the last article, I had already used the BRect class, and I'll do it again. The BWindow::Bounds() method returns a rect that describes the window size. So we assign this one to our rect. However, because our menu bar has the file menu added in it, it has resized its height and we should set the beginning of the file list just below that menu bar. What I have done is I set the top of the rect, which is the starting y value to the height of the menubar plus one. I added one pixel because it looks a bit nicer, though it isn't mandatory.

After I created the BView deratives, I added these to the window using the BWindow::AddChild( BView *child ) method. This attaches the views to the window and makes sure that they are shown when the window is shown.

Creating menus

Menus are a very powerful concept, and they are very conveniently implemented in the Be API. It is quite easy for us to create and handle menu actions. The base class for menus is the BMenu class. The constructor of the BMenu class is as follows:

BMenu(const char *name, menu_layout layout = B_ITEMS_IN_COLUMN) 
BMenu(const char *name, float width, float height) 
BMenu(BMessage *archive) 
BMenu(BRect frame, const char *name, uint32 resizingMode,
      uint32 flags, menu_layout layout, bool resizeToFit)

BMenu is actually the base class of BMenuBar, which you could've guessed by looking at the fourth constructor. Anyway, to create the file menu, I use the first one, which makes sure I only have to specify the name of the menu. I named the file menu "File", which is rather traditional. To add this menu to the menubar we use BMenu::AddItem(BMenu *submenu), which naturally is inherited by BMenuBar.

The next thing we do is adding a Quit item to the menubar. The class for menu items is the BMenuItem class (how surprising) and the constructor reads as follows.

BMenuItem(const char *label, BMessage *message, 
	char shortcut = 0, uint32 modifiers = 0)

In the constructor, we specify the label (thus, the name that is displayed in the menu) for the item ("Quit" in our example). The second argument is the message argument, which implies the message that is sent when the menu is clicked (the Quit action emits the B_QUIT_REQUESTED message). The short cut is the underlined letter we can use to quickly call the action. Here I have chosen the Q. I haven't implemented the modifiers, but you can add these too if you want to asign a short cut that needs shift or control to be pressed.

We add the the menu item by using bool BMenu::AddItem(BMenuItem *item). We also need to set a point where to direct the message to when the action is selected, and we have selected this window, which calls our overridden BeatriceMainWindow::QuitRequested method automatically. This way, we get the quit functionality for free!

These are the basic things you need to know when using menus. Dive a bit into the BeBook to find out more!

Conclusion

What have we learned:

  • Coordinates are representations of a point in a two-dimensional system
  • The coordinates are represented by floats
  • The x-value is higher if you go further to the right
  • The y-value increases if you go down
  • The global coordinate system represents the whole screen with (0,0) top left
  • The window coordinate system represents the coordinates relative to the window
  • The view coordinate system represents the coordinates relative to the view
  • BViews encapsulate the functionality and looks of a screen element
  • There are a lot of standard BView deratives that have a certain functionality
  • The constructor of a BView derative requires a size and a name
  • BMenuBar is a BView that takes represents the menu bar
  • BMenuBar can resize itself
  • BOutlineListview is an indented list view
  • You can add views to a window using BWindow::AddChild( BView *child)
  • The BWindow::Bounds() returns the size of the window
  • You can create menus with BMenu and their items with BMenuItem

Exercises:

  • Play with adding items to our BOutlineListView. Look at the BStringItem class
  • Add a BStringView to the bottom of the window. Add the text "Statusbar" to it. Find out the right height

Next time I will really get to BMessages and their meaning in the greater plan. And as always, feel free to email me about anything that is unclear or missing!

 
The Fate of Microsoft by Michael Phipps 

There are many people out there who predict the demise of Microsoft. Those who advocate or, at least, believe in such a fate, point out the rise of Linux, alternatives on other fronts (like OpenOffice, for example) and the manifold sins of Microsoft, the corporation, real, exaggerated, or imagined.

I would like to look at Microsoft from a more ... traditional business perspective. Ignoring the technology, ignoring the hype, let's just take a look at it through a business person's eyes.

Here we have a mature company. Their main products are more than 10 years old. Their changes in their new products (again, ignoring the hype) are relatively low. Years between releases of new versions of core products. Furthermore, they have completely saturated their market for *new* sales. It is pretty safe to assume that new Windows sales are really "upgrades" of previous machines that are now donated or junked. The vast majority of the companies profits come from the main two products - Windows and Office.

Microsoft has ignored and/or discarded most of the conventional business wisdom. Microsoft can not define itself or its customers in one sentence. Coke, for example, sells to soda drinkers. Microsoft sells to computer users, IT people, manufacturers, cell phone users, executives who use PDAs, etc. Almost everyone is a potential Microsoft customer. And what does Microsoft sell? Software, hardware, phones, support, consulting, services and more. As a result of the saturation and inability to grow, Microsoft has spread into tons of other markets. This is not normally a successful strategy for businesses. Most companies that try to extend a successful product line into a different market fail. Microsoft also doesn't listen to the people who really get things done - geeks. I don't know almost anyone who really likes Microsoft or most of their products. Web development with .Net is a disaster, to put it kindly. Their pricing is outrageous.

Their future plans are nebulous and amorphous. Their current products that look to define their future are underwhelming, at best. Their XBox is losing tons of money. Bob certainly lost them a fair amount, not to mention all of the jokes. Longhorn has potential, but no one has any confidence that it will be a quality product until its third or fourth release.

Microsoft's profitability is not assured. They spend 5 *BILLION* a quarter on R&D, sales costs, etc. It wouldn't take a whole lot of lost sales to drive Microsoft to the break even point or even lower. Yes, they have 40 billion in the bank. That is 2 years operating expenses. Not a bad cushion, don't get me wrong, but that is not an infinitely deep warchest for a company of that size.

The press has recently been most harsh to Microsoft. Their own internal documents show them to be what many people have accused them of being - cruel, harsh monopolists who want to drive their competition out of business through unfair business practices. Their attempts to influence those who are considering open source solutions seem transparent and clumsy. If it is that visible to those on the outside, it has to be crystal clear to those on the inside.

A final obsticle coming into Microsoft's path is their stock price. One of the key ways that Microsoft has motivated its employees is with stock options. The lure of stock options is that the stock will go up and up. When the employee is ready to cash in, there is a lot of value in the options. But Microsoft's stock price has fallen over the last few years, from $120 per share in Jan 2000 to under $60, now. If I were a Microsoft employee, those stock options would no longer be much of an incentive to me. So the company would have to pony up some extra cash to motivate me. That directly impacts the bottom line, when multiplied over thousands of employees.

Microsoft reminds me of Rome in the 200's. A huge empire that seems indomitable. But corrupt and sour in its heart. The emperor is fiddling while Rome burns. Microsoft needs to stay focused on its core business. If the 50 people at Be could write a slick OS, I can not believe that there are not 50 competent people at Microsoft who could write a quality operating system. Office is a huge, bloated mess. It is hard to use, hard to integrate, and, in trying to suit everyone, it suits no one.

As I wrote last time, Windows has been an insufferable pain. Not just to me, but to everyone around me. Everyone that I know curses it but sort of shrugs their shoulders as if Bill Gates has a divine right to make The One True Operating System.

The computing world is hungry for a better desktop. That is the niche that OpenBeOS can fit into, if we can be ready.