Commit f49685ec authored by Alessandro Rubini's avatar Alessandro Rubini Committed by Adam Wujek

arch-wrs: new shmem, split per-process and w/ bigger size

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 52fda5e9
......@@ -6,10 +6,11 @@
#define __WRS_SHM_H__
#include <stdint.h>
#define WRS_SHM_FILE "/dev/shm/wrs-shmem"
#define WRS_SHM_SIZE (64*1024) /* each */
#define WRS_SHM_FILE "/dev/shm/wrs-shmem-%i"
#define WRS_SHM_MIN_SIZE (4*1024)
#define WRS_SHM_MAX_SIZE (256*1024)
/* Every process gets 8 pages (32k) to be safe for the future */
/* Each process "name" (i.e. id) is added to the filename above */
enum wrs_shm_name {
wrs_shm_ptp,
wrs_shm_rtu,
......@@ -25,7 +26,7 @@ struct wrs_shm_head {
unsigned long stamp; /* Last modified, w/ CLOCK_MONOTONIC */
unsigned long data_off; /* Where the structure lives */
int shm_name; /* The enum above, for cross-checking */
int fd; /* So we can enlarge it using fd */
int pid; /* The current pid owning the area */
unsigned pidsequence; /* Each new pid must increments this */
......
/* Alessandro Rubini for CERN 2014, LGPL-2.1 or later */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
......@@ -18,6 +19,7 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
struct wrs_shm_head *head;
struct stat stbuf;
void *map;
char fname[64];
int write_access = flags & WRS_SHM_WRITE;
int fd;
......@@ -26,20 +28,22 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
return NULL;
}
fd = open(WRS_SHM_FILE, O_RDWR | O_CREAT | O_SYNC, 0644);
sprintf(fname, WRS_SHM_FILE, name_id);
fd = open(fname, O_RDWR | O_CREAT | O_SYNC, 0644);
if (fd < 0)
return NULL; /* keep errno */
/* The file may be too short: enlarge it as needed */
/* The file may be too short: enlarge it to the minimum size */
if (fstat(fd, &stbuf) < 0)
return NULL; /* keep errno */
if (stbuf.st_size < WRS_SHM_SIZE * (name_id + 1)) {
lseek(fd, WRS_SHM_SIZE * (name_id + 1) -1, SEEK_SET);
if (stbuf.st_size < WRS_SHM_MIN_SIZE) {
lseek(fd, WRS_SHM_MIN_SIZE - 1, SEEK_SET);
write(fd, "", 1);
}
map = mmap(0, WRS_SHM_SIZE,
map = mmap(0, WRS_SHM_MAX_SIZE,
PROT_READ | (write_access ? PROT_WRITE : 0),
MAP_SHARED, fd, WRS_SHM_SIZE * name_id);
MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
return NULL; /* keep errno */
if (!write_access)
......@@ -48,10 +52,11 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
/* Init the fields */
head = map;
if (head->pid && kill(head->pid, 0) == 0) {
munmap(map, WRS_SHM_SIZE);
munmap(map, WRS_SHM_MAX_SIZE);
errno = EBUSY;
return NULL;
}
head->fd = fd;
head->sequence = 1; /* a sort of lock */
head->mapbase = head;
strncpy(head->name, name, sizeof(head->name));
......@@ -59,7 +64,6 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
head->stamp = 0;
head->data_off = sizeof(*head);
head->data_size = 0;
head->shm_name = name_id;
head->pid = getpid();
head->pidsequence++;
/* version and size are up to the user (or to allocation) */
......@@ -74,9 +78,11 @@ int wrs_shm_put(void *headptr)
{
struct wrs_shm_head *head = headptr;
int err;
if (head->pid == getpid())
if (head->pid == getpid()) {
head->pid = 0; /* mark that we are not writers any more */
if ((err = munmap(headptr, WRS_SHM_SIZE)) < 0)
close(head->fd);
}
if ((err = munmap(headptr, WRS_SHM_MAX_SIZE)) < 0)
return err;
return 0;
}
......@@ -89,10 +95,15 @@ void *wrs_shm_alloc(void *headptr, size_t size)
if (head->pid != getpid())
return NULL; /* we are not writers */
if (head->data_off + head->data_size + size > WRS_SHM_SIZE)
if (head->data_off + head->data_size + size > WRS_SHM_MAX_SIZE)
return NULL; /* no space left */
nextptr = headptr + head->data_off + head->data_size;
head->data_size += (size + 7) & ~7; /* force 8-alignment */
/* Before we write to shmem, ensure the backing store exists */
lseek(head->fd, head->data_off + head->data_size - 1, SEEK_SET);
write(head->fd, "", 1);
memset(nextptr, 0, size);
return nextptr;
}
......@@ -102,7 +113,7 @@ void *wrs_shm_follow(void *headptr, void *ptr)
{
struct wrs_shm_head *head = headptr;
if (ptr < head->mapbase || ptr > head->mapbase + WRS_SHM_SIZE)
if (ptr < head->mapbase || ptr > head->mapbase + WRS_SHM_MAX_SIZE)
return NULL; /* not in the area */
return headptr + (ptr - head->mapbase);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment