arena_lock.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 
42 #define HAVE_CREATE_ARENA_MUTEX (01 << 31)
43 
44 
46 extern struct shm_arena *_shm_default_arena;
47 extern pthread_mutex_t _shm_create_arena_mutex;
48 
49 
50 static inline
51 pthread_rwlock_t *arena_rwlock(const struct shm_arena *a)
52 {
53  return (&(a->header->rwlock));
54 }
55 
56 
57 
58 static inline struct shm_arena
59 *get_arena_min_size(struct shm_arena *a,
60  int rwlock_type, /* 1 for read, 2 for write, and 0
61  * for unlock */
62  int *err,
63  IF_SPEW(const char *func,) size_t min_size)
64 /* This is used to get the default arena in a thread-safe way. When
65  * it returns successfully you will have the intra-process arena mutex
66  * lock, else if it fails you will not.
67  * TODO: This is wrong!!! */
68 {
69  if(!a)
70  {
71  pthread_mutex_lock(&_shm_create_arena_mutex);
72  if(!_shm_default_arena)
73  {
74  if(rwlock_type)
75  {
76  int flags =
77  O_RDWR | SHM_ARENA_DEFAULT |
78  HAVE_CREATE_ARENA_MUTEX;
79 
80  if(rwlock_type == 2)
81  flags |= O_CREAT;
82 
83  shm_arena_create(NULL, flags, SHM_RW_MODE, min_size);
84  if(!_shm_default_arena)
85  {
86  /* It failed */
87  *err = errno;
88  pthread_mutex_unlock(&_shm_create_arena_mutex);
89  return SPEW_SYS_RET(NULL, _WARN,
90  "%s() failed", func);
91  }
92  }
93  else /* rwlock_type == 0 -- unlocking */
94  {
95  /* It failed */
96  pthread_mutex_unlock(&_shm_create_arena_mutex);
97  return SPEW_SYS_RET(NULL, _WARN,
98  "%s() failed: the arena object "
99  "has not been created yet", func);
100  }
101  }
102  a = _shm_default_arena;
103  pthread_mutex_unlock(&_shm_create_arena_mutex);
104  }
105 
106  return a;
107 }
108 
109 static inline struct shm_arena
110 *get_arena(struct shm_arena *a,
111  int rwlock_type, /* 1 for read, 2 for write, and 0
112  * for unlock */
113  int *err
114  IF_SPEW(, const char *func))
115 {
116  return get_arena_min_size(a, rwlock_type, err IF_SPEW(, func), 0);
117 }
118 
119 static inline struct shm_arena
120 *get_arena_min_size_and_autolock(struct shm_arena *a,
121  int rwlock_type, /* 1 for read, 2 for write, and 0
122  * for unlock */
123  int *err, /* phread_rwlock_*() error number */
124  IF_SPEW(const char *func,)
125  size_t min_size)
126 /* arena may be passed in as NULL and this will check and get the
127  * arena. If rwlock_type is 1 the default arena object will be
128  * created only if the arena file exists, else if wrlock_type is 2 the
129  * default arena object will be created and so will the arena file if
130  * it does not exist. If rwlock_type is 0 the default arena object
131  * will not be created, so it must exist already. */
132 {
133  struct rwlock_attr *rwlock;
134 
135  ASSERT(rwlock_type == 0 || rwlock_type == 1 || rwlock_type == 2);
136 
137  a = get_arena_min_size(a, rwlock_type, err IF_SPEW(, func), min_size);
138  if(!a) return a;
139 
140  rwlock = get_rwlock_attr(a);
141 
142  if(!rwlock)
143  return SPEW_RET(NULL, _WARN, "%s() failed: %s() failed",
144  func, __func__);
145 
146  ASSERT(rwlock->rdlock_count > -1 && rwlock->wrlock_count > -1);
147 
148  if(rwlock_type == 2 && rwlock->rdlock_count > 0)
149  {
150  *err = EINVAL; /* "Invalid argument" this errno sucks */
151  return
152  SPEW_SYS_RET(NULL, _WARN,
153  "%s() failed: you have an arena read-lock"
154  " but need an arena write-lock", func);
155  }
156 
157  if(rwlock_type == 0)
158  {
159  *err = 0;
160  if(rwlock->rdlock_count > 0)
161  {
162  rwlock->rdlock_count--;
163  if(rwlock->rdlock_count == 0)
164  *err = pthread_rwlock_unlock(arena_rwlock(a));
165  }
166  else if(rwlock->wrlock_count > 0)
167  {
168  rwlock->wrlock_count--;
169  if(rwlock->wrlock_count == 0)
170  *err = pthread_rwlock_unlock(arena_rwlock(a));
171  }
172  if(!(*err))
173  return a;
174  SPEW_SYS(_WARN,
175  "%s() failed: pthread_rwlock_unlock() failed",
176  func);
177  return NULL;
178  }
179 
180  if(rwlock->wrlock_count > 0)
181  {
182  rwlock->wrlock_count++;
183  return a;
184  }
185  if(rwlock->rdlock_count > 0)
186  {
187  rwlock->rdlock_count++;
188  return a;
189  }
190 
191  if(rwlock_type == 1)
192  {
193  *err = pthread_rwlock_rdlock(arena_rwlock(a));
194  if(!(*err))
195  {
196  rwlock->rdlock_count++;
197  return a;
198  }
199  SPEW_SYS(_WARN,
200  "%s() failed: pthread_rwlock_rdlock() failed",
201  func);
202  return NULL;
203  }
204 
205  /* rwlock_type == 2 */
206 
207  *err = pthread_rwlock_wrlock(arena_rwlock(a));
208  if(!(*err))
209  {
210  rwlock->wrlock_count++;
211  return a;
212  }
213  SPEW_SYS(_WARN,
214  "%s() failed: pthread_rwlock_wrlock() failed",
215  func);
216  return NULL;
217 }
218 
219 static inline struct shm_arena
220 *get_arena_and_autolock(struct shm_arena *a,
221  int rwlock_type, /* 1 for read, 2 for write, and 0
222  * for unlock */
223  int *err /* phread_rwlock_*() error number */
224  IF_SPEW(, const char *func))
225 {
226  return get_arena_min_size_and_autolock(a, rwlock_type,
227  err IF_SPEW(, func),
228  0);
229 }
230 
231 static inline int
232 arena_autounlock(struct shm_arena *a
233  IF_SPEW(, const char *func))
234 /* We must really have an arena object before this call, so we cannot
235  * use this in shm_arena_unlock() and shm_unlock() since arena may be
236  * NULL for those calls. You must have the intra-process arena mutex
237  * before this call. */
238 {
239  int err = 0;
240  struct rwlock_attr *rwlock;
241 
242  ASSERT(a);
243 
244  rwlock = get_rwlock_attr(a);
245 
246  if(!rwlock)
247  return SPEW_RET(errno, _WARN, "%s() failed: %s() failed",
248  func, __func__);
249 
250  ASSERT(!(rwlock->rdlock_count > 0 && rwlock->wrlock_count > 0));
251  ASSERT(rwlock->rdlock_count > -1 && rwlock->wrlock_count > -1);
252 
253  if(rwlock->rdlock_count > 0)
254  {
255  rwlock->rdlock_count--;
256  if(rwlock->rdlock_count == 0)
257  err = pthread_rwlock_unlock(arena_rwlock(a));
258  }
259  else if(rwlock->wrlock_count > 0)
260  {
261  rwlock->wrlock_count--;
262  if(rwlock->wrlock_count == 0)
263  err = pthread_rwlock_unlock(arena_rwlock(a));
264  }
265 
266 #ifdef WITH_SPEW
267  if(err)
268  SPEW_SYS(_WARN,
269  "%s() failed: pthread_rwlock_unlock() failed",
270  func);
271 #endif
272 
273  return err;
274 }
struct arena_header * header
Definition: arena.h:446
#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
pthread_rwlock_t rwlock
Definition: arena.h:371
int rdlock_count
Definition: arena.h:424
int wrlock_count
Definition: arena.h:426
#define SHM_ARENA_DEFAULT
shm_arena_create() flag for insuring this is the default arena
Definition: shm_arena.h:144

Shared Memory Arena version RC-0.0.25