arena.h
1 /*
2  shm-arena shared memory arena
3  Copyright (C) 2006-2008 Lance Arsenault (LGPL v3)
4 
5 
6  This file is part of shm-arena.
7 
8  shm-arena is free software; you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as
10  published by the Free Software Foundation; either version 3 of the
11  License, or (at your option) any later version.
12 
13  shm-arena is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this program. If not, see
20  <http://www.gnu.org/licenses/>.
21 */
22 
23 /* extra 32 bit prime number: 0xBE2CEE45 */
24 
31 /* the max string length including the '\0' of the generated segment
32  * name made in get.c and refered to in smq.c. */
33 #define GEN_NAME_SIZE 32
34 
37 #define ARENA_MAGIC 0xCB35CC0D
38 
40 #define IS_FREE (01 << 0)
41 
42 #define WITH_RWLOCK (01 << 1)
43 
44 
47 #define PLUS_SIZE(x,s) ((((x)+(s)-1)/(s))*(s))
48 
50 #define PAGES(x, pagesize) PLUS_SIZE((x), (pagesize))
51 
54 #define CHUNKS(x) PLUS_SIZE((x), CHUNK)
55 
56 
60 typedef int16_t mapnum_t;
61 
62 #define MAPNUM_FORMAT "%"PRId16 /* for printing */
63 
83 typedef uint32_t offset_t;
84 
85 #define OFFSET_FORMAT "%"PRIu32 /* for printing */
86 
87 
95 typedef int32_t height_t;
96 
97 #define HEIGHT_FORMAT "%"PRId32 /* for printing */
98 
99 
132 {
150  height_t height;
153  offset_t length;
156  size_t user_length;
157 };
158 
159 
162 {
168  offset_t length;
171  uint32_t flags;
172 };
173 
337 {
345  offset_t map_length;
352  offset_t length_used;
353 };
354 
361 {
364  uint32_t magic;
365 
367  uint32_t flags;
368 
371  pthread_rwlock_t rwlock;
372 
375 
377  uint32_t name_count;
378 
383  uint32_t change_count;
384 
387  mapnum_t num_mappings;
388 
390  mapnum_t free_mapnum;
392  mapnum_t alloc_mapnum;
394  offset_t free_offset;
396  offset_t alloc_offset;
397 };
398 
402 {
405  uint8_t *start;
406 
410  offset_t map_length;
411 };
412 
422 {
427 };
428 
430 struct shm_arena
431 {
436  int fd;
437 
446  struct arena_header *header; /* not changing after arena creation. */
447 
455 
460 
464  uint32_t change_count;
465 
468  pthread_mutex_t mapping_mutex;
469 
473  pthread_mutex_t rwlock_mutex;
474 
479  pthread_key_t rwlock_key;
480 
485  };
486 
487 
488 /* Oh the shit we do to be thread-safe. */
489 static inline
490 struct rwlock_attr *get_rwlock_attr(struct shm_arena *a)
491 /* We have the two counters rdlock_count and wrlock_count for each
492  * thread so that each thread may have recursive arena read-write
493  * locks. So if the user calls shm_get() the user will automatically
494  * get a read or write arena lock. Or they may get the arena read or
495  * write lock explicitly with shm_arena_rdlock() or
496  * shm_arena_wrlock(). */
497 {
498  struct rwlock_attr *attr;
499  int err;
500 
501  ASSERT(a);
502 
503  /* We make sure that just one thread will initialize the per-thread
504  * flags in the struct rwlock_attr for each thread per arena. */
505  pthread_mutex_lock(&a->rwlock_mutex);
506  attr = (struct rwlock_attr *) pthread_getspecific(a->rwlock_key);
507  if(attr)
508  {
509  pthread_mutex_unlock(&a->rwlock_mutex);
510  return attr;
511  }
512 
513  attr = (struct rwlock_attr *) malloc(sizeof(struct rwlock_attr));
514  if(!attr)/* pretty well screwed. */
515  {
516  pthread_mutex_unlock(&a->rwlock_mutex);
517  return attr;
518  }
519 
520  if((err = pthread_setspecific(a->rwlock_key, attr)))
521  {
522  free(attr);
523  pthread_mutex_unlock(&a->rwlock_mutex);
524  return /* pretty well screwed. */
525  SPEW_SYS_ERR_RET(NULL, _WARN, err,
526  "pthread_setspecific() failed");
527  }
528  pthread_mutex_unlock(&a->rwlock_mutex);
529 
530  /* initialize it */
531  attr->rdlock_count = 0;
532  attr->wrlock_count = 0;
533 
534  SPEW(_DEBUG, "Initialized thread arena recursive read-write lock flags");
535  return attr;
536 }
537 
538 static inline
539 struct seg_footer *get_seg_footer(const struct seg_header *seg)
540 {
541  return (struct seg_footer *)
542  (((uint8_t *) seg +
543  (seg->length*CHUNK - CHUNKS(sizeof(struct seg_footer)))));
544 }
545 
546 /* seg_header and seg_footer must be set up to call this. */
547 static inline
548 char *get_seg_name(const struct seg_header *seg)
549 {
550  return (char *)
551  (((uint8_t *) seg +
552  (CHUNKS(sizeof(struct seg_header)) +
553  CHUNKS(seg->user_length) +
554  ((get_seg_footer(seg)->flags & WITH_RWLOCK)?
555  CHUNKS(sizeof(pthread_rwlock_t)):0))));
556 }
557 
558 /* get a pointer to the user data -- assumes that seg_header and
559  * seg_footer are set up. */
560 static inline
561 void *get_seg_ptr(struct seg_header *seg)
562 {
563  return (void *)
564  (((uint8_t *) seg +
565  CHUNKS(sizeof(struct seg_header))));
566 }
567 
568 
569 
570 /* returns the offset from the top of the mapping to the top of struct
571  * seg_header *seg in CHUNKs. Offset in bytes is CHUNK times this. */
572 static inline
573 offset_t get_offset(const struct shm_arena *a,
574  struct seg_header *seg, mapnum_t seg_mapnum)
575 {
576  return (offset_t)
577  (
578  (((uintptr_t) seg) - ((uintptr_t)(a->mapping[seg_mapnum].start)))/CHUNK
579  );
580 }
581 
582 static inline
583 struct seg_header *get_seg_header(const struct shm_arena *a,
584  mapnum_t map_num, offset_t offset)
585 {
586  if(offset)
587  return (struct seg_header *)
588  (((uint8_t *) (a->mapping[map_num].start)) + (offset*CHUNK));
589  else
590  return NULL;
591 }
592 
593 static inline
594 struct mapping_header *get_mapping_header(const struct shm_arena *a,
595  mapnum_t mapnum)
596 {
597  /* For Debug builds */
598  ASSERT(a);
599  ASSERT(a->mapping);
600  ASSERT(a->change_count > 0);
601  ASSERT(a->num_mappings > 0);
602  ASSERT(mapnum <= a->num_mappings && mapnum >= -1);
603 
604  if(mapnum == -1 || mapnum >= a->num_mappings + 1)
605  return NULL;
606 
607  if(mapnum != 0 && mapnum != 1)
608  return (struct mapping_header *)(a->mapping[mapnum-1].start);
609 
610  if(mapnum == 0)
611  return &(a->header->map_header);
612 
613  /* mapnum == 1 */
614  return (struct mapping_header *) (((uint8_t *)(a->mapping[0].start)) +
615  CHUNKS(sizeof(struct arena_header)));
616 }
617 
618 /* returns segment read-write lock or NULL is there are no segment
619  * read-write lock */
620 static inline
621 pthread_rwlock_t *ptr_rwlock(const void *ptr)
622 {
623  struct seg_header *seg;
624  seg = (struct seg_header *)
625  (((uint8_t *) ptr) - CHUNKS(sizeof(struct seg_header)));
626 
627  if(get_seg_footer(seg)->flags & WITH_RWLOCK)
628  return (pthread_rwlock_t *)
629  (((uint8_t *) ptr) + CHUNKS(seg->user_length));
630  return NULL;
631 }
632 
633 static inline
634 pthread_rwlock_t *get_seg_rwlock(const struct seg_header *seg)
635 {
636  ASSERT(get_seg_footer(seg)->flags & WITH_RWLOCK);
637 
638  return
639  (pthread_rwlock_t *)
640  (((uint8_t *) seg) +
641  CHUNKS(sizeof(struct seg_header)) +
642  CHUNKS(seg->user_length));
643 }
644 
645 /* return non-zero is there is an error. */
646 extern int
647 _shm_arena_sync_mappings(IF_SPEW(const char *func,)
648  struct shm_arena *arena);
struct arena_header * header
Definition: arena.h:446
uint32_t flags
Definition: arena.h:367
struct shm_mapping * mapping
Definition: arena.h:454
offset_t free_offset
Definition: arena.h:394
int num_mappings
Definition: arena.h:459
pthread_mutex_t mapping_mutex
Definition: arena.h:468
mapnum_t num_mappings
Definition: arena.h:387
pthread_mutex_t rwlock_mutex
Definition: arena.h:473
mapnum_t right_mapnum
Definition: arena.h:142
offset_t right_offset
Definition: arena.h:147
offset_t length_used
Definition: arena.h:352
pthread_key_t rwlock_key
Definition: arena.h:479
mapnum_t left_mapnum
Definition: arena.h:142
uint32_t change_count
Definition: arena.h:464
mapnum_t alloc_mapnum
Definition: arena.h:392
offset_t map_length
Definition: arena.h:345
pthread_rwlock_t rwlock
Definition: arena.h:371
offset_t length
Definition: arena.h:153
void * user_shm_address
Definition: arena.h:484
int rdlock_count
Definition: arena.h:424
struct mapping_header map_header
Definition: arena.h:374
offset_t map_length
Definition: arena.h:410
offset_t left_offset
Definition: arena.h:147
mapnum_t free_mapnum
Definition: arena.h:390
int wrlock_count
Definition: arena.h:426
uint32_t change_count
Definition: arena.h:383
uint32_t magic
Definition: arena.h:364
size_t user_length
Definition: arena.h:156
offset_t alloc_offset
Definition: arena.h:396
uint8_t * start
Definition: arena.h:405
int fd
Definition: arena.h:436
height_t height
Definition: arena.h:150
uint32_t name_count
Definition: arena.h:377

Shared Memory Arena version RC-0.0.25