29 #include <sys/types.h>
44 #include "debug_lock.h"
45 #include "shm_arena.h"
47 #include "arena_lock.h"
51 #define IS_FULL_PATH(x) ((x)&&(x)[0]==DIR_CHAR&&(x)[1])
53 struct shm_arena *_shm_default_arena = NULL;
54 pthread_mutex_t _shm_create_arena_mutex = PTHREAD_MUTEX_INITIALIZER;
57 static int num_arenas = 0;
59 static int atfork_set = 0;
62 static void prefork(
void)
66 for(i=0;i<num_arenas;i++)
75 pthread_rwlock_wrlock(arena_rwlock(arenas[i]));
79 pthread_mutex_lock(&_shm_create_arena_mutex);
82 static void parent_postfork(
void)
87 pthread_mutex_unlock(&_shm_create_arena_mutex);
88 for(i=0;i<num_arenas;i++)
92 pthread_rwlock_unlock(arena_rwlock(arenas[i]));
96 static void child_postfork(
void)
101 pthread_mutex_unlock(&_shm_create_arena_mutex);
102 for(i=0;i<num_arenas;i++)
108 pthread_getspecific(arenas[i]->rwlock_key);
115 pthread_mutex_unlock(&arenas[i]->mapping_mutex);
116 pthread_mutex_unlock(&arenas[i]->rwlock_mutex);
126 static int rec_mkdir(
const char *dir, mode_t mode)
129 mode |= (S_IXUSR|S_IXGRP|S_IXOTH);
131 if(!mkdir(dir, mode))
132 return SPEW_RET(0, _DEBUG,
"Made directory \"%s\".", dir);
134 char *parent_dir = strdup(dir);
136 return SPEW_RET(errno?errno:ENOMEM, _WARN,
144 for(;*s != DIR_CHAR && s != parent_dir; s--);
148 if(*parent_dir ==
'\0')
155 int i = stat(parent_dir,&st);
156 if(i && errno == ENOENT && !rec_mkdir(parent_dir, mode))
160 if(!mkdir(dir, mode))
161 return SPEW_RET(0, _DEBUG,
"Made directory \"%s\".", dir);
163 return SPEW_RET(errno?errno:-1,
164 _WARN,
"mkdir(\"%s\", mode=0%o) failed:", dir, mode);
169 if(S_ISDIR(st.st_mode))
176 SPEW(_WARN,
"Failed to make directory \"%s\" because the file"
178 " and is not a directory.", dir, parent_dir);
185 return SPEW_RET(-1, _WARN,
"Failed to make directory \"%s\".", dir);
189 # define STRCPY(x,y) strcpy(x,y)
198 arena_path(
const char *path,
int *flags,
char **alloc_path_out)
204 *alloc_path_out = NULL;
206 if(!path || !(path[0]))
208 file = getenv(
"SHM_DEFAULT_ARENA_FILE");
213 file = (
char *) path;
218 && IS_FULL_PATH(file)
219 && strncmp(
"/dev/shm/", file, 9))
225 if(!strncmp(
"/dev/shm/", file, 9))
235 if((flags && ((*flags) & SHM_WITH_SHM_OPEN)) || IS_FULL_PATH(file))
237 apath = strdup(file);
238 if(!apath)
return ENOMEM;
239 *alloc_path_out = apath;
243 dir = getenv(
"SHM_DEFAULT_ARENA_DIR");
247 if(!strncmp(
"/dev/shm", dir, 8))
253 if(dir[0] == DIR_CHAR)
260 malloc(strlen(dir) + strlen(DIR_STRING) + strlen(file) + 1);
261 if(!apath)
return ENOMEM;
262 sprintf(apath,
"%s"DIR_STRING
"%s", dir, file);
263 *alloc_path_out = apath;
267 apath = strdup(file);
268 if(!apath)
return ENOMEM;
269 *alloc_path_out = apath;
277 static void rwlock_attr_destructor(
void *ptr)
279 SPEW(_INFO,
"%s(ptr=%p)", __func__, ptr);
394 char err_str[64] =
"";
396 uint32_t arena_flags = 0;
399 void *start = MAP_FAILED;
400 size_t map_length = 0;
402 pthread_rwlock_t *rwlock = 0;
406 SPEW(_INFO,
"%s(path=\"%s\", flags=%d, mode=0%o, min_size=%zu)",
407 __func__, path, flags, mode, min_size);
411 err = arena_path(path, &flags, &apath);
412 else if(path == NULL || !path[0])
415 SPEW(_WARN,
"Bad path \"%s\"\n", path);
422 SPEW(_WARN,
"Can't use arena file path");
426 if(apath) path = apath;
433 HAVE_CREATE_ARENA_MUTEX |
448 shm_address = getenv(
"SHM_ADDRESS");
453 val = strtoul(shm_address, NULL, 16);
454 if(errno || val == 0)
457 SPEW(_WARN,
"Invalid env SHM_ADDRESS");
460 user_shm_address = (
void*) val;
467 if(!(arena_flags & HAVE_CREATE_ARENA_MUTEX))
468 pthread_mutex_lock(&_shm_create_arena_mutex);
471 if(!(SHM_WITH_SHM_OPEN & flags) && flags & O_CREAT)
474 char *dir = strdup(path);
484 for(;*s != DIR_CHAR && s != dir;s--);
486 if(*dir && rec_mkdir(dir, mode))
490 STRCPY(err_str,
": Can't make directory");
503 if(SHM_WITH_SHM_OPEN & arena_flags)
504 fd = shm_open(path, flags, mode);
506 fd = open(path, flags, mode);
512 if(SHM_WITH_SHM_OPEN & arena_flags)
513 STRCPY(err_str,
": shm_open() failed");
515 STRCPY(err_str,
": open() failed");
522 if(flock(fd, LOCK_EX))
525 STRCPY(err_str,
": Can't flock(fd, LOCK_EX) file");
534 STRCPY(err_str,
": Can't stat file");
539 st.st_size < (off_t) (CHUNKS(
sizeof(
struct arena_header)) +
544 STRCPY(err_str,
": existing file not big enough");
558 STRCPY(err_str,
": read() failed");
564 STRCPY(err_str,
": Can't read file");
568 if(shm.
magic != ARENA_MAGIC)
570 STRCPY(err_str,
": Bad magic number in file");
575 if((shm.
flags & SHM_WITH_SHM_OPEN) != (arena_flags & SHM_WITH_SHM_OPEN))
578 if(arena_flags & SHM_WITH_SHM_OPEN)
579 STRCPY(err_str,
": Arena file not using shm_open(), "
582 STRCPY(err_str,
": Arena file is using shm_open(), "
583 "but is not requested");
588 if(lseek(fd, 0, SEEK_SET) == -1)
590 STRCPY(err_str,
": lseek(fd, 0, SEEK_SET) failed");
598 start = mmap(user_shm_address, map_length,
599 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
600 if(start == MAP_FAILED)
602 STRCPY(err_str,
": mmap() failed");
606 if(user_shm_address && user_shm_address != start)
611 sprintf(err_str,
": mmap()=%p failed "
612 "with SHM_ADDRESS=%p", start, user_shm_address);
619 if((err = pthread_rwlock_rdlock(rwlock)))
622 STRCPY(err_str,
": pthread_rwlock_rdlock() failed");
630 pthread_rwlockattr_t attr;
633 if(min_size < 1) min_size = 1;
638 map_length = PAGES(file_length +
641 CHUNKS(
sizeof(pthread_rwlock_t)) +
648 (start = mmap(user_shm_address, map_length,
649 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0));
651 if(start == MAP_FAILED)
653 STRCPY(err_str,
": mmap() failed");
662 if(ftruncate(fd, file_length))
665 sprintf(err_str,
": ftruncate(fd=%d, length=%zu) failed",
673 munmap(start, map_length);
682 if(user_shm_address && user_shm_address != start)
687 sprintf(err_str,
": mmap()=%p failed "
688 "with SHM_ADDRESS=%p", start, user_shm_address);
694 if((err = pthread_rwlockattr_init(&attr)))
696 STRCPY(err_str,
": pthread_rwlockattr_init() failed");
699 if((err = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)))
701 STRCPY(err_str,
": pthread_rwlockattr_setpshared() failed");
704 if((err = pthread_rwlock_init(&header->
rwlock, &attr)))
706 STRCPY(err_str,
": pthread_rwlock_init() failed");
709 if((err = pthread_rwlock_wrlock(&(header->
rwlock))))
711 STRCPY(err_str,
": pthread_rwlock_rdlock() failed");
715 rwlock = &(header->
rwlock);
755 SPEW(_DEBUG,
"%s(): %s %sshared memory arena \"%s\"",
758 "created":
"connected to",
759 arena_flags&SHM_WITH_SHM_OPEN?
"shm_open type ":
"",
774 if((err = pthread_key_create(&arena->
rwlock_key,
775 rwlock_attr_destructor)))
777 STRCPY(err_str,
": pthread_key_create() failed");
782 STRCPY(err_str,
": pthread_mutex_init() failed");
785 if((err = pthread_mutex_init(&arena->
rwlock_mutex, NULL)))
787 STRCPY(err_str,
": pthread_mutex_init() failed");
802 SPEW(_INFO,
"mapped %p -> %p %zu bytes",
817 (((uint8_t *)start) + CHUNKS(
sizeof(
struct arena_header)));
828 (
void*)(((uintptr_t)user_shm_address +
832 PROT_READ|PROT_WRITE, MAP_SHARED, fd, total_len);
835 STRCPY(err_str,
": mmap() failed");
839 if(user_shm_address &&
842 STRCPY(err_str,
": mmap() failed with SHM_ADDRESS set");
847 SPEW(_INFO,
"mapped %p -> %p %zu bytes",
861 if(((
struct arena_header *)start)->magic != ARENA_MAGIC)
865 if((err = pthread_rwlock_unlock(rwlock)))
868 STRCPY(err_str,
": pthread_rwlock_unlock() failed");
877 if((err = pthread_rwlock_unlock(rwlock)))
881 STRCPY(err_str,
": pthread_rwlock_unlock() failed");
892 _shm_default_arena = arena;
893 SPEW(_DEBUG,
"Made this new arena object the default "
900 if((err = pthread_atfork(prefork,
901 parent_postfork, child_postfork)))
903 STRCPY(err_str,
": pthread_atfork() failed");
911 realloc(arenas,
sizeof(
struct shm_arena *)*num_arenas);
916 STRCPY(err_str,
": realloc() failed");
919 arenas[num_arenas-1] = arena;
921 if(have_flock && flock(fd, LOCK_UN))
924 STRCPY(err_str,
": flock(fd, LOCK_UN) failed");
928 if(!(arena_flags & HAVE_CREATE_ARENA_MUTEX))
929 pthread_mutex_unlock(&_shm_create_arena_mutex);
944 SPEW_SYS(_WARN,
"%s() failed%s: failed "
945 "to attach to shared memory file \"%s\"",
946 __func__, err_str, path);
948 if(start != MAP_FAILED &&
952 if(arena_flags & SHM_WITH_SHM_OPEN)
977 else if(start != MAP_FAILED)
978 munmap(start, map_length);
981 pthread_rwlock_unlock(rwlock);
984 if(start != MAP_FAILED)
985 munmap(start, map_length);
987 if(have_flock && fd != -1)
990 if(fd != -1) close(fd);
992 if(apath) free(apath);
999 if(!(arena_flags & HAVE_CREATE_ARENA_MUTEX))
1000 pthread_mutex_unlock(&_shm_create_arena_mutex);
1022 SPEW(_INFO,
"%s(arena=%p)", __func__, arena);
1024 arena = get_arena(arena, 1, &err IF_SPEW(, __func__));
1032 pthread_mutex_lock(&_shm_create_arena_mutex);
1040 if((ptr = pthread_getspecific(arena->
rwlock_key)))
1044 pthread_setspecific(arena->
rwlock_key, NULL);
1054 SPEW_SYS(_WARN,
"%s() failed: munmap() mapping number="
1055 MAPNUM_FORMAT
" failed",
1079 realloc(arenas,
sizeof(
struct shm_arena *)*num_arenas);
1093 if(arena != _shm_default_arena)
1095 pthread_mutex_unlock(&_shm_create_arena_mutex);
1101 _shm_default_arena = NULL;
1102 pthread_mutex_unlock(&_shm_create_arena_mutex);
1133 SPEW(_INFO,
"%s(\"%s\", flags=%d)", __func__, path, flags);
1136 arena_path(path, &flags, &apath))
1139 if(flags & SHM_USE_GIVEN_PATH && (path == NULL || !path[0]))
1142 SPEW(_WARN,
"Bad path \"%s\"\n", path);
1146 if(apath) path = apath;
1148 if(flags & SHM_WITH_SHM_OPEN)
1151 fd = open(path, O_RDONLY);
1155 SPEW_SYS(_WARN,
"%s() failed to %sopen \"%s\"",
1157 (flags & SHM_WITH_SHM_OPEN)?
"SHM_":
"", path);
1160 if(read(fd, &a_hdr,
sizeof(a_hdr)) !=
sizeof(a_hdr))
1162 SPEW_SYS(_WARN,
"%s() failed to read \"%s\"",
1167 if(a_hdr.
flags & SHM_WITH_SHM_OPEN)
1172 ret = shm_unlink(path);
1187 SPEW(_INFO,
"Removed %sarena file \"%s\"",
1188 (flags & SHM_WITH_SHM_OPEN)?
"/dev/shm ":
"", path);
1190 SPEW(_INFO,
"Failed to remove %sarena file \"%s\"",
1191 (flags & SHM_WITH_SHM_OPEN)?
"/dev/shm ":
"", path);
struct arena_header * header
struct shm_mapping * mapping
pthread_mutex_t mapping_mutex
pthread_mutex_t rwlock_mutex
#define SHM_RW_MODE
a mode with all the read and write bits enabled
shm_arena_t shm_arena_create(const char *path, int flags, mode_t mode, size_t min_size)
create a shared memory arena object
#define SHM_DEFAULT_ARENA_DIR
the default arena directory
int shm_arena_destroy(const char *path, int flags)
destroy a shared memory arena file
#define SHM_WITH_SHM_OPEN
shm_arena_create() flag to use shm_open()
#define SHM_ARENA_DEFAULT
shm_arena_create() flag for insuring this is the default arena
#define SHM_DEFAULT_ARENA_FILE
the default arena file
#define SHM_USE_GIVEN_PATH
shm_arena_create() flag interpting arena file path
#define SHM_ARENA_HAVE_FLOCK
shm_arena_create() flag for advisory file lock
int shm_arena_delete(shm_arena_t arena)
delete a local shared memory arena object