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.
a) PM can load their modules localy or throught the tcp/ip network (or unix-domain). To do that, it uses a transparent (to application and to the modules) communication way to talk with the daemon. The daemon can load the module instead of the application and can return a set of fake-function pointers to the application. So, the application does not know what happens and still it is working with the functions pointer that was returned by pm_getmid(). But that fake function-pointers are belongs to PML and not to the module itself. The PML now, ask from the daemon to run the functions (throught sockets) and sends the results back to the application.
b) PM require from their modules to have as specified set of functions. It has categirized their sets to:
That has the great effect to provides a common API to all of its apllications for various jobs. For example, we use the VFS API to provide info about pm-modules, system's users, etc.
More about that on the next section.
c) But the basic job of PM is keep up the system stability and the "speed". PM it keeps a list with the loads of every pid. Also, it is designed to keep info about the use of the modules (cache manager).
As we said, the modules are simple shared-libraries.
There are three main differences between common shared-libraries and PM's modules
a) The modules must have a specified set of routines. One of them tells to PM what set of routines are supported by the module.
b) The modules does not needs to fullfill PM's requirenments. In a lot of cases PM can (symplirosei) the functions that are missing from the modules.
For example, if a GFX module provides only the setpixel/getpixel functions, then PM can use its own draw_line and draw_circle instead of modules ones.
c) Shared-libraries are used in one-way communication style. In PM, the modules can call the PM's routines. That is a different approach to common thinking. The modules on PM are working more like the DOS's overlays, rather than a library. Also, that makes the size of the modules extremly small.
As we said, modules are categorized by theirs set of routines.
The routines of that must supported by the modules ...
(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)
(repeat how apps works)
(what is the returned pointer, how-to call module's routines)
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.
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 :)
...
1.2.13.1 written by Dimitri van Heesch,
© 1997-2001