Initial commit - move development to a public repo
[libautomation/elektra-notification.git] / lib / shm.c
blob02bc7445436d9d8b2916304c6c25bf36447ff2cb
1 #include "libautomation.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/mman.h>
8 #include <sys/stat.h> /* For mode constants */
9 #include <fcntl.h> /* For O_* constants */
10 #include <sys/file.h>
11 #include <limits.h>
13 #include "managed_data.h"
15 #define MAGIC_NUMBER 217
17 #define SHM_SIZE 4096
19 ATM_SHM atm_shm_stdmem;
21 static int _atm_shm_open(const char *id, int flags) {
22 char name[NAME_MAX];
24 snprintf(name, NAME_MAX, "/dev/shm/libautomation_%s", id);
25 return open(name, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
28 static ATM_SHM _atm_shm_alloc(struct ATM_SHM_HEADER *h) {
29 ATM_SHM mem = malloc(sizeof(*mem));
31 mem->header = h;
32 mem->keys = (void *) h + sizeof(*h);
33 mem->data = (void *) h + SHM_SIZE/2;
35 return mem;
39 ATM_SHM atm_shm_attach(const char *id) {
40 struct ATM_SHM_HEADER *h;
41 ATM_SHM mem;
42 int fd;
44 fd = _atm_shm_open(id, O_RDONLY);
45 if (fd < 0)
46 return NULL;
48 flock(fd, LOCK_EX);
50 h = mmap(NULL, SHM_SIZE, PROT_READ, MAP_SHARED, fd, 0);
51 if (h == MAP_FAILED)
52 atm_fail(id); /* Should never happen */
54 if (h->magic != MAGIC_NUMBER) {
55 atm_log("Shared memory with id '%s' is corrupted!", id);
56 exit(1);
59 mem = _atm_shm_alloc(h);
60 flock(fd, LOCK_UN);
62 return mem;
65 ATM_SHM atm_shm_create(const char *id) {
66 struct ATM_SHM_HEADER *h;
67 ATM_SHM mem;
68 int fd;
69 struct stat fd_info;
71 fd = _atm_shm_open(id, O_RDWR | O_CREAT);
72 if (fd < 0)
73 return NULL;
75 flock(fd, LOCK_EX);
76 fstat(fd, &fd_info);
77 if (fd_info.st_size == 0) /* File was just created */
78 ftruncate(fd, SHM_SIZE);
79 else if (fd_info.st_size != SHM_SIZE) /* Not our file !!! */
80 goto wrong_file;
82 h = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
83 if (h == MAP_FAILED)
84 atm_fail(id); /* Should never happen */
86 mem = _atm_shm_alloc(h);
87 mem->fd = fd;
89 if (fd_info.st_size == 0) { /* Need to initialize data structure */
90 /* mem->keys[] already initialized by ftruncate() */
91 h->magic = MAGIC_NUMBER;
93 else if (h->magic != MAGIC_NUMBER) {
94 wrong_file:
95 atm_log("Shared memory with id '%s' is corrupted!", id);
96 exit(1);
99 flock(fd, LOCK_UN);
101 if (!atm_shm_stdmem)
102 atm_shm_stdmem = mem;
104 return mem;
108 * Internal version of atm_shm_find() assumes that mem->keys[] is already
109 * locked by mem->header->sem ...
111 static int _atm_shm_find(ATM_SHM mem, const char *key) {
112 int i;
113 char *p = mem->keys;
115 for (i = 0; *p; ++i) {
116 if (!strcmp(p, key))
117 return i;
119 p += strlen(&mem->keys[i]) + 1;
122 return -1;
125 struct ATM_VALUE *atm_shm_find(ATM_SHM mem, const char *key) {
126 int i;
128 flock(mem->fd, LOCK_EX);
129 i = _atm_shm_find(mem, key);
130 flock(mem->fd, LOCK_UN);
132 return i == -1 ? NULL : &mem->data[i];
135 struct ATM_VALUE *atm_shm_register(ATM_SHM mem, const char *key) {
136 int i, keysize;
138 flock(mem->fd, LOCK_EX);
140 i = _atm_shm_find(mem, key);
141 if (i == -1) {
142 keysize = strlen(key) + 1;
143 if (keysize + mem->header->ks + sizeof(*mem->header) >= SHM_SIZE/2) {
144 atm_log("running out of shared memory, crashing ...");
145 exit(1);
147 strcpy(&mem->keys[mem->header->ks], key);
148 mem->header->ks += keysize;
149 i = mem->header->value_count++;
152 flock(mem->fd, LOCK_UN);
154 return &mem->data[i];
157 struct MD_LUT _atm_shm_lut = {0, 0, NULL};
159 struct ATM_VALUE *atm_shm_get(const char *id, const char *key) {
160 struct MD_LUT_ENTRY *e = NULL;
161 ATM_SHM mem;
163 if (_atm_shm_lut.size == 0)
164 md_lut_init(&_atm_shm_lut);
165 else
166 e = md_lut_find(&_atm_shm_lut, id);
168 if (e)
169 return atm_shm_find(e->data, key);
171 mem = atm_shm_attach(id);
172 if (!mem)
173 return NULL;
175 md_lut_insert(&_atm_shm_lut, id, mem);
177 return atm_shm_find(mem, key);
180 void atm_shm_update(struct ATM_VALUE *var, int value) {
181 var->v = value;
182 var->ts = atm_timestamp();
185 struct ATM_VALUE *atm_value(const char *key) {
186 return (atm_shm_stdmem && key) ? atm_shm_register(atm_shm_stdmem, key)
187 : malloc(sizeof(struct ATM_VALUE));