. .

C: POSIX shared memory objects


Ich liste hier kurz eine Möglichkeit, unter Linux unterschiedlichen Prozessen Zugriff auf gemeinsamen Speicher über das Dateisystem zu geben. Dazu kann man sog. POSIX Shared Memory Objekte verwenden.

Es wird mit shm_open() entweder vorhandener Speicher geöffnet oder erstellt. Danach kann man über /dev/shm/[dateiname] auf diesen Speicherbereich zugreifen. Dieser verhält sich wie eine normale Datei.

Hier also erst einmal die Headerdatei mmap.h:

#ifndef PRJ_MMAP_H
#define PRJ_MMAP_H 1

#if defined(__cplusplus)
extern "C" {
#endif


int
prj_shm_mmap_create(char const *filename, int readonly);

int
prj_shm_mmap_write(int shmfd, char const *filecontent, size_t sz);

int
prj_shm_mmap_remove(char const *filename);


#if defined(__cplusplus)
}
#endif

#endif /* !PRJ_SHMEM_H */

Und danach der eigentliche Code mmap.c:
Beachtet bitte, dass die Funktion prjlog() in diesem Code angepasst werden muss.


#include <prjconfig.h>

#define _XOPEN_SOURCE 500 /* for snprintf */
#define _XOPEN_SOURCE_EXTENDED 1

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/mman.h>
#include <time.h>

#undef _XOPEN_SOURCE_EXTENDED
#undef _XOPEN_SOURCE

#include "logger.h"
#include "mmap.h"

/*
 * \brief   prj_shm_mmap_create
 *
 * Tries to open a POSIX shared memory object.
 * If this fails a POSIX shared memory object will be created.
 *
 * \param   filename        name of file applications are able to read in filesystem
 * \param   readonly        file should be opened readonly or not
 * 
 * \return                  on success POSIX shared memory object file descriptor, otherwise -1
 */
int
prj_shm_mmap_create(char const *filename, int readonly) {
    int shmfd;
    mode_t mode = 0400;

    if (readonly == 0)
        mode = 0600;

    shmfd = shm_open(filename, O_RDWR, mode);

    if (shmfd == -1) {
        shmfd = shm_open(filename, O_CREAT | O_RDWR | O_EXCL, mode);
        if (shmfd == -1) {
            prjlog("warn", "mmap", "shm_open() failed: %s (%d)", ERR, (int) errno);
            return -1; 
        }   
    }   

    return shmfd;
}

/*
 * \brief   prj_shm_mmap_write
 *
 * Writes content of `filecontent' to given POSIX shared memory object file descriptor
 *
 * \param   shmfd           POSIX shared memory object file descriptor
 * \param   filecontent     file data
 * \param   sz              size of data, filesize
 *
 * \return                  status code, 0 on success, otherwise -1 
 */
int
prj_shm_mmap_write(int shmfd, char const *filecontent, size_t sz) {
    char *r_ptr = NULL;

    if (ftruncate(shmfd, (off_t) sz) == -1) 
        return -1; 

    r_ptr = (char *) mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, (off_t) 0); 

    if (r_ptr == MAP_FAILED) {
        prjlog("warn", "mmap", "mmap() failed: %s (%d)", ERR, (int) errno);
        return -1; 
    }

    memcpy(r_ptr, filecontent, sz);

    return 0;
}

/*
 * \brief   prj_shm_mmap_remove
 *
 * Deletes POSIX shared memory object file.
 *
 * \param   filename        POSIX shared memory object file name
 *
 * \return                  status code from shm_unlink()
 */
int
prj_shm_mmap_remove(char const *filename) {
    return shm_unlink(filename);
}

Nun sind drei Funktionen verfügbar, die beispielhaft in etwa so verwendet werden können:

        /* some code before */

        snprintf(targetfile, len, "%s-%d_%s", pass_wd->pw_name, (int) timestamp, outfile);
        mmapfd = prj_shm_mmap_create(targetfile, openoptions.readonly);

        len += strlen("/dev/shm/");
        if ((shmfile = (char *) realloc(shmfile, len)) == NULL)
            memerror();
        snprintf(shmfile, len, "/dev/shm/%s", targetfile);

        if (prj_shm_mmap_write(mmapfd, input, sz) == -1)
            memerror();

        /* do something with content of file, eg. opens it with another application */

        prj_shm_mmap_remove(outfile);

        /* some code behind */

Viele Informationen lassen sich über „man 3 shm_open“ abrufen.


Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>