Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

PM for Applications

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.

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 gives the oppunity to an application to use the same set of routines for many kind of jobs. For example, an application can use the same code to use the serial-port or a telnet session (by just passing a different key on pm_getmid()).

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).

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

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.

More about modules

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)

PM applications

(repeat how apps works)

(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 :)

The future of APIs

...


Generated on Sun May 19 20:13:36 2002 for 'PM for Applications' by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001