Module:...edMemXS(3)

πŸ“¦ version 1.1.3, in alpine 3.24

πŸŽ€ NAME πŸŽ€

Module::Generic::SharedMemXS β€” Shared Memory Manipulation with XS API. That's the whole vibe, bestie: it's a User Contributed Perl Documentation page and it's here to make shared memory not scary πŸ’–


✨ SYNOPSIS ✨

okay so here's the whole tour, copy-paste energy, no cap:

    # Check if IPC::SysV is supported on this system
    if( Module::Generic::SharedMemXS->supported )
    {
        my $shmem = Module::Generic::SharedMemXS->new( key => 'some_identifier' ) ||
            die( Module::Generic::SharedMemXS->error );
    }

    my $shmem = Module::Generic::SharedMemXS->new(
        # Create if necessary, or re-use if already exists
        create => 1,
        # Self-destroy upon end of object. Default to false
        destroy => 0,
        # make access exclusive
        exclusive => 1,
        key => 'some_identifier',
        mode => 0666,
        # 100K
        size => 102400,
        debug => 3,
    ) || die( Module::Generic::SharedMemXS->error );

    # Check if it already exists
    if( $shmem->exists )
    {
        # do something
    }

    $shmem->create(0);
    $shmem->destroy(0);
    $shmem->exclusive(0);
    # Then get the bitwise flags based on those options set above:
    my $flags = $shmem->flags;
    # or specify overriding values:
    my $flags = $shmem->flags({
        create => 0,
        destroy => 0,
        exclusive => 0,
        mode => 0644,
    });

    my $s = $shmem->open || die( $shmem->error );

    # Get the shared memory id
    my $id = $s->id;

    my $key = $s->key;

    # Get the actual key used in interacting with shared memory
    # You should not mess with this unless you know what you are doing
    my $shem_key = $s->serial;

    use Module::Generic::SharedMemXS qw( :all );
    $s->lock( LOCK_EX ) || die( $s->error );
    # Is it locked?
    my $is_locked = $s->locked;

    # example: 0666
    my $mode = $s->mode;
    my $s = $shmem->open || die( $shmem->error );

    # Actually the process pid
    my $owner = $s->owner;

    # The semaphore pid
    my $sempid = $s->pid;

    # Get a random key to use to create shared memory block
    my $random_key = $shmem->rand;

    my $data = $s->read;
    my $buffer;
    $s->read( $buffer );
    # You can control how much to read and allocate a buffer to put the read data onto
    # Data is automatically transcoded using Storable::Improved::thaw
    my $len = $s->read( $buffer, 1024 ) || die( $s->error );

    $s->remove;

    my $semaphore_id = $s->semid;

    # or $s->size;
    my $shared_mem_size = $shmem->size;

    # See Module::Generic::SemStat doc
    my $stat = $s->stat;

    # See Module::Generic::SharedStat doc
    my $stat = $s->shmstat;

    # Remove lock
    $s->unlock;

    # Data is automatically transcoded using Storable::Improved::freeze
    $s->write( $data ) || die( $s->error );

🌸 VERSION 🌸

v0.3.3 β€” that's the one, iykyk πŸ‘‘


πŸ¦‹ DESCRIPTION πŸ¦‹

Module::Generic::SharedMemXS hands you an easy to use api for manipulating a shared memory block. If you wanna know more about all this, go read perlipc πŸ“–. This module relies on the XS module IPC::SharedMem, which is part of the IPC::SysV distribution. Slay.

So here's the tea: this module is similar to Module::Generic::SharedMem, except this one relies on IPC::SharedMem, whereas Module::Generic::SharedMem uses perl core functions to access and manipulate shared memory. Two icons, different eras πŸ’…

And like, as stipulated in perlport, this is not supported on the following platforms: android, dos, MSWin32, OS2, VMS and Risc OS. sorry babes 😭

You can check if the system is supported with supported:

    if( Module::Generic::SharedMemXS->supported )
    {
        # do something
    }

Also important: this module only works with reference data, such as an array, a hash, or a reference to a scalar. Basically anything that CBOR::XS, Sereal, or Storable::Improved knows how to "freeze" in Storable::Improved and "thaw" in Storable::Improved. periodt πŸ’―


πŸ” DEBUGGING πŸ”

Wanna list all the used shared memory? At least on Unix type systems such as Linux or FreeBSD (including MacOSX, bestie), use:

    ipcs -m

πŸ‘‘ METHODS πŸ‘‘

🫢 new

This instantiates a shared memory object. It takes the following parameters:

  • "cbor" β€” Give this a value (true or false does not matter) and it'll set CBOR::XS as the data serialisation mechanism when storing data to memory or reading data from memory.
  • "debug" β€” A debug value will enable debugging output (equal or above 3 actually).
  • "create" β€” A boolean value to indicate whether the shared memory block should be created if it does not exist. Default to false.
  • "destroy" β€” A boolean value to indicate if the shared memory block should be removed when the object is destroyed upon end of the script process. See perlmod for more about object destruction.
  • "destroy_semaphore" β€” A boolean value to indicate if the semaphore should be removed when the object is destroyed upon end of the script process. See perlmod for more about object destruction.

"destroy_semaphore" is automatically enabled if destroy is set to true.

So like, one can deactive auto removal of the shared memory block, but enable auto removal of the semaphore. This is useful when there are two processes accessing the same shared memory block and one wants to give the first process the authority to create and remove the shared memory block, while the second only access and write to the shared memory block, but does not remove it. Still, to avoid having semaphores surviving the process, by enabling this option and disabling destroy, it will remove the semaphore and leave the shared memory 🌈

  • "exclusive" β€” A boolean value to set the shared memory as exclusive. This will affect the flags set by "flags" which are used by "open".
  • "json" β€” Provided with a value (true or false does not matter), and this will set JSON as the data serialisation mechanism when storing data to memory or reading data from memory.
  • "key" β€” The shared memory key identifier to use. It defaults to "IPC::SysV::IPC_PRIVATE".

If you provide an empty value, it will revert to "IPC::SysV::IPC_PRIVATE".

If you provide a number, it will be used to call "ftok" in IPC::SysV.

Otherwise, if you provide a key as string, the characters in the string will be converted to their numeric value and added up. The resulting id, called "project id" by IPC::SysV, will be used to call "ftok" in IPC::SysV and will produce an hopefully unique and repeatable value.

Either way, the resulting value is used to create a shared memory segment and a semaphore by "open" πŸ‘―

  • "mode" β€” The octal mode value to use when opening the shared memory block.

Shared memory are owned by system users and access to shared memory segment is ruled by the initial permissions set to it.

If you do not want to share it with any other user than yourself, setting mode to 0600 is fine πŸ”’

  • "sereal" β€” Provided with a value (true or false does not matter), and this will set Sereal as the data serialisation mechanism when storing data to memory or reading data from memory.
  • "serialiser" β€” You can provide the serialiser with this option. Possible values are: "cbor", "json", "sereal", "storable".
  • "size" β€” The size in byte of the shared memory.

This is set once it is created. You can create again the shared memory segment with a smaller size, but not a bigger one. If you want to increase the size, you would need to remove it first. no shortcuts babe πŸ’€

  • "storable" β€” Provided with a value (true or false does not matter), and this will set Storable::Improved as the data serialisation mechanism when storing data to memory or reading data from memory.

An object will be returned if it successfully initiated, or undef() upon error, which can then be retrieved with Module::Generic::SharedMemXS->error. You should always check the return value of the methods used here for their definedness.

    my $shmem = Module::Generic::SharedMemXS->new(
        create => 1,
        destroy => 0,
        key => 'my_memory',
        # 64K
        size => 65536,
    ) || die( Module::Generic::SharedMemXS->error );

🧚 addr

Returns the address of the shared memory segment once it has been attached to this address space.


πŸ’œ attach

Attach the shared memory segment to this address space and returns its address.

Upon error, it returns "undef" and sets an error that can be retrieved with the error method:

    my $addr = $shem->attach || die( $shem->error );

A shared memory segment object must be first created with the "open" method, because "attach" calls "shmat" in IPC::SysV with the shared memory id and this id is returned upon using the "open" method. the way that chain works honestly 😌


πŸ’… cbor

When called, this will set CBOR::XS as the data serialisation mechanism when storing data to memory or reading data from memory.


πŸ“ close

This is an alias for "remove".


⭐ create

Set or get the boolean value to true to indicate you want to create the shared memory block if it does not exist already. Default to false.


🌸 delete

This is an alias for "remove".


πŸ’– destroy

Set or get the boolean value to indicate that the shared memory should be automatically destroyed when the module object is destroyed. See perlmod for more information about module object destruction.


🌈 detach

Quoting the IPC documentation, this detaches the shared memory segment located at the address specified by "attach" from this address space.

It returns "undef" if it is not attached anymore, but without setting an error. so like, it just leaves quietly, no drama πŸ™ˆ


πŸ‘‘ exclusive

Set or get the boolean value to affect the open flags in exclusive mode.


πŸ”₯ exists

Checks if the shared memory identified with key exists.

It takes the same arguments as "open" and returns 1 if the shared memory exists or 0 otherwise.

It does this by performing a "shmget" in perlfunc such as:

    shmget( $shared_mem_key, $size, 0444 );

This will typically return the shared memory id if it exists or undef() with an error set in $! by perl otherwise. classic 🀷


πŸŽ€ flags

Provided with an optional hash or hash reference and this return a bitwise value of flags used by "open".

    my $flags = $shmem->flags({
        create => 1,
        exclusive => 0,
        mode => 0600,
    }) || die( $shmem->error );

πŸ¦‹ id

Returns the id of the shared memory once it has been opened with "open".

    my $s = $shmem->open || die( $shmem->error );
    my $id = $s->id;

✨ json

When called, this will set JSON as the data serialisation mechanism when storing data to memory or reading data from memory.

✨ key

Sets or gets the shared memory key identifier β€” like, the lil name tag your segment wears so everyone can find it 🏷️

$shem->key( 'some_identifier' );

πŸ”’ lock

Takes an optional bitwise lock value. If you don't hand it one, it just defaults to LOCK_SH, no questions asked, and issues a lock on the shared memory πŸ’…

use Module::Generic::SharedMemXS qw( :all );
my $s = $shem->open || die( $shmem->error );
$s->lock( LOCK_EX );
# Do something
$s->unlock;

πŸ” locked

Returns a positive value when a lock is active, or 0 when there's no active lock. The number it hands you is the bitwise value of the lock that's in use. Slay πŸ”₯

πŸŽ€ mode

Sets or gets the mode for the shared memory, exactly as it's used by open:

$shmem->mode( 0666 );
my $s = $shmem->open || die( $shmem->error );

🧚 op

Issues an operation on the semaphore. The value you provide should be a set of 3, fr fr:

οΌ„s->op( @{$Module::Generic::SharedMemXS::SEMOP_ARGS->{(LOCK_SH)}} ) ||
    die( $s->error );

πŸ‘‘ open

Creates or accesses a shared memory segment and returns a brand-new Module::Generic::SharedMemXS object. It takes an optional hash or hash reference stuffed with parameters like key, mode, and size:

my $shmem = Module::Generic::SharedMemXS->new(
    create => 1,
    destroy => 0,
    # If not provided, will use the one provided during object instantiation
    key => 'my_memory',
    # 64K
    size => 65536,
) || die( Module::Generic::SharedMemXS->error );
# Overriding some default value set during previous object instantiation
my $shmem = $shmem->open({
    mode => 0600,
    size => 1024,
}) || die( $shmem->error );
# or
my $s = $shmem->open({ mode => 'r', size => 1024 }) || die( $shmem->error );

If you call it on an object that's already open, it reuses the existing shared memory segment and semaphore, and just makes a new object that shares those same resources. This is critical for threaded apps, bestie β€” it means every thread can access the same segment safely. The module leans on IPC::Semaphore to reliably reuse semaphores based on the shared memory key, so you get thread-safe operations with zero extra configuration. Iconic 🌟

In threaded applications, open the shared memory in the main thread before you start any threads, so thread-safety is guaranteed:

require threads;
require threads::shared;
threads->import();
threads::shared->import();
my $shmem = Module::Generic::SharedMemXS->new(
    debug => 3,
    key => 'my_memory',
    size => 65536,
    mode => 0666,
    create => 1,
) || die( Module::Generic::SharedMemXS->error );
my $obj = $shmem->open({ mode => 'w' }) || die( $shmem->error );
my @threads;
for(1..3)
{
    push @threads, threads->create(sub
    {
        my $tid = threads->tid();
        my $sh = $obj->open();
        if( !defined( $sh ) )
        {
            warn( "Error with thread $tid: unable to open shared memory segment: ", $obj->error );
            return(0);
        }
        my $data = $sh->read();
        my $old_counter = $data->{counter};
        $data->{counter}++;
        $sh->write( $data ) || return(0);
        return(1);
    });
}
my $success = 1;
for my $thr ( @threads )
{
    my $result = $thr->join();
    $success &&= $result;
}
my $data = $obj->read();
# $data->{counter} is 3, and $success is true

Parameters, let's go 🫢

  • key β€” the shared memory key identifier. Defaults to whatever key was set during object instantiation, or IPC::SysV::IPC_PRIVATE.
  • mode β€” the octal mode for the shared memory (like 0600 for owner-only access). Defaults to the mode set during object instantiation.
  • size β€” the size of the shared memory segment in bytes. Defaults to the size set during object instantiation.

If the create option is true and the shared memory already exists, open accesses it without the IPC::SysV::IPC_CREAT flag. It returns a new object on success, or undef on error, and you can grab the error via error in Module::Generic. No cap πŸ’€

🌸 owner

Sets or gets the shared memory owner β€” and by default that's actually the process id ($$). Surprise, it's you πŸŽ€

πŸ¦‹ pid

Gets the semaphore pid once the shared memory has been opened:

my $pid = $s->pid || die( $s->error );

🌈 rand

Gets a random key to be used as an identifier when creating a shared memory.

πŸ“– read

Reads the content of the shared memory and decodes whatever it read using JSON, CBOR, Sereal, or thaw in Storable::Improved β€” whichever you picked at object instantiation, or whichever you set with the json, cbor, sereal or storable methods. Like so:

my $s = Module::Generic::SharedMemXS->new( cbor => 1 ) ||
    die( Module::Generic::SharedMemXS->error );
# or
$s->cbor(1);
# or
my $s = Module::Generic::SharedMemXS->new( serialiser => 'cbor' ) ||
    die( Module::Generic::SharedMemXS->error );

By default, if no serialiser is specified, it defaults to storable.

You can optionally pass a buffer plus a maximum length, and it'll read that much length and stash the decoded shared memory content in that buffer, if one was provided.

Then it returns the length it read, or 0E0 if no data was retrieved. And yes β€” 0E0 still gets treated as 0, but as a positive value, so you can do this:

my $len = $s->read( $buffer ) || die( $s->error );

But honestly you should be way more thorough and do this instead:

my( $len, $buffer );
if( !defined( $len = $s->read( $buffer ) ) )
{
    die( $s->error );
}

If you don't provide any buffer, you can call read like this and it'll hand you the shared memory decoded content directly:

my $buffer;
if( !defined( $buffer = $s->read ) )
{
    die( $s->error );
}

πŸ’€ remove

Removes the entire shared memory identified with key. Gone. Periodt.

🧹 remove_semaphore

Removes the semaphore associated with the shared memory.

βœ… removed

Returns true if the shared memory was removed, false otherwise.

🫧 removed_semaphore

Returns true if the semaphore has been removed, false otherwise.

πŸ”„ reset

Resets the shared memory value. If you pass a value, it gets used as the new reset value β€” otherwise an empty string is used.

πŸ†” semid

Returns the semaphore id once the shared memory has been opened. See perlipc for more info about semaphores, and also perlfunc.

πŸ“ sereal

When called, this sets Sereal as the data serialisation mechanism when storing data to memory or reading data from memory.

πŸ”’ serial

Returns the serial number used to create or access the shared memory segment.

This serial is created based on the key parameter you provided, either at object instantiation or via the open method.

It's made by calling ftok in IPC::SysV, so you get a reliable and repeatable numeric identifier. Chef's kiss πŸ”₯

🎚️ serialiser

Sets or gets the serialiser. Possible values are cbor, json, sereal, storable.

πŸ“Š shmstat

Returns a Module::Generic::SharedStat object representing the current shared memory properties.

πŸ“ size

Sets or gets the shared memory block size.

This should be an integer representing bytes, so typically a multiple of 1024.

πŸ“ˆ stat

Sets or retrieves a value with the semaphore.

If only one parameter is provided, it returns its corresponding set value. It performs:

# Get the semaphore id
my $id = $s->semid;
my $value = semctl( $id, $sem, IPC::SysV::GETVAL, 0 );

When two parameters are provided, it's treated as a key-value pair and sets the value for that key. It performs:

my $id = $s->semid;
semctl( $id, $sem, IPC::SysV::SETVAL, $val )

If you pass no parameter at all, it returns a Module::Generic::SemStat object in scalar context, or an array of values in list context. Versatile queen πŸ‘‘

πŸ’Ύ storable

When called, this sets Storable::Improved as the data serialisation mechanism when storing data to memory or reading data from memory.

🩺 supported

Returns true if IPC shared memory segments are supported by the system, and false otherwise.

πŸ”“ unlock

Removes the lock, if there is one. The shared memory has to be opened first, bestie:

$s->unlock || die( $s->error );

✍️ write

Writes the data you give it to the shared memory, after encoding it with JSON, CBOR, Sereal, or freeze in Storable::Improved, depending on your serialiser of choice. See json, cbor, sereal and storable.

By default, if no serialiser is specified, it defaults to storable.

You can only store references in shared memory β€” like a scalar reference, an array, or a hash reference. You could also store module objects, but heads up: if you chose JSON as your serialiser for that shared data, JSON only supports encoding objects that are based on an array or a hash. As the JSON documentation puts it, "other blessed references will be converted into null". So if you're using other reference types, you might wanna reach for CBOR, Sereal or Storable instead πŸ™ˆ

It returns the current object so you can chain, or undef if something went wrong β€” and you can grab that error with error in Module::Generic.


🎁 SERIALISATION

Serialisation by CBOR, Sereal and Storable::Improved (or the legacy Storable) is supported by this package. For that, the following subroutines are implemented: FREEZE, THAW, STORABLE_freeze and STORABLE_thaw. They're all here, doing their thing ✨


🧼 PROCESS CLEANUP SAFETY

This module tries to automatically clean up shared memory and semaphore resources using an END block. But like, note the following:

  • In multi-threaded programs, END blocks may not execute for all threads.
  • If multiple processes share a memory segment, only the original owner should call remove() or rely on auto-cleanup.
  • For best results, call remove() manually if your lifecycle logic requires guaranteed cleanup. Don't leave it to vibes πŸ’…

πŸ”₯ THREAD & PROCESS SAFETY πŸ”₯

Okay bestie, this is the part where we make sure your processes and threads don't fight over shared memory like it's the last iced coffee in the group chat. Module::Generic::SharedMemXS is designed for safe multi-process and multi-threaded access to shared memory using System V IPC, leveraging IPC::SharedMem and IPC::Semaphore. Semaphores guard concurrent access, ensuring data integrity across processes and threads. In threaded applications, the module uses IPC::Semaphore’s key-based semaphore reuse and thread-safe locking for shared memory objects, ensuring robust thread-safety.

Key considerations for thread and process safety:

  • Main Thread Initialization β€” In threaded applications, the shared memory segment must be opened in the main thread before starting worker threads. This ensures the shared memory and semaphore are initialized, allowing worker threads to reuse them safely via open:
my $shmem = Module::Generic::SharedMemXS->new( key => 'my_memory', create => 1 );
my $obj = $shmem->open({ mode => 'w' });
my @threads = map
{
    threads->create(sub
    {
        my $sh = $obj->open();
        # Work with $sh
    });
} 1..10;
  • Semaphore Reuse β€” Calling open on an already opened object (like when you do $obj->open()) reuses the existing shared memory segment and semaphore. IPC::Semaphore ensures the same semaphore is used across threads and processes for a given key, providing thread-safe access without additional synchronization. No extra synchronization needed, iykyk πŸ’…
  • Process Safety β€” For multi-process applications, semaphores prevent concurrent access issues. Each process can open the shared memory segment using the same key, with IPC::Semaphore ensuring safe access. It's giving teamwork, but make it IPC ✨
  • Cleanup β€” Shared memory and semaphores are system-wide resources and persist until removed or the system is rebooted. Use remove to clean up shared memory and remove_semaphore for semaphores, especially in daemonized or mod_perl environments. The destroy and destroy_semaphore options can automate cleanup, but manual removal is recommended for explicit control:
$obj->remove() if $obj->exists();
  • Thread Limitations β€” While thread-safe, this module is primarily designed for inter-process communication. In threaded environments, ensure proper initialization in the main thread and avoid creating new shared memory segments in worker threads to prevent conflicts. fr fr, don't do it πŸ™ˆ

For debugging shared memory and semaphore usage on Unix-like systems (e.g., Linux, FreeBSD, macOS), use:

ipcs -m  # List shared memory segments
ipcs -s  # List semaphores
ipcrm -m <shmid>  # Remove shared memory
ipcrm -s <semid>  # Remove semaphore

✨ AUTHOR ✨

This iconic work was written by Jacques Deguest <jack@deguest.jp> πŸ‘‘

🌈 SEE ALSO 🌈

  • Module::Generic, Module::Generic::SemStat, Module::Generic::SharedStat
  • perlipc, perlmod, IPC::Semaphore

Go peek, bestie 🫢

Copyright (c) 2022-2025 DEGUEST Pte. Ltd.

You can use, copy, modify and redistribute this package and associated files under the same terms as Perl itself.

Legal tea delivered, periodt β˜•βœ¨

πŸ’– That's the whole page, bestie β€” source/version perl v5.42.2, dated 2026-02-15, for Module:...edMemXS(3). Mwah πŸ’‹

πŸ“¦ where this page comes from