Small shared library to use shared memory as a FILE* , with interprocess communication in mind.
Overview
shmfile is desgined in an "owner/guest" format.
One process is the owner [FSHM_OWMER] of a shared mapping (given by a string name). It creates the mapping, and can destroy it.
Other processes then can map that same string name as guest [FSHM_GUEST].
The guest only needs to know the unique name that the owner picked to have access to the data.
Permissions
Permissions for who can map the same shm as FSHM_GUEST and what they can do with the shmfile are specified by the octal: "mode".
These follow the same rules as chmod.
For example, same user only and read-only would be 0400. Same user r/w, all other users r/o, 0644
You specify the mode when the owner creates the shmfile, which will later determine whomelse on the system may have access.
The permissions are specified by the FSHM_OWNER when creating the shmfile.
If fshm_open is used instead of fshm_guest_open to map an existing shmfile stream as FSHM_GUEST, the mode argument is ignored.
Usage
The fshm_open is the core function that returns a FILE* object, with a valid integer file descriptor [ fd ]. It is passed either FSHM_OWNER or FSHM_GUEST in the "flags" argument to define the operation.
The owner may also create an shmfile stream by using the helper function, fshm_create, and a guest may also map an existing shmfile stream by using the helper function, fshm_guest_open.
You can read/write the data using either the buffered I/O functions (like fread, fwrite, fseek) and flushing with fflush, OR
the unbuffered I/O functions (like read, write, lseek) by using the fd returned by fileno( fileObj ) where fileObj is the FILE* returned by one of the aforementioned functions.
The size is completely automatic, you do not need to allocate an underlying buffer -- any data written to it and flushed will expand the buffer automatically.
There is no built-in locking, so it's suggested if you are going to have multiple processes writing to the stream,
that you either use fixed-size sections for each process, or implement your own locking.
The following functions make up the public API of shmfile.
fshm_create - Create a new shmfile stream (convenience/helper function for fshm_open with fshm_flags as FSHM_OWNER)
FILE* fshm_create(const char *name, mode_t mode)
/**
* fshm_create - Create a new shmfile (as FSHM_OWNER)
* with a given mode.
*
*
* name - A unique name which corrosponds to this stream.
* Guests will use this name as a reference to map
* this shmfile stream.
*
* mode - An octal representing the "mode" for guest mappings.
* Mode has same meaning as with chmod.
* This mode will be used to determine how FSHM_GUEST
* mappings will be able to access this stream.
*
* See the 'fshm_open' function for more information
* on mode.
*
*
* RETURN VALUE -
* A pointer to a FILE structure which may be used
* with standard io functions (e.x. fread, fprintf, fseek)
*
* On error, this function will return NULL and `errno' will be set
*
* NOTES -
* * This is the same as calling fshm_open(name, mode, FSHM_OWNER)
*
* * See fshm_open for more info
*/
fshm_guest_open - Opens an existing shmfile stream (convenience/helper function for fshm_open with fshm_flags as FSHM_GUEST)
FILE *fshm_guest_open(const char *name);
/**
* fshm_guest_open - Maps an existing shmfile stream (as FSHM_GUEST)
* using the given name for reference.
*
*
* name - The name associated with an already-created fshmfile stream
*
*
* RETURN VALUE -
* A pointer to a FILE structure which may be used
* with standard io functions (e.x. fread, fprintf, fseek)
*
* On error, this function will return NULL and `errno' will be set
*
* NOTES -
* * This is the same as calling fshm_open(name, 0, FSHM_GUEST)
*
* * See fshm_open for more info
*/
fshm_open - Opens a shmfile stream
FILE* fshm_open(const char *name, mode_t mode, int fshm_flags);
This is the "core" function, and can be used both to create a new shared memory stream or open an existing stream. The FILE pointer returned allows you to use all the other I/O systems that come standard with libc.
/**
* fshm_open - Open a shared memory stream, either creating a new
* stream [FSHM_OWNER] or mapping an existing stream [FSHM_GUEST],
* and returning a FILE* object with an associated int fd.
* This will work with both FILE* and int filedes functions
* (e.x. fwrite and write, fread and read, etc).
*
* name - A unique name which corrosponds to this stream.
* If flags contain FSHM_OWNER, we attempt to create
* a stream using this name.
* Guests who wish to map this shmfile will provide
* this same name to reference which shmfile stream
* to map.
*
* mode - An octal representing the "mode" for this file stream.
* Mode has same meaning as with chmod.
*
* This mode will be used to determine how FSHM_GUEST
* mappings will be able to access this stream.
*
* It will also define the permissions (read/write/execute) for the
* owner / group-member / other
* relations on mappings.
*
*
* This field only has meaning when creating the shmfile ( FSHM_OWNER ).
* For an FSHM_GUEST open of an existing shmfile stream, this can be
* set to 0. Any other value will be ignored when flags contains FSHM_GUEST.
*
* Columns:
*
* - First column from left is always 0 for now (no sticky/setguid bit meaning)
*
* - Second column from left is permissions for owner (user who creates shmfile)
*
* - Third column from the left is permissions for users who are a member of
* the group associated with this stream.
* This could be primary group of creating user (FSHM_OWNER), or a different
* group (set by fshm_chgrp).
*
* - Fourth column from the left are permissions for any user which
* does NOT fall into any categories listed above
*
* Values:
*
* For each column, the number is derived by starting with 0
* and following these rules:
*
* - Add 4 to allow FSHM_GUEST mapping and read for represented set
* - Add 2 to allow writing to the mapping
* - Add 1 to allow execution
*
*
* Examples - Some examples of various #mode[s] and their meaning
*
* Allow current user only to map as guest, read/write:
* 0600
*
* Allow current user only to map as guest, read-only:
* 0400
*
* Allow current user to map as guest, read and write,
* allow a different user belonging to same primary group
* to map as guest read-only:
* 0640
*
* Allow anybody on system to map read/write:
* 0777
*
*
*
* fshm_flags - A list of flags OR'd together
*
* FSHM_OWNER - Specifies that this call will create the stream
* specified by #name . When the owner closes the stream,
* it will be destroyed.
*
* FSHM_GUEST - Specifies that this call will open an existing stream
* specified by #name . An FSHM_OWNER must have created
* this stream already, or the call will fail.
* Closing the stream as a guest will not destroy the file.
*
* FSHM_PERSIST - Do NOT remove this stream when the FSHM_OWNER closes it.
* fshm_force_destroy must be used to destroy the stream
* when this flag is provided.
*
* Return:
*
* A FILE* object on success, otherwise NULL and errno is set.
*
* NOTES:
*
* The idea here is to simply allow interprocess I/O that exists
* only in memory. One process creates the mapping ( FSHM_OWNER )
* and several other processes can inherit that mapping,
* and share data between them.
*
* There is a real FD associated with this FILE (unlike, open_memstream, for example).
*
* You may choose to use either the buffered variants ( like fwrite, fread),
* or the unbuffered variants (like write, read).
*
* Keep in mind that if you use the buffered functions, you must call fflush to
* sync the changes.
*
*
* You can use this object anywhere a FILE* is allowed, or anywhere an fd is allowed
* by calling fileno(X) where X is the FILE* returned by this function.
*
*/
fshm_chgrp - Change the group associated with an shmfile stream
int fshm_chgrp(FILE *fshm_file, gid_t group)
/**
* fshm_chgrp - Change the group associated with an existing shmfile stream
*
* You must be the the same user as the FSHM_OWNER of the given stream,
* or root in order to change the gid assigned to the shmfile.
*
* The shmfile created by fshm_open is assigned the gid
* matching the primary group of the creating user.
*
* The purpose is to allow guests in a different group access rights to
* this shmfile ( based on the group bits in the mode set with fshm_open ),
* but not just open up access for everybody ( using the "other" bits in mode ).
*
* As non-root, you may change the group to any groups to which you are a member.
* This includes your primary gid as well as all supplementry groups to which you belong.
* As root, you may change the shmfile's group to any group existing on this system.
*
*
* fshm_file - A FILE* object as returned by fshm_open.
* You must be the FSHM_OWNER of this shmfile to change permissions.
*
*
* group - new gid to replace current group on this shmfile.
*
* If you are not root, this must be either your primary gid
* or a group contained in your list of supplementry groups.
*
*
* RETURN VALUE -
* 0: Success
* -1: Failure (and errno will be set)
*
* See man 2 chown for possible error conditions and values of errno
*
*/
fshm_chmod - Change the mode (permissions) on this shmfile
int fshm_chmod(FILE *fshm_file, mode_t mode);
/**
* fshm_chmod - Change the mode on a shmfile
*
* fshm_file - A FILE* object representing an shmfile stream
*
* mode - An octal of permissions. See "chmod" for meaning.
*
* RETURN VALUE -
* 0: Success
* -1: Failure (and errno will be set)
*
* See man 2 chmod for possible error conditions and values of errno
*/
fshm_force_destroy - Forcibly destroys a stream, as a recovery tool.
Use this function if the FSHM_OWNER of a shmfile stream dies before calling fclose on the stream.
int fshm_force_destroy(const char *name);
/**
* fshm_force_destroy - Forcibly destroy the shared memory region associated
* with #name.
*
* Normal operation does not require this, however, if a process opens
* a fshm stream as FSHM_OWNER, and does not close it before terminating,
* the stream will maintain stuck open without an owner.
*
*
* name - The name associated with this stream
*
* NOTES -
*
* The owner should test for this, and forcibly destroy if required.
*
* Like so:
*
* FILE *fObj;
*
* errno = 0;
* fObj = fshm_open("/example1", 0775, FSHM_OWNER);
*
* if ( !fObj && errno == EEXIST )
* {
* fshm_force_destroy("/example1");
* fObj = fshm_open("/example1", 0775, FSHM_OWNER);
* }
*
*
* RETURN:
* 0 on success, -1 on error.
*/
shmfile_get_version - Gets version info on libshmfile
void shmfile_get_version(unsigned char *major, unsigned char *minor, unsigned char *patchlevel, const char **extra);
/**
* shmfile_get_version - Get the version info on this version of shmfile
*
* Sets the value of *major, *minor, *patchlevel, and *extra to the numeric version numbers
*/
Defined Constants
FSHM_OWNER - Used as a flag with fshm_open to denote that the current process and user will create and own the shmfile stream.
FSHM_GUEST - Used as a flag with fshm_open to denote that we want to map an existing shmfile stream.
FSHM_PERSIST - Used as a flag with fshm_open to denote that we should not automatically destroy the stream when the FSHM_OWNER closes it. If the owner provides this flag then the stream must be explicitly destroyed by calling fshm_force_destroy
The source code contains the following examples/tests of libshmfile which can be used as references:
examples/owner ( from examples/owner.c ) is an example that creates a stream ( as FSHM_OWNER ), writes some data to it, and leaves it open for a period of time.
examples/guest ( from examples/guest.c ) is an example that connects to an existing stream ( as FSHM_GUEST ), reads data from it, and prints it to stdout.
These examples test using a struct as data which is given initial values by "owner", and is updated each time "guest" is run.
The examples show both buffered I/O (fwrite and fflush), as well as unbuffered I/O (read and write).
Optionally, the fshm_chgrp method will be used if you uncomment and set the SET_GID_MACRO at the top of examples/owner.c