NAME

Win32::MMF - Win32 Memory Mapped File (MMF) Support for Perl

SYNOPSIS

# Object-oriented style
use Win32::MMF;

# --- in process 1 ---
my $ns = Win32::MMF->new( -namespace => "MySharedMem" );

$ns->setvar('varid', $data);

# --- in process 2 ---
my $ns = Win32::MMF->new( -namespace => "MySharedMem" );

$data = $ns->getvar('varid');

$ns->deletevar('varid');


# Tied variable style
use Win32::MMF::Shareable;
Win32::MMF::Shareable::Init( -namespace => "MySharedMem" );

# --- in process 1 ---
tie $data, "Win32::MMF::Shareable", "varid";
$data = 'Hello world!";

# --- in process 2 ---
tie $data, "Win32::MMF::Shareable", "varid";
print "$data\n";

ABSTRACT

This module provides Windows' native Memory Mapped File Service for shared memory support under Windows. The core of the module is written in XS and is currently supported only under Windows NT/2000/XP.

The current version 0.05 of Win32::MMF is available on CPAN at:

http://search.cpan.org/search?query=Win32::MMF

DESCRIPTION

Programming Style

This module provides three types of interfaces - object-oriented, functional, and tied interfaces (Via Win32::MMF::Shareable). The default access method is via objects. The functional interface is not exported by default because it requires a detailed knowledge of the Windows operating system internals to use properly.

There are many advantages of using the object oriented interface. For example, the following is the amount of code required in function-oriented style to create a namespace (a named block of shared memory). It involves openning or creating a swap file, creating a memory mapping and finally creating a view:

use Win32::MMF qw/ ClaimNamespace UseNamespace MapViewOfFile /;

my ($swap, $ns, $view) = (0, 0, 0);
$ns = UseNamespace("MyDataShare");
if (!ns) {
    ($swap, $ns) = ClaimNamespace("data.swp",
                                  "MyDataShare",
                                  2 * 1024 * 1024);
    die "Can not create swap file" if !$swap;
    die "Can not create namespace" if !$ns;
}

$view = MapViewOfFile($ns, 0, 1000);

...

UnmapViewOfFile($view);
ReleaseNamespace($swap, $ns);

The following is the amount of code required to achieve the same result in object-oriented style:

use Win32::MMF;

my $ns = Win32::MMF->new( -swapfile => "data.swp",
                          -namespace => "MyDataShare",
                          -size => 2 * 1024 * 1024 )
    or die "Can not create namespace";
    

Note that there is no need to explicitly unmap the view, close the namespace and close the swap file in object-oriented mode, the view, namespace and swap file handles are automatically closed-off and disposed of when the Win32::MMF object falls out of scope.

The following is the amount of code required in tied variable style, which virtually eliminates all hassles dealing with shared memory under Windows... :-)

use Win32::MMF::Shareable;
Win32::MMF::Shareable::Init( -swapfile => "data.swp",
                             -namespace => "MyDataShare",
                             -size => 2 * 1024 * 1024 )
   or die "Can not create namespace";

...

tie my $scalar, "Win32::MMF::Shareable", "scalar1";
$scalar = "Hello world";

tie my %hash = "Win32::MMF::Shareable", "hash1";
%hash = ( A => '1', B => '2', C => '3' );

tie my @array = "Win32::MMF::Shareable", "array1";
@array = qw/ A B C D E /;

REFERENCE

Memory Mapped File (MMF) Under Windows

Under Windows, code and data are both repesented by pages of memory backed by files on disk - code by executable image an data by system pagefile (swapfile). These are called memory mapped files. Memory mapped files can be used to provide a mechanism for shared memory between processes. Different processes are able to share data backed by the same swapfile, whether it's the system pagefile or a user-defined swapfile.

Windows has a tight security system that prevents processes from directly sharing information among each other, but mapped memory files provide a mechanism that works with the Windows security system - by using a name that all processes use to open the swapfile.

A shared section of the swapfile is translated into pages of memory that are addressable by more than one process, Windows uses a system resource called a prototype page table entry (PPTE) to enable more than one process to address the same physical page of memory, thus multiple process can share the same data without violating the Windows system security.

In short, MMF's provide shared memory under Windows.

What is a Namespace?

In Win32::MMF a namespace represents shared memory identified by a unique name. The namespace must be unique system wide. A suggested convention to follow is <[APPID].[VARID]>.

Example: 'MyApp.SharedMemory'.

Creating a Namespace Object

There are three ways to pass parameters into the Win32::MMF object constructor: named parameters, a hashref of parameters or a list of parameters.

Using Named Parameters
$ns = Win32::MMF->new(
             -swapfile => $swapfilename,
             -namespace => $namespace_id,
             -size => 1024,
             -reuse => 0,
             -autolock => 1,
             -timeout => 10 );

The parameter names begin with '-' and are case insensitive. For example, -swapfile, -Swapfile and -SwapFile are equivalent.

Passing Parameters in a Hashref
$ns = Win32::MMF->new({
             swapfile => $swapfilename,
             namespace => $namespace_id,
             size => 1024,
             reuse => 0 });

The parameter names do not begin with '-' and are case insensitive. This mode is good for working with external configuration files.

Passing Parameters in a List
$ns = Win32::MMF->new(
             $namespace_id,
             $size,
             $swapfile,
             $reuse_flag);

The $namespace_id parameter is mandatory, other parameters are optional.

Input Parameters
-swapfile

Specify the name of the memory mapped file (swap file). if it is omitted or undef then the system pagefile will be used.

-namespace

A label that uniquely identifies the shared memory. The namespace must be unique system wide. A suggested convention to follow is <[APPID].[VARID]>. This option is mandatory.

-size

Specify the size of the memory mapped file in bytes.

-reuse

This option tells the constructor to check if the namespace has already been declared by another process, and use the existing namespace instead. It gurrantees that a namespace is not created if it does not exist.

-autolock

Automatic read/write locking, turned on by default.

-timeout

Specify the number of seconds to wait before timing out the lock. This value is set to 10 seconds by default. Set timeout to 0 to wait forever.

-debug

Turn on/off the internal MMF debugger.

Locking a Namespace

All read and write accesses to a namespace are locked by default. However if auto-locking is turned off, a namespace can be explicitly locked with the lock method.

$ns->lock($timeout);

Input Parameters
$timeout

Number of seconds before the lock attempt fails.

Return Values
undef    Namespace error
0        Time out waiting for lock
1        Success

Unlock A Namespace Object

$ns->unlock();

Accessing a Namespace

All read and write accesses to a namespace are locked by default to preserve data integrity across processes. The Storeable module is used for data serialization for complex structures.

Variables inside a Namespace

Each data element written to a namespace is identified by a unique label (variable name). Variable definitions are held inside the namespace itself to be shared among multiple processes. The debug method can be used to display current variable definitions within the namespace.

Note that variables defined inside a namespace are considered global and will not be deleted unless the user explicitly calls the deletevar method or setting the variable to undef.

$ns->setvar('VarId', $data, ...);

Serialize all given data and then write the serialized data into the variable inside the namespace. The variable will be automatically created if it does not exist.

Because the variable definition table is held inside the shared memory itself, variables created in one process can be used by another process immediately.

Beware that setting a namespace variable to empty string will free up the shared memory currently held by the variable, but will not delete the variable from the namespace. Setting the variable to undef will not only free up the shared memory but also delete the variable from the namespace.

$data = $ns->getvar('VarId');

Retrieves the serialized data string from the namespace, and deserializes back into perl variable(s). Please refer to the Storeable documentation on how to serialize (freeze) and retrieve (thaw) data. Simple scalars are not serialized however to maximize the access efficiency.

$ns->deletevar('VarId');

Delete the given variable from the namespace and free up shared memory allocated to the variable. This is equivalent to setting a variable to undef.

if ($ns->findvar('VarId')) { ... }

Test for the existance of a given variable inside the namespace.

Debugging a Namespace

There is a built-in method debug that will display as much information as possible for a given namespace object.

$ns->debug();

Dump the Memory Mapped File Descriptor (MMFD), shared memory heap and variable definition table for the namespace.

Using Tied Variable Interface

The Win32::MMF::Shareable module is modelled after IPC::Shareable. All options from IPC::Shareable can be used in Win32::MMF::Shareable, although they are mostly ignored except for the 'label' argument. Because memory and variable management are managed internally by the Win32::MMF module, you do not need to specify how much memory is required by the variable.

All access to tied variables are automatically and exclusively locked to preserve data integrity across multiple processes.

Win32::MMF::Shareable mimics the operation of IPC::Shareable, it allows you to tie a variable to a namespace (shared memory) making it easy to share its content with other Perl processes.

Note that before trying to tie a variable to a namespace, you need to initialize the namespace first. You can do this after the use Win32::MMF::Shareable; statement:

use Win32::MMF::Shareable;
Win32::MMF::Shareable::Init( -namespace => ... );

The options are exactly the same as the Win32::MMF constructor options.

Currently only scalars, arrays, and hashes can be tied, I am investigating on the possibilities with tied file handles at the moment.

To tie a variable to the namespace:

tie $scalar, "Win32::MMF::Shareable", "var_1";
tie @array,  "Win32::MMF::Shareable", "var_2";
tie %hash,   "Win32::MMF::Shareable", "var_3";

And to use a tied variable:

$scalar = 'Hello Perl';

@array = qw/ A B C D E F G /;

%hash = @array;

EXAMPLE 1 - setvar, getvar and deletevar

use strict;
use warnings;
use Win32::MMF;
use Data::Dumper;

my $ns = new Win32::MMF( -namespace => "MyNamespace" ) or die;

# setting variables and getting them back
my $var1 = "Hello world!";
my $var2 = {
   'Name' => 'Roger',
   'Module' => 'Win32::MMF',
};

$ns->setvar('Hello', $var1);
$ns->setvar('Hash', $var2);
$ns->debug();

my $r1 = $ns->getvar('Hello');
my $r2 = $ns->getvar('Hash');
print Dumper($r1), Dumper($r2), "\n";

$ns->deletevar('Hello');
$ns->setvar('Hash', undef);
$ns->debug();

EXAMPLE 2 - inter-process signalling

use strict;
use warnings;
use Win32::MMF::Shareable;

Win32::MMF::Shareable::Init( -namespace => 'MySharedmem' );

defined(my $pid = fork()) or die "Can not fork a child process!";

if (!$pid) {
   tie my $sig1, "Win32::MMF::Shareable", '$signal1';
   tie my $sig2, "Win32::MMF::Shareable", '$signal2';

   print "PROC1 WAIT SIGNAL 2\n";
   while (!$sig2) {};
   print "PROC1 SEND SIGNAL 1\n";

   $sig1 = 1;
} else {
   tie my $sig1, "Win32::MMF::Shareable", '$signal1';
   tie my $sig2, "Win32::MMF::Shareable", '$signal2';

   print "PROC2 SEND SIGNAL 2\n";
   $sig2 = 1;
   print "PROC2 WAIT SIGNAL 1\n";
   while (!$sig1) {};

   print "PROC2 GOT SIGNAL 1\n";
}

SEE ALSO

Win32::MMF::Shareable

CREDITS

Credits go to my wife Jenny and son Albert, and I love them forever.

AUTHOR

Roger Lee <roger@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2004 Roger Lee

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

3 POD Errors

The following errors were encountered while parsing the POD:

Around line 689:

=back without =over

Around line 760:

=back without =over

Around line 767:

=back without =over