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.