About PM...

Copyright © 2001-2004, arm0nia project

Version
0.1, sometime in 2002
Authors
Nicholas Christopoulos

What is PM

The PM is a simple manager for shared-libraries. An application ask for a module, and PM loads it for it.

A module is a shared library. A set of routines and nothing more.

PM controls their modules by a key. There is one unique key for each module. When an application wants to load a module, it calls the pm_getmid() and pass the key. The PM loads the module and returns a structure with pointers to the module's routines. Now, the application can execute the routines.

That is simple and easy but that is not all.

Results

All of us we have worked with graphics libraries (like SDL, SVGALIB, etc), with keyboard and the 'hell' of termcap, different OSes, etc.

The PM promises to provide one API (per category) for all that. So, if you write a code for the SDL it will works on SVGALIB too (by changing the module-key). Keyboard codes will the same on all environments, terminals, etc. The same things for the rest like pointing-devices (mouse), sound, etc.

There is also a full described data style. The graphics-related modules must use/return always data similar (almost the same) to PC's video-ram. The sound-related modules must use/return always raw-data similar to /dev/dsp. There are libs on PM to help the module-developers to do that work. So, all the graphics modules and all the vfs modules (which are used to encode/decode graphics files) are returns or using a virtual video-ram structure that is compatible with the PC's hardware's one (in almost all cases).

Additional, since, it can load modules as root or as a common user, throught the tcp/ip or locally (daemon) or into applications space, its flexibility is beyond of our imagination. Of course, that has its cost, the security. So, will let that to others (system, modules, window-manager, etc).

You maybe think that all these things will reduce the code's speed. I can say that, if the module will be loaded in application's space (that is common), there is no loss of speed because it is almost the same as to link the module as shared library!. That can be easy understood if you think that the PM, in that case, returns a structure with function-pointers which are points directly to module's functions. Transformation of data normally will cost nothing to speed because its format is based on PC's hardware. For example, the screen-data of a virtual-video-ram structure can be placed in the video-ram directly by using a simple memcpy()!

What are the modules

As we said, the modules are simple shared-libraries.

There are three main differences between common shared-libraries and PM's modules

More about modules

As we said, modules are categorized by theirs set of routines.

The routines of that must supported by the modules ...

TODO....

*	(routines typoi)
*	required routines
*	optional routines
*	extentions
*	and the bastards, optionals that can replaced by PM if their are missing from the module
*	(standard routines)
*	(APIs)

PM applications

(TODO: repeat how apps works)

(TODO: what is the returned pointer, how-to call module's routines)

A VFS application example

The following example is a typical vfs application. It does nothing more than load a module and display one of its files.

The 'module-key' and the 'file' are the command-line parameters.

// vfstest.c #include "../pm_app.h" int main(int argc, char *argv[]) { int handle; pm_vfs_module *m; pm_init(); // initialize PML if ( argc != 3 ) // wrong args panic("usage: vfstest module-key open-file"); // load the module if ( (m = pm_vfs_load(argv[1])) == NULL ) panic("pm_vfs_load(\"%s\"): failed", argv[1]); // open the file if ( (handle = m->open(m->mid, argv[2], 0)) == -1 ) panic("m->open(m->mid,\"%s\"): failed", argv[2]); // display theirs contents while ( m->gets(m->mid, handle, buf, 256) ) printf("%s", buf); m->close(m->mid, handle); pm_vfs_release(m); // close the module return 0; }

The power of PM can be easily showed here. You'll need to use the 'root' user to run these examples. Actually, that is no required (or it will no rq) but for now it is good.

Example 1: Use vfstest to get the time from a local or internet server

# vfstest vfs/telnet localhost:13

if the vfstest fail, that means there is no configured the timegen service in your machine. Edit /etc/inetd.conf and remove the # from timegen lines. restart your inetd (on SuSE: rcinetd restart) and try again.

Example 2: Use vfstest to connect to other device (like my Palm) through serial port, for a chat :)

# vfstest vfs/serial /dev/ttyS1:57600

In my Palm, I run the SB with the sertest.bas and ... voila... I do a chat through the cardle.

Example 3: Use vfstest to get info about a username

# vfstest vfs/users users/root

A few information about the user 'root' will be displayed in your console.

A VFS module example

The following code demonstrates how to use the PM to build a VFS module that shows every username as a file. Uid, gid, real-name, home-directory and the shell are part of the file's contents.

Note that is quite different than default PM's users module because the default-module uses directories to help the applications to find the users by the username or the uid.

#include "../pm_km.h" #include "../vfslib.h" static vfs_tree_t *tree; // our vfs-tree static int userfs_init = 0; // thread protection // the PM has just now, load the module int pm_module_init(mid_t mid) { userfs_init ++; if ( userfs_init == 1 ) { FILE *fp; tree = vfs_build(1,1,0); // build vfs if ( (fp = fopen("/etc/passwd", "rt")) != NULL ) { char buf[1024]; // for each line of /etc/passwd while ( fgets(buf, 1024, fp) ) { if ( strlen(buf) > 4 && buf[0] != '#' ) { char fdata[4096]; // our file's contents strlist_t *list; // building our virtual-file list = slsplit(buf, ":", NULL, 0); sprintf(fdata, "%s\n%s\n%s\n%s\n%s\n%s\n", list->str[0], list->str[2], list->str[3], list->str[4], list->str[5], list->str[6] ); // insert file to vfs-tree vfs_build_file(tree, list->str[0], fdata, strlen(fdata)); // clean-up strlist_destroy(list); } } fclose(fp); return 1; // everything ok } } return 0; // error } // PM will close the module void pm_module_close(mid_t mid) { userfs_init --; if ( userfs_init == 0 ) vfs_destroy(tree); // free vfs-tree } // An application wants info about our vfs void pm_vfs_sysinfo(mid_t mid, pm_vfs_sysinfo_t *info) { memset(info, 0, sizeof(pm_vfs_sysinfo_t)); info->version = PM_VFS_SYSINFO_T_VER; info->readonly = 1; // this is a read-only file-system info->dirsup = 1; // directory-routines are supported } // PM wants to known what routines are supported by the module void pm_module_getapi(mid_t mid, pm_module_api_t *api) { api->version = PM_MODULE_API_T_VER; // version of this structure api->api_type = pm_api_vfs; // what kind of interface is supported api->api_version = 1; // what interface-version is supported by the module } // redirect everything else to vfslib int pm_vfs_open(mid_t mid, const char *filename, int flags) { return vfs_open(tree, filename, flags); } ...

That's all folks :)