arena.c
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 
27 #include "config.h"
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <inttypes.h>
37 #include <sys/file.h>
38 #include <sys/mman.h>
39 #include <stdint.h>
40 
41 #include <pthread.h>
42 #include "spew.h"
43 #include "assert.h"
44 #include "debug_lock.h"
45 #include "shm_arena.h"
46 #include "arena.h"
47 #include "arena_lock.h"
48 #include "avl.h"
49 
50 
51 #define IS_FULL_PATH(x) ((x)&&(x)[0]==DIR_CHAR&&(x)[1])
52 
53 struct shm_arena *_shm_default_arena = NULL;
54 pthread_mutex_t _shm_create_arena_mutex = PTHREAD_MUTEX_INITIALIZER;
55 
56 /* list of all arenas. Protected by _shm_create_arena_mutex. */
57 static int num_arenas = 0; /* array length */
58 static struct shm_arena **arenas; /* array of all arenas allocated. */
59 static int atfork_set = 0; /* atfork callbacks are set up. */
60 
61 
62 static void prefork(void)
63 /* called before fork() if there is or were any arena objects. */
64 {
65  int i;
66  for(i=0;i<num_arenas;i++)
67  {
68  /* To avoid deadlock we must as a rule get the arena file write
69  * (or read) lock and hold it before the mutex locks, and not
70  * the other way around. That's what happens in shm_get(),
71  * shm_remove() and the other shared memory segment
72  * functions. */
73  /* This must be a write lock in order to stop any segment
74  * inter-process arena file read or write lock calls. */
75  pthread_rwlock_wrlock(arena_rwlock(arenas[i]));
76  pthread_mutex_lock(&arenas[i]->rwlock_mutex);
77  pthread_mutex_lock(&arenas[i]->mapping_mutex);
78  }
79  pthread_mutex_lock(&_shm_create_arena_mutex);
80 }
81 
82 static void parent_postfork(void)
83 /* called after fork() by the parent if there is or were any arena
84  * objects. */
85 {
86  int i;
87  pthread_mutex_unlock(&_shm_create_arena_mutex);
88  for(i=0;i<num_arenas;i++)
89  {
90  pthread_mutex_unlock(&arenas[i]->mapping_mutex);
91  pthread_mutex_unlock(&arenas[i]->rwlock_mutex);
92  pthread_rwlock_unlock(arena_rwlock(arenas[i]));
93  }
94 }
95 
96 static void child_postfork(void)
97 /* called after fork() by the child if there is or were any arena
98  * objects. */
99 {
100  int i;
101  pthread_mutex_unlock(&_shm_create_arena_mutex);
102  for(i=0;i<num_arenas;i++)
103  {
104  struct rwlock_attr *attr;
105  /* Reset any rwlock flags that may have been passed down from
106  * the parent process. */
107  attr = (struct rwlock_attr *)
108  pthread_getspecific(arenas[i]->rwlock_key);
109  if(attr)
110  {
111  attr->rdlock_count = 0;
112  attr->wrlock_count = 0;
113  }
114 
115  pthread_mutex_unlock(&arenas[i]->mapping_mutex);
116  pthread_mutex_unlock(&arenas[i]->rwlock_mutex);
117  /* Do we inherit this inter-process lock from the parent? The
118  * answer is NO. So we do not call
119  * pthread_rwlock_unlock(arena_rwlock(arenas[i])); */
120  }
121 }
122 
123 
124 /* return 0 on success, returns system errno on error or -1 if not a
125  * sys error. */
126 static int rec_mkdir(const char *dir, mode_t mode)
127 {
128  /* directory require execute permission */
129  mode |= (S_IXUSR|S_IXGRP|S_IXOTH);
130 
131  if(!mkdir(dir, mode))
132  return SPEW_RET(0, _DEBUG, "Made directory \"%s\".", dir);
133 
134  char *parent_dir = strdup(dir);
135  if(!parent_dir)
136  return SPEW_RET(errno?errno:ENOMEM, _WARN,
137  "malloc() failed");
138 
139  {
140  char *s;
141  s = parent_dir;
142  for(;*s;s++);
143 
144  for(;*s != DIR_CHAR && s != parent_dir; s--);
145  *s = '\0';
146  }
147 
148  if(*parent_dir == '\0')
149  {
150  free(parent_dir);
151  return 0;
152  }
153 
154  struct stat st;
155  int i = stat(parent_dir,&st);
156  if(i && errno == ENOENT && !rec_mkdir(parent_dir, mode))
157  // parent_dir did not exist and we made it by recursing.
158  {
159  free(parent_dir);
160  if(!mkdir(dir, mode))
161  return SPEW_RET(0, _DEBUG, "Made directory \"%s\".", dir);
162  else
163  return SPEW_RET(errno?errno:-1,
164  _WARN, "mkdir(\"%s\", mode=0%o) failed:", dir, mode);
165  }
166 
167  if(i == 0) // this part of the path exists
168  {
169  if(S_ISDIR(st.st_mode))
170  {
171  free(parent_dir);
172  return 0;
173  }
174  else
175  {
176  SPEW(_WARN, "Failed to make directory \"%s\" because the file"
177  " \"%s\" exists"
178  " and is not a directory.", dir, parent_dir);
179  free(parent_dir);
180  return -1;
181  }
182  }
183 
184  free(parent_dir);
185  return SPEW_RET(-1, _WARN, "Failed to make directory \"%s\".", dir);
186 }
187 
188 #ifdef WITH_SPEW
189 # define STRCPY(x,y) strcpy(x,y)
190 #else
191 # define STRCPY(x,y) /* empty macro */
192 #endif
193 
194 /* Find the shared memory arena file path */
195 /* return 0 on success, return errno on error. alloc_path_out will
196  * point to the malloc() allocated string or NULL on failure. */
197 static int
198 arena_path(const char *path, int *flags, char **alloc_path_out)
199 {
200  char *apath = NULL;
201  char *dir = NULL;
202  char *file = NULL;
203 
204  *alloc_path_out = NULL;
205 
206  if(!path || !(path[0]))
207  {
208  file = getenv("SHM_DEFAULT_ARENA_FILE");
209  if(!file)
210  file = SHM_DEFAULT_ARENA_FILE;
211  }
212  else
213  file = (char *) path;
214 
215 #if 0 /* let shm_open() fail if it wants to. */
216  if((flags) &&
217  ((*flags) & SHM_WITH_SHM_OPEN)
218  && IS_FULL_PATH(file)
219  && strncmp("/dev/shm/", file, 9))
220  /* This is a bad path that should start with /dev/shm/ or not a
221  * full path. */
222  return EINVAL; /* "Invalid argument" */
223 #endif
224 
225  if(!strncmp("/dev/shm/", file, 9))
226  {
227  if(flags)
228  (*flags) |= SHM_WITH_SHM_OPEN;
229  file += 9; /* strip off the /dev/shm/ shm_open() does not like
230  * it. */
231  if(!file[0])
232  return EINVAL; /* "Invalid argument" */
233  }
234 
235  if((flags && ((*flags) & SHM_WITH_SHM_OPEN)) || IS_FULL_PATH(file))
236  {
237  apath = strdup(file);
238  if(!apath) return ENOMEM;
239  *alloc_path_out = apath;
240  return 0;
241  }
242 
243  dir = getenv("SHM_DEFAULT_ARENA_DIR");
244  if(!dir)
245  dir = SHM_DEFAULT_ARENA_DIR;
246 
247  if(!strncmp("/dev/shm", dir, 8))
248  {
249  if(flags)
250  (*flags) |= SHM_WITH_SHM_OPEN;
251  dir += 8; /* strip off the /dev/shm shm_open() does not like
252  * it. */
253  if(dir[0] == DIR_CHAR)
254  dir++;
255  }
256 
257  if(dir[0])
258  {
259  apath = (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;
264  }
265  else
266  {
267  apath = strdup(file);
268  if(!apath) return ENOMEM;
269  *alloc_path_out = apath;
270  }
271 
272  return 0;
273 }
274 
275 /* cleans up memory for the pre-thread pre-arena object automatic
276  * arena read-write locks. See struct rwlock_attr in arena.h. */
277 static void rwlock_attr_destructor(void *ptr)
278 {
279  SPEW(_INFO, "%s(ptr=%p)", __func__, ptr);
280  if(ptr)
281  free(ptr); /* frees a struct rwlock_attr */
282 }
283 
284 
387 shm_arena_t shm_arena_create(const char *path, int flags, mode_t mode,
388  size_t min_size)
389 {
390  struct stat st;
391  char *apath = NULL; /* allocated path if we have too */
392  int err = 0; /* will be errno if needed */
393 #ifdef WITH_SPEW
394  char err_str[64] = "";
395 #endif
396  uint32_t arena_flags = 0;
397 
398  int fd = -1;
399  void *start = MAP_FAILED;
400  size_t map_length = 0;
401  struct shm_arena *arena = NULL;
402  pthread_rwlock_t *rwlock = 0;
403  int have_flock = 0; /* got the flock here in this function */
404  void *user_shm_address = NULL;
405 
406  SPEW(_INFO, "%s(path=\"%s\", flags=%d, mode=0%o, min_size=%zu)",
407  __func__, path, flags, mode, min_size);
408 
409  /* find the path to the arena file */
410  if(!(flags & SHM_USE_GIVEN_PATH))
411  err = arena_path(path, &flags, &apath);
412  else if(path == NULL || !path[0])
413  {
414  errno = ENOENT; /* "No such file or directory" */
415  SPEW(_WARN, "Bad path \"%s\"\n", path);
416  return NULL;
417  }
418 
419  if(err)
420  {
421  errno = err;
422  SPEW(_WARN, "Can't use arena file path");
423  return NULL;
424  }
425 
426  if(apath) path = apath;
427 
428  /* save these flags for later below. */
429  arena_flags =
430  (SHM_WITH_SHM_OPEN |
431  SHM_USE_GIVEN_PATH |
433  HAVE_CREATE_ARENA_MUTEX |
434  SHM_ARENA_HAVE_FLOCK) & flags;
435 
436  /* creation flags are:
437 
438  0 = just connect
439  O_CREAT = create and connect or just connect
440  O_CREATE|O_EXCL = create and connect
441 
442  that is or'd with the SHM_WITH_SHM_OPEN bit flag
443  */
444 
445  {
446  /************************* handle env SHM_ADDRESS ***********************/
447  char *shm_address;
448  shm_address = getenv("SHM_ADDRESS");
449  if(shm_address)
450  {
451  unsigned long val;
452  errno = 0;
453  val = strtoul(shm_address, NULL, 16);
454  if(errno || val == 0)
455  {
456  errno = EFAULT;
457  SPEW(_WARN, "Invalid env SHM_ADDRESS");
458  return NULL;
459  }
460  user_shm_address = (void*) val;
461  }
462  }
463 
464 
465  /* At this point the path is okay to use */
466 
467  if(!(arena_flags & HAVE_CREATE_ARENA_MUTEX))
468  pthread_mutex_lock(&_shm_create_arena_mutex);
469 
470 
471  if(!(SHM_WITH_SHM_OPEN & flags) && flags & O_CREAT)
472  {
473  /* Here we'll check that the directory part of path is made. */
474  char *dir = strdup(path);
475  if(!dir)
476  {
477  err = ENOMEM;
478  goto arena_error;
479  }
480  {
481  char *s;
482  s = dir;
483  for(;*s;s++);
484  for(;*s != DIR_CHAR && s != dir;s--);
485  *s = '\0';
486  if(*dir && rec_mkdir(dir, mode))
487  {
488  free(dir);
489  err = EACCES; /* Permission denied */
490  STRCPY(err_str, ": Can't make directory");
491  goto arena_error;
492  }
493  }
494  free(dir);
495  }
496 
497  /* At this point the directory part exists, or if it does not it
498  * will give the user the well earned error for not setting O_CREAT
499  * in flags. */
500 
501  flags &= 0x00FFFFFF; /* strip shm_arena specfic flags */
502 
503  if(SHM_WITH_SHM_OPEN & arena_flags)
504  fd = shm_open(path, flags, mode);
505  else
506  fd = open(path, flags, mode);
507 
508  if(fd == -1)
509  {
510  err = errno;
511 #ifdef WITH_SPEW
512  if(SHM_WITH_SHM_OPEN & arena_flags)
513  STRCPY(err_str, ": shm_open() failed");
514  else
515  STRCPY(err_str, ": open() failed");
516 #endif
517  goto arena_error;
518  }
519 
520  if(!(arena_flags & SHM_ARENA_HAVE_FLOCK))
521  {
522  if(flock(fd, LOCK_EX))
523  {
524  err = errno;
525  STRCPY(err_str, ": Can't flock(fd, LOCK_EX) file");
526  goto arena_error;
527  }
528  have_flock = 1;
529  }
530 
531  if(fstat(fd, &st))
532  {
533  err = errno;
534  STRCPY(err_str, ": Can't stat file");
535  goto arena_error;
536  }
537 
538  if(st.st_size > 0 &&
539  st.st_size < (off_t) (CHUNKS(sizeof(struct arena_header)) +
540  CHUNKS(sizeof(struct mapping_header))))
541  {
542  /* The file existed before we opened it and it's not big enough*/
543  /* EMEDIUMTYPE 124 "Wrong medium type" is the best I see. */
544  STRCPY(err_str, ": existing file not big enough");
545  err = EMEDIUMTYPE;
546  goto arena_error;
547  }
548 
549  if(st.st_size > 0)
550  {
551  ssize_t ret;
552  struct arena_header shm;
553 
554  /* We need the mapping size before we can map the file. */
555  ret = read(fd, &shm, sizeof(struct arena_header));
556  if(ret == -1)
557  {
558  STRCPY(err_str, ": read() failed");
559  err = errno;
560  goto arena_error;
561  }
562  if((size_t) ret < sizeof(struct arena_header))
563  {
564  STRCPY(err_str, ": Can't read file");
565  err = EMEDIUMTYPE;
566  goto arena_error;
567  }
568  if(shm.magic != ARENA_MAGIC)
569  {
570  STRCPY(err_str, ": Bad magic number in file");
571  err = EMEDIUMTYPE;
572  goto arena_error;
573  }
574 
575  if((shm.flags & SHM_WITH_SHM_OPEN) != (arena_flags & SHM_WITH_SHM_OPEN))
576  {
577 #ifdef WITH_SPEW
578  if(arena_flags & SHM_WITH_SHM_OPEN)
579  STRCPY(err_str, ": Arena file not using shm_open(), "
580  "but is requested");
581  else
582  STRCPY(err_str, ": Arena file is using shm_open(), "
583  "but is not requested");
584 #endif
585  err = EMEDIUMTYPE;
586  goto arena_error;
587  }
588  if(lseek(fd, 0, SEEK_SET) == -1)
589  {
590  STRCPY(err_str, ": lseek(fd, 0, SEEK_SET) failed");
591  err = errno;
592  goto arena_error;
593  }
594  map_length = shm.map_header.map_length * CHUNK;
595 
596  /********* Now we connect to the arena, mmap() *********/
597 
598  start = mmap(user_shm_address, map_length,
599  PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
600  if(start == MAP_FAILED)
601  {
602  STRCPY(err_str, ": mmap() failed");
603  err = errno;
604  goto arena_error;
605  }
606  if(user_shm_address && user_shm_address != start)
607  {
608  /* The user had env SHM_ADDRESS set and we failed
609  * to map to that address. */
610 #ifdef WITH_SPEW
611  sprintf(err_str, ": mmap()=%p failed "
612  "with SHM_ADDRESS=%p", start, user_shm_address);
613 #endif
614  err = EFAULT;
615  goto arena_error;
616  }
617 
618  rwlock = &(((struct arena_header *)start)->rwlock);
619  if((err = pthread_rwlock_rdlock(rwlock)))
620  {
621  rwlock = NULL; /* we don't have a read lock */
622  STRCPY(err_str, ": pthread_rwlock_rdlock() failed");
623  goto arena_error;
624  }
625  /* we have a read lock now */
626  }
627  else /* file size is now zero, we need to build it */
628  {
629  struct arena_header *header;
630  pthread_rwlockattr_t attr;
631  size_t file_length;
632 
633  if(min_size < 1) min_size = 1;
634 
635  /* file_length will start out smaller than map_length */
636  file_length = CHUNKS(sizeof(struct arena_header)) +
637  CHUNKS(sizeof(struct mapping_header));
638  map_length = PAGES(file_length +
639  CHUNKS(sizeof(struct seg_header)) +
640  CHUNKS(min_size) +
641  CHUNKS(sizeof(pthread_rwlock_t)) +
642  CHUNKS(16) + /* for the name string */
643  CHUNKS(sizeof(struct seg_footer)),
644  getpagesize()
645  );
646 
647  header = (struct arena_header *)
648  (start = mmap(user_shm_address, map_length,
649  PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0));
650 
651  if(start == MAP_FAILED)
652  {
653  STRCPY(err_str, ": mmap() failed");
654  err = errno;
655  goto arena_error;
656  }
657 
658  /* We must make the file have some length even if
659  * mmap() mapped to the wrong address so that we
660  * can see if header->magic was set without a
661  * memory fault in the error cleanup below. */
662  if(ftruncate(fd, file_length))
663  {
664 #ifdef WITH_SPEW
665  sprintf(err_str, ": ftruncate(fd=%d, length=%zu) failed",
666  fd, file_length);
667 #endif
668  if(user_shm_address)
669  {
670  /* We must unmap the memory now since the cleanup
671  * below assumes the memory is not zero length if
672  * start not equal to MAP_FAILED. */
673  munmap(start, map_length);
674  /* Keep start from being accessed at cleanup
675  * below. */
676  start = MAP_FAILED;
677  }
678  err = errno;
679  goto arena_error;
680  }
681 
682  if(user_shm_address && user_shm_address != start)
683  {
684  /* The user had env SHM_ADDRESS set and we failed
685  * to map to that address. */
686 #ifdef WITH_SPEW
687  sprintf(err_str, ": mmap()=%p failed "
688  "with SHM_ADDRESS=%p", start, user_shm_address);
689 #endif
690  err = EFAULT;
691  goto arena_error;
692  }
693 
694  if((err = pthread_rwlockattr_init(&attr)))
695  {
696  STRCPY(err_str, ": pthread_rwlockattr_init() failed");
697  goto arena_error;
698  }
699  if((err = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)))
700  {
701  STRCPY(err_str, ": pthread_rwlockattr_setpshared() failed");
702  goto arena_error;
703  }
704  if((err = pthread_rwlock_init(&header->rwlock, &attr)))
705  {
706  STRCPY(err_str, ": pthread_rwlock_init() failed");
707  goto arena_error;
708  }
709  if((err = pthread_rwlock_wrlock(&(header->rwlock))))
710  {
711  STRCPY(err_str, ": pthread_rwlock_rdlock() failed");
712  goto arena_error;
713  }
714  /* we have the arena write lock */
715  rwlock = &(header->rwlock);
716 
717  /* this is the flags that are saved in the arena header */
718  header->flags = (arena_flags & SHM_WITH_SHM_OPEN);
719 
720  /* the change_count in the shared memory starts at 1. */
721  header->change_count = 1;
722  header->name_count = 0;
723  header->num_mappings = 1;
724  header->free_mapnum = -1;
725  header->alloc_mapnum = -1;
726  header->free_offset = 0;
727  header->alloc_offset = 0;
728 
729  /* Setup the first mapping struct */
730  header->map_header.map_length = map_length/CHUNK;
731  header->map_header.length_used = file_length/CHUNK;
732 
733  { /* The second mapping struct starts life zero-ed. */
734  struct mapping_header *map_header;
735 
736  map_header = (struct mapping_header *)
737  (start + CHUNKS(sizeof(struct arena_header)));
738  map_header->map_length = 0;
739  map_header->length_used = 0;
740  }
741  }
742 
743  /* At this point if the magic number in the mapped file is set we
744  * are connecting to the arena, else we are creating it. */
745 
746  arena = (struct shm_arena *) malloc(sizeof(struct shm_arena));
747  if(!arena)
748  {
749  err = errno;
750  goto arena_error;
751  }
752 
753  /* Assuming the malloc() and pthread_rwlock_unlock() below do not
754  * fail this is a good time to spew what happened. */
755  SPEW(_DEBUG, "%s(): %s %sshared memory arena \"%s\"",
756  __func__,
757  (((struct arena_header *)start)->magic != ARENA_MAGIC)?
758  "created":"connected to",
759  arena_flags&SHM_WITH_SHM_OPEN?"shm_open type ":"",
760  path);
761 
762 
763  /**************************************************/
764  /* Initialize the local allocated arena structure */
765  /**************************************************/
766  arena->fd = fd;
767  arena->num_mappings =
768  ((struct arena_header *) start)->num_mappings;
769  arena->change_count = 0;
770  arena->user_shm_address = user_shm_address;
771 
772  arena->header = (struct arena_header *) start;
773 
774  if((err = pthread_key_create(&arena->rwlock_key,
775  rwlock_attr_destructor)))
776  {
777  STRCPY(err_str, ": pthread_key_create() failed");
778  goto arena_error;
779  }
780  if((err = pthread_mutex_init(&arena->mapping_mutex, NULL)))
781  {
782  STRCPY(err_str, ": pthread_mutex_init() failed");
783  goto arena_error;
784  }
785  if((err = pthread_mutex_init(&arena->rwlock_mutex, NULL)))
786  {
787  STRCPY(err_str, ": pthread_mutex_init() failed");
788  goto arena_error;
789  }
790 
791  arena->mapping = (struct shm_mapping *)
792  malloc(arena->num_mappings*sizeof(struct shm_mapping));
793  if(!(arena->mapping))
794  {
795  err = errno;
796  goto arena_error;
797  }
798 
799  arena->mapping[0].start = start;
800  arena->mapping[0].map_length = map_length/CHUNK;
801 
802  SPEW(_INFO, "mapped %p -> %p %zu bytes",
803  arena->mapping[0].start,
804  (void*)(((uintptr_t)arena->mapping[0].start)+
805  arena->mapping[0].map_length*CHUNK),
806  arena->mapping[0].map_length*CHUNK);
807 
808  {
809  int i;
810  off_t total_len;
811  struct mapping_header *header;
812 
813  for(i=1; i<arena->num_mappings; i++)
814  arena->mapping[i].start = MAP_FAILED;
815 
816  header = (struct mapping_header *)
817  (((uint8_t *)start) + CHUNKS(sizeof(struct arena_header)));
818  total_len = map_length;
819 
820  /* connect to all the mappings after the first */
821  for(i=1; i<arena->num_mappings; i++)
822  {
823  size_t len;
824 
825  len = header->map_length * CHUNK;
826  if(user_shm_address)
827  user_shm_address =
828  (void*)(((uintptr_t)user_shm_address +
829  arena->mapping[i-1].map_length*CHUNK));
830 
831  arena->mapping[i].start = mmap(user_shm_address, len,
832  PROT_READ|PROT_WRITE, MAP_SHARED, fd, total_len);
833  if(arena->mapping[i].start == MAP_FAILED)
834  {
835  STRCPY(err_str, ": mmap() failed");
836  err = errno;
837  goto arena_error;
838  }
839  if(user_shm_address &&
840  user_shm_address != arena->mapping[i].start)
841  {
842  STRCPY(err_str, ": mmap() failed with SHM_ADDRESS set");
843  err = EFAULT;
844  goto arena_error;
845  }
846 
847  SPEW(_INFO, "mapped %p -> %p %zu bytes",
848  arena->mapping[i].start,
849  (void*)(((uintptr_t)arena->mapping[i].start)+len),
850  len);
851 
852  arena->mapping[i].map_length = header->map_length;
853  total_len += len;
854 
855  header = (struct mapping_header *) arena->mapping[i].start;
856  }
857  }
858 
859 
860 
861  if(((struct arena_header *)start)->magic != ARENA_MAGIC)
862  {
863  /* We created the arena file so we mark it with magic */
864  ((struct arena_header *)start)->magic = ARENA_MAGIC;
865  if((err = pthread_rwlock_unlock(rwlock)))
866  {
867  ((struct arena_header *)start)->magic = 0;
868  STRCPY(err_str, ": pthread_rwlock_unlock() failed");
869  goto arena_error;
870  }
871  else
872  arena->change_count =
873  ((struct arena_header *)start)->change_count;
874  }
875  else /* We didn't create the arena file */
876  {
877  if((err = pthread_rwlock_unlock(rwlock)))
878  {
879  /* don't unset arena magic number because we didn't create the
880  * arena */
881  STRCPY(err_str, ": pthread_rwlock_unlock() failed");
882  goto arena_error;
883  }
884  arena->change_count =
885  ((struct arena_header *)start)->change_count;
886  }
887 
888  /* Set the default arena if there is not one or we are told to with
889  * flags. */
890  if(_shm_default_arena == NULL || arena_flags & SHM_ARENA_DEFAULT)
891  {
892  _shm_default_arena = arena;
893  SPEW(_DEBUG, "Made this new arena object the default "
894  "arena object");
895  }
896 
897  /* Make this code thread-safe at a fork call */
898  if(!atfork_set)
899  {
900  if((err = pthread_atfork(prefork,
901  parent_postfork, child_postfork)))
902  {
903  STRCPY(err_str, ": pthread_atfork() failed");
904  goto arena_error;
905  }
906  atfork_set = 1;
907  }
908 
909  num_arenas++;
910  arenas = (struct shm_arena **)
911  realloc(arenas, sizeof(struct shm_arena *)*num_arenas);
912  if(!arenas)
913  {
914  err = errno;
915  num_arenas = 0;
916  STRCPY(err_str, ": realloc() failed");
917  goto arena_error;
918  }
919  arenas[num_arenas-1] = arena;
920 
921  if(have_flock && flock(fd, LOCK_UN))
922  {
923  err = errno;
924  STRCPY(err_str, ": flock(fd, LOCK_UN) failed");
925  goto arena_error;
926  }
927 
928  if(!(arena_flags & HAVE_CREATE_ARENA_MUTEX))
929  pthread_mutex_unlock(&_shm_create_arena_mutex);
930 
931  if(apath)
932  {
933  free(apath);
934  apath = NULL;
935  }
936 
937  return arena;
938 
939 
940  arena_error:
941 
942  errno = err;
943 
944  SPEW_SYS(_WARN, "%s() failed%s: failed "
945  "to attach to shared memory file \"%s\"",
946  __func__, err_str, path);
947 
948  if(start != MAP_FAILED &&
949  ((struct arena_header *)start)->magic != ARENA_MAGIC)
950  {
951  /* We failed to create the arena file so we'll remove it now. */
952  if(arena_flags & SHM_WITH_SHM_OPEN)
953  shm_unlink(path);
954  else
955  unlink(path);
956  }
957 
958  if(arena && arena->mapping)
959  {
960  while(arena->num_mappings > 0)
961  {
962  if(arena->mapping[arena->num_mappings-1].start != MAP_FAILED)
963  {
964  struct mapping_header *header;
965  header = (struct mapping_header *)
966  arena->mapping[arena->num_mappings-1].start;
967 
968  munmap(arena->mapping[arena->num_mappings-1].start,
969  header->map_length);
970  }
971 
972  (arena->num_mappings)--;
973  }
974 
975  free(arena->mapping);
976  }
977  else if(start != MAP_FAILED)
978  munmap(start, map_length);
979 
980  if(rwlock)
981  pthread_rwlock_unlock(rwlock);
982 
983  /* the top (first) arena mapping */
984  if(start != MAP_FAILED)
985  munmap(start, map_length);
986 
987  if(have_flock && fd != -1)
988  flock(fd, LOCK_UN);
989 
990  if(fd != -1) close(fd);
991 
992  if(apath) free(apath);
993  if(arena)
994  {
995  free(arena);
996  arena = NULL;
997  }
998 
999  if(!(arena_flags & HAVE_CREATE_ARENA_MUTEX))
1000  pthread_mutex_unlock(&_shm_create_arena_mutex);
1001 
1002  return arena;
1003 }
1004 
1017 {
1018  int ret = 0;
1019  int err = 0;
1020  void *ptr;
1021 
1022  SPEW(_INFO, "%s(arena=%p)", __func__, arena);
1023 
1024  arena = get_arena(arena, 1, &err IF_SPEW(, __func__));
1025 
1026  if(!arena)
1027  {
1028  errno = err;
1029  return -1;
1030  }
1031 
1032  pthread_mutex_lock(&_shm_create_arena_mutex);
1033 
1039  /* We can clean it up for this thread now. */
1040  if((ptr = pthread_getspecific(arena->rwlock_key)))
1041  {
1042  free(ptr);
1043  /* This will keep the memory from being freed twice. */
1044  pthread_setspecific(arena->rwlock_key, NULL);
1045  }
1046 
1047  while(arena->num_mappings)
1048  {
1049  arena->num_mappings--;
1050  if(munmap(arena->mapping[arena->num_mappings].start,
1051  arena->mapping[arena->num_mappings].map_length*CHUNK))
1052  {
1053  ret = -1;
1054  SPEW_SYS(_WARN, "%s() failed: munmap() mapping number="
1055  MAPNUM_FORMAT " failed",
1056  __func__, arena->num_mappings);
1057  }
1058  }
1059 
1060  if(arena->mapping)
1061  {
1062  free(arena->mapping);
1063  /* We set the memory incase things go to hell they will not get
1064  * to far. Setting it to a bad value will make it crash faster
1065  * in most cases. */
1066  arena->mapping = NULL;
1067  }
1068 
1069  if(arena->fd != -1)
1070  {
1071  close(arena->fd);
1072  arena->fd = -1;
1073  }
1074 
1075  num_arenas--;
1076  if(num_arenas)
1077  {
1078  arenas = (struct shm_arena **)
1079  realloc(arenas, sizeof(struct shm_arena *)*num_arenas);
1080  if(!arenas)
1081  {
1082  num_arenas = 0;
1083  /* realloc() failed so we are screwed, return error anyway. */
1084  ret = -1;
1085  }
1086  }
1087  else
1088  {
1089  free(arenas);
1090  arenas = NULL;
1091  }
1092 
1093  if(arena != _shm_default_arena)
1094  {
1095  pthread_mutex_unlock(&_shm_create_arena_mutex);
1096  free(arena);
1097  arena = NULL;
1098  return ret;
1099  }
1100 
1101  _shm_default_arena = NULL;
1102  pthread_mutex_unlock(&_shm_create_arena_mutex);
1103 
1104  free(arena);
1105  arena = NULL;
1106 
1107  return ret;
1108 }
1109 
1126 int shm_arena_destroy(const char *path, int flags)
1127 {
1128  char *apath = NULL; /* allocated path */
1129  int ret = -1;
1130  int fd = -1;
1131  struct arena_header a_hdr;
1132 
1133  SPEW(_INFO, "%s(\"%s\", flags=%d)", __func__, path, flags);
1134 
1135  if((!(flags & SHM_USE_GIVEN_PATH)) &&
1136  arena_path(path, &flags, &apath))
1137  goto finish0; /* error */
1138 
1139  if(flags & SHM_USE_GIVEN_PATH && (path == NULL || !path[0]))
1140  {
1141  errno = ENOENT; /* "No such file or directory" */
1142  SPEW(_WARN, "Bad path \"%s\"\n", path);
1143  goto finish0; /* error */
1144  }
1145 
1146  if(apath) path = apath;
1147 
1148  if(flags & SHM_WITH_SHM_OPEN)
1149  fd = shm_open(path, O_RDONLY, SHM_RW_MODE);
1150  else
1151  fd = open(path, O_RDONLY);
1152 
1153  if(fd == -1)
1154  {
1155  SPEW_SYS(_WARN, "%s() failed to %sopen \"%s\"",
1156  __func__,
1157  (flags & SHM_WITH_SHM_OPEN)?"SHM_":"", path);
1158  goto finish0;
1159  }
1160  if(read(fd, &a_hdr, sizeof(a_hdr)) != sizeof(a_hdr))
1161  {
1162  SPEW_SYS(_WARN, "%s() failed to read \"%s\"",
1163  __func__, path);
1164  goto finish1;
1165  }
1166 
1167  if(a_hdr.flags & SHM_WITH_SHM_OPEN)
1168  {
1169  /* It's likely that shm_unlink() and unlink() are the same on
1170  * Linux systems, but in keeping with POSIX bullshit we use
1171  * shm_unlink(): */
1172  ret = shm_unlink(path);
1173  }
1174  else
1175  ret = unlink(path);
1176 
1177 
1178  finish1:
1179 
1180  if(fd != -1)
1181  close(fd);
1182 
1183  finish0:
1184 
1185 #ifdef WITH_SPEW
1186  if(ret == 0)
1187  SPEW(_INFO, "Removed %sarena file \"%s\"",
1188  (flags & SHM_WITH_SHM_OPEN)?"/dev/shm ":"", path);
1189  else
1190  SPEW(_INFO, "Failed to remove %sarena file \"%s\"",
1191  (flags & SHM_WITH_SHM_OPEN)?"/dev/shm ":"", path);
1192 #endif
1193 
1194  if(apath)
1195  free(apath);
1196 
1197  return ret;
1198 }
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
#define SHM_RW_MODE
a mode with all the read and write bits enabled
Definition: shm_arena.h:105
shm_arena_t shm_arena_create(const char *path, int flags, mode_t mode, size_t min_size)
create a shared memory arena object
Definition: arena.c:387
offset_t length_used
Definition: arena.h:352
pthread_key_t rwlock_key
Definition: arena.h:479
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
void * user_shm_address
Definition: arena.h:484
#define SHM_DEFAULT_ARENA_DIR
the default arena directory
Definition: shm_arena.h:86
int rdlock_count
Definition: arena.h:424
struct mapping_header map_header
Definition: arena.h:374
offset_t map_length
Definition: arena.h:410
mapnum_t free_mapnum
Definition: arena.h:390
int shm_arena_destroy(const char *path, int flags)
destroy a shared memory arena file
Definition: arena.c:1126
int wrlock_count
Definition: arena.h:426
uint32_t change_count
Definition: arena.h:383
uint32_t magic
Definition: arena.h:364
#define SHM_WITH_SHM_OPEN
shm_arena_create() flag to use shm_open()
Definition: shm_arena.h:123
#define SHM_ARENA_DEFAULT
shm_arena_create() flag for insuring this is the default arena
Definition: shm_arena.h:144
#define SHM_DEFAULT_ARENA_FILE
the default arena file
Definition: shm_arena.h:97
#define SHM_USE_GIVEN_PATH
shm_arena_create() flag interpting arena file path
Definition: shm_arena.h:138
offset_t alloc_offset
Definition: arena.h:396
uint8_t * start
Definition: arena.h:405
int fd
Definition: arena.h:436
#define SHM_ARENA_HAVE_FLOCK
shm_arena_create() flag for advisory file lock
Definition: shm_arena.h:130
int shm_arena_delete(shm_arena_t arena)
delete a local shared memory arena object
Definition: arena.c:1016
uint32_t name_count
Definition: arena.h:377

Shared Memory Arena version RC-0.0.25