29 #include <sys/types.h>
42 #include "debug_lock.h"
43 #include "shm_arena.h"
45 #include "arena_lock.h"
48 #define DEFAULT_NAME_PREFIX "~"
49 #define DEFAULT_NAME_SUFFIX "~"
53 void *allocate_segment(
struct shm_arena *a,
54 const char *name,
size_t size,
60 size_t total_seg_size;
65 SPEW(_DEBUG,
"Creating segment \"%s\" with size=%zu",
77 (with_rwlock?CHUNKS(
sizeof(pthread_rwlock_t)):0) +
78 CHUNKS(strlen(name)+1) +
81 seg = find_free_segment(a, total_seg_size, &mapnum);
96 _shm_detach_free_segment(a, seg, mapnum);
101 total_seg_size + CHUNKS(
sizeof(
struct seg_footer))))
109 SPEW(_DEBUG,
"Case 1: Found Free & Split");
112 free_hdr = (
struct seg_header *)(((uint8_t *)seg) + total_seg_size);
114 free_hdr->
length = (seg->
length*CHUNK - total_seg_size)/CHUNK;
116 (((uint8_t *)free_hdr) + (free_hdr->
length*CHUNK -
119 fdr->
flags = IS_FREE;
121 seg->
length = total_seg_size/CHUNK;
123 insert_free_segment(a, free_hdr, mapnum);
132 SPEW(_DEBUG,
"Case 2: Found Free With This Size");
147 if(fstat(a->
fd, &st))
149 SPEW_SYS_ERR_RET(NULL, _WARN, errno,
150 "fstat(fd=%d,) failed", a->
fd);
168 ASSERT(!(fdr->
flags & IS_FREE));
175 SPEW(_DEBUG,
"Case 3: Ftrunate & Add Segment");
181 ASSERT(st.st_size >= (off_t) (mhdr->
length_used*CHUNK));
183 if(ftruncate(a->
fd, st.st_size + total_seg_size))
185 SPEW_SYS_ERR_RET(NULL, _WARN, errno,
186 "ftruncate(fd=%d,) failed", a->
fd);
188 SPEW(_DEBUG,
"Total arena file size has increased to %lu bytes",
189 st.st_size + total_seg_size);
202 void *map_start = NULL;
208 pagesize = getpagesize();
216 if(ftruncate(a->
fd, old_map_end +
219 SPEW_SYS_ERR_RET(NULL, _WARN, errno,
220 "ftruncate(fd=%d,) failed", a->
fd);
222 SPEW(_DEBUG,
"Total arena file size has increased to %lu bytes",
223 old_map_end + total_seg_size + CHUNKS(
sizeof(
struct mapping_header)));
228 SPEW(_DEBUG,
"Case 4: Ftrunate & Add Free Pad & Add Mapping");
245 (((uint8_t *) seg) + (seg->
length*CHUNK -
248 fdr->
flags = IS_FREE;
256 SPEW(_DEBUG,
"Case 5: Ftrunate & Add Pad To Last Segment & Add Mapping");
276 if(with_rwlock) fdr->
flags |= WITH_RWLOCK;
285 SPEW(_DEBUG,
"Case 6: Ftrunate & Add Mapping");
297 SPEW_SYS_ERR_RET(NULL, _WARN, errno,
"realloc() failed");
304 map_start = (
void*)(((uintptr_t) a->
mapping[mapnum-1].
start) +
308 MAP_SHARED, a->
fd, old_map_end);
318 SPEW_SYS_ERR_RET(NULL, _WARN, errno,
"mmap() failed");
325 SPEW_SYS_ERR_RET(NULL, _WARN, errno,
326 "mmap() failed with SHM_ADDRESS set");
335 mhdr = get_mapping_header(a, mapnum);
345 SPEW(_DEBUG,
"Created new mapping of %zu pages = %zu bytes",
349 seg->
length = total_seg_size/CHUNK;
362 (((uint8_t *)seg) + (seg->
length*CHUNK - CHUNKS(
sizeof(
struct seg_footer))));
365 if(with_rwlock) fdr->
flags |= WITH_RWLOCK;
367 strcpy(get_seg_name(seg), name);
369 insert_alloc_segment(a, seg, mapnum);
374 pthread_rwlockattr_t attr;
375 if((err = pthread_rwlockattr_init(&attr)))
377 SPEW_SYS_ERR_RET(NULL, _WARN, err,
"pthread_rwlockattr_init() failed");
378 if((err = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)))
380 SPEW_SYS_ERR_RET(NULL, _WARN, err,
"pthread_rwlockattr_setpshared() failed");
381 if((err = pthread_rwlock_init(get_seg_rwlock(seg), &attr)))
383 SPEW_SYS_ERR_RET(NULL, _WARN, err,
"pthread_rwlock_init() failed");
384 SPEW(_DEBUG,
"Initialized segment rwlock");
387 return get_seg_ptr(seg);
439 char gen_name[GEN_NAME_SIZE] =
"";
440 void *ret_ptr = NULL;
443 SPEW(_INFO,
"%s(arena=%p, size=%zu, name=\"%s\", flags=%d)",
447 if((!name || !name[0]) && !((flags & O_CREAT) && (flags & O_EXCL)))
449 return SPEW_SYS_ERR_RET(NULL, _WARN, EINVAL,
450 "%s() failed: flags O_CREAT and "
451 "O_EXCL bits must be set if name "
452 "is not set", __func__);
455 return SPEW_SYS_ERR_RET(NULL, _WARN, EINVAL,
456 "%s() failed: O_CREAT is set "
457 "and size == SHM_UNKNOWN_SIZE",
464 arena = get_arena_min_size_and_autolock(arena,
465 (flags & O_CREAT)? 2: 1,
466 &err IF_SPEW(, __func__), size);
495 if(!(flags & O_CREAT))
498 if(_shm_arena_sync_mappings(IF_SPEW(__func__,) arena))
504 if(!(flags & O_CREAT))
513 if(!name || !name[0])
515 if(!((flags & O_CREAT) && (flags & O_EXCL)))
518 SPEW_SYS_ERR(_WARN, EINVAL,
519 "%s() failed: flags O_CREAT and "
520 "O_EXCL bits must be set if segment name "
521 "is not set", __func__);
530 snprintf(gen_name, GEN_NAME_SIZE,
531 DEFAULT_NAME_PREFIX
"%u"DEFAULT_NAME_SUFFIX,
533 ret_ptr = find_segment_name(arena, gen_name, NULL);
536 SPEW(_DEBUG,
"Generated segment name \"%s\"", name);
542 ret_ptr = find_segment_name(arena, name, &user_size);
544 if((flags & O_CREAT) && (flags & O_EXCL) && ret_ptr)
546 SPEW_SYS_ERR(_WARN, EINVAL,
547 "%s() failed: flags O_CREAT and "
548 "O_EXCL bits must not be set: segment named "
549 "\"%s\" exists.", __func__, name);
553 else if(!ret_ptr && !(flags & O_CREAT))
560 "%s() failed: flag O_CREAT is not set and segment named "
561 "\"%s\" does not exist.", __func__, name);
572 SPEW_SYS_ERR(_WARN, EINVAL,
573 "%s() failed: segment \"%s\" exists and has "
574 "a size %zu bytes not %zu bytes", __func__,
575 name, user_size, size);
581 (((uint8_t *) ret_ptr) - CHUNKS(
sizeof(
struct seg_header)));
582 if(get_seg_footer(seg)->flags & WITH_RWLOCK &&
586 SPEW_SYS_ERR(_WARN, EINVAL,
587 "%s() failed: segment \"%s\" exists and has "
588 "read-write locks. SHM_WITHOUT_RWLOCK"
589 " should not be set.",
592 else if(!(get_seg_footer(seg)->flags & WITH_RWLOCK) &&
596 SPEW_SYS_ERR(_WARN, EINVAL,
597 "%s() failed: segment \"%s\" exists and has "
598 "no read-write locks. SHM_WITHOUT_RWLOCK"
607 SPEW(_INFO,
"Connected to existing segment \"%s\" with size %zu bytes",
625 SPEW(_INFO,
"Created segment \"%s\" with size %zu bytes", name, size);
627 SPEW(_WARN,
"Failed to create segment \"%s\" with size %zu bytes", name, size);
633 err = arena_autounlock(arena IF_SPEW(, __func__));
635 arena_autounlock(arena IF_SPEW(, __func__));
struct arena_header * header
struct shm_mapping * mapping
pthread_mutex_t mapping_mutex
#define SHM_UNKNOWN_SIZE
shm_get() flag for when you don't know the segment size
void * shm_get(shm_arena_t arena, size_t size, const char *name, int flags)
get a shared memory segment
#define SHM_WITHOUT_RWLOCK
shm_get() flag for not having segment read-write lock