** Warning: Cannot open xref database.
1 /*
2 Copyright (C) 2003 Paul Davis
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: shm.c,v 1.12 2003/11/07 05:45:03 joq Exp $
19 */
20
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <signal.h>
26 #include <limits.h>
27 #include <errno.h>
28 #include <sys/mman.h>
29 #include <sys/types.h>
30 #include <dirent.h>
31 #include <sys/ipc.h>
32 #include <sys/shm.h>
33 #include <config.h>
34
35 #include <jack/shm.h>
36 #include <jack/internal.h>
37
38 static jack_shm_registry_t* jack_shm_registry;
39
40 static void
41 jack_shm_lock_registry ()
42 {
43 /* XXX magic with semaphores here */
44 }
45
46 static void
47 jack_shm_unlock_registry ()
48 {
49 /* XXX magic with semaphores here */
50 }
51
52 jack_shm_registry_t *
53 jack_get_free_shm_info ()
54 {
55 jack_shm_registry_t* si = NULL;
56 int i;
57
58 jack_shm_lock_registry ();
59
60 for (i = 0; i < MAX_SHM_ID; ++i) {
61 if (jack_shm_registry[i].size == 0) {
62 break;
63 }
64 }
65
66 if (i < MAX_SHM_ID) {
67 si = &jack_shm_registry[i];
68 }
69
70 jack_shm_unlock_registry ();
71
72 return si;
73 }
74
75 void
76 jack_release_shm_info (jack_shm_registry_index_t index)
77 {
78 if (jack_shm_registry[index].allocator == getpid()) {
79 jack_shm_lock_registry ();
80 jack_shm_registry[index].size = 0;
81 jack_shm_registry[index].allocator = 0;
82 jack_shm_unlock_registry ();
83 }
84 }
85
86 void
87 jack_cleanup_shm ()
88 {
89 int i;
90 int destroy;
91 jack_shm_info_t copy;
92
93 jack_initialize_shm ();
94 jack_shm_lock_registry ();
95
96 for (i = 0; i < MAX_SHM_ID; i++) {
97 jack_shm_registry_t* r;
98
99 r = &jack_shm_registry[i];
100 copy.index = r->index;
101 destroy = FALSE;
102
103 if (r->allocator == getpid()) {
104
105 /* allocated by this process, so unattach
106 and destroy.
107 */
108
109 jack_release_shm (©);
110 destroy = TRUE;
111
112 } else {
113
114 if (kill (r->allocator, 0)) {
115 if (errno == ESRCH) {
116
117 /* allocator no longer exists, so destroy */
118
119 destroy = TRUE;
120 }
121 }
122 }
123
124 if (destroy) {
125
126 jack_destroy_shm (©);
127
128 r->size = 0;
129 r->allocator = 0;
130 }
131 }
132
133 jack_shm_unlock_registry ();
134 }
135
136 #if USE_POSIX_SHM
137
138 int
139 jack_initialize_shm ()
140 {
141 int shm_fd;
142 jack_shmsize_t size;
143 int new_registry = FALSE;
144 int ret = -1;
145
146 if (jack_shm_registry != NULL) {
147 return 0;
148 }
149
150 /* grab a chunk of memory to store shm ids in. this is
151 to allow clean up of all segments whenever JACK
152 starts (or stops).
153 */
154
155 size = sizeof (jack_shm_registry_t) * MAX_SHM_ID;
156
157 jack_shm_lock_registry ();
158
159 /* try without O_CREAT to see if it already exists */
160
161 if ((shm_fd = shm_open ("/jack-shm-registry", O_RDWR, 0666)) < 0) {
162
163 if (errno == ENOENT) {
164
165 /* it doesn't exist, so create it */
166
167 if ((shm_fd = shm_open ("/jack-shm-registry", O_RDWR|O_CREAT, 0666)) < 0) {
168 jack_error ("cannot create shm registry segment (%s)",
169 strerror (errno));
170 goto out;
171 }
172 new_registry = TRUE;
173
174 } else {
175
176 jack_error ("cannot open existing shm registry segment (%s)",
177 strerror (errno));
178 goto out;
179 }
180 }
181
182 if (ftruncate (shm_fd, size) < 0) {
183 jack_error ("cannot set size of engine shm registry "
184 "(%s)", strerror (errno));
185 goto out;
186 }
187
188 if ((jack_shm_registry = mmap (0, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
189 jack_error ("cannot mmap shm registry segment (%s)",
190 strerror (errno));
191 goto out;
192 }
193
194 if (new_registry) {
195 int i;
196
197 memset (jack_shm_registry, 0, size);
198 for (i = 0; i < MAX_SHM_ID; ++i) {
199 jack_shm_registry[i].index = i;
200 }
201 fprintf (stderr, "JACK compiled with POSIX SHM support\n");
202 }
203
204 ret = 0;
205
206 out:
207 close (shm_fd);
208 jack_shm_unlock_registry ();
209 return ret;
210 }
211
212 void
213 jack_destroy_shm (jack_shm_info_t* si)
214 {
215 shm_unlink (jack_shm_registry[si->index].id);
216 jack_release_shm_info (si->index);
217 }
218
219 void
220 jack_release_shm (jack_shm_info_t* si)
221 {
222 if (si->attached_at != MAP_FAILED) {
223 munmap (si->attached_at, jack_shm_registry[si->index].size);
224 }
225 }
226
227 int
228 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
229 {
230 jack_shm_registry_t* registry;
231 int shm_fd;
232
233 if ((registry = jack_get_free_shm_info ()) == NULL) {
234 return -1;
235 }
236
237 if ((shm_fd = shm_open (shm_name, O_RDWR|O_CREAT, 0666)) < 0) {
238 jack_error ("cannot create shm segment %s (%s)", shm_name,
239 strerror (errno));
240 return -1;
241 }
242
243 if (ftruncate (shm_fd, size) < 0) {
244 jack_error ("cannot set size of engine shm registry "
245 "(%s)", strerror (errno));
246 return -1;
247 }
248
249 close (shm_fd);
250
251 registry->size = size;
252 snprintf (registry->id, sizeof (registry->id), "%s", shm_name);
253 registry->allocator = getpid();
254
255 si->index = registry->index;
256 si->attached_at = MAP_FAILED; /* segment not attached */
257
258 return 0;
259 }
260
261 int
262 jack_attach_shm (jack_shm_info_t* si)
263 {
264 int shm_fd;
265 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
266
267 if ((shm_fd = shm_open (registry->id,
268 O_RDWR, 0666)) < 0) {
269 jack_error ("cannot open shm segment %s (%s)", registry->id,
270 strerror (errno));
271 return -1;
272 }
273
274 if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
275 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
276 jack_error ("cannot mmap shm segment %s (%s)",
277 registry->id,
278 strerror (errno));
279 close (shm_fd);
280 return -1;
281 }
282
283 close (shm_fd);
284
285 return 0;
286 }
287
288 int
289 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
290 {
291 int shm_fd;
292 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
293
294 if ((shm_fd = shm_open (registry->id, O_RDWR, 0666)) < 0) {
295 jack_error ("cannot create shm segment %s (%s)", registry->id,
296 strerror (errno));
297 return -1;
298 }
299
300 munmap (si->attached_at, registry->size);
301
302 if (ftruncate (shm_fd, size) < 0) {
303 jack_error ("cannot set size of shm segment %s "
304 "(%s)", registry->id, strerror (errno));
305 return -1;
306 }
307
308 if ((si->attached_at = mmap (0, size, PROT_READ|PROT_WRITE,
309 MAP_SHARED, shm_fd, 0))
310 == MAP_FAILED) {
311 jack_error ("cannot mmap shm segment %s (%s)", registry->id,
312 strerror (errno));
313 close (shm_fd);
314 return -1;
315 }
316
317 close (shm_fd);
318 return 0;
319 }
320
321 #else /* USE_POSIX_SHM */
322
323 #define JACK_SHM_REGISTRY_KEY 0x282929
324
325 int
326 jack_initialize_shm ()
327 {
328 int shmflags;
329 int shmid;
330 key_t key;
331 jack_shmsize_t size;
332 int new_registry = FALSE;
333 int ret = -1;
334
335 if (jack_shm_registry != NULL) {
336 return 0;
337 }
338
339 /* grab a chunk of memory to store shm ids in. this is
340 to allow our parent to clean up all such ids when
341 if we exit. otherwise, they can get lost in crash
342 or debugger driven exits.
343 */
344
345 shmflags = 0666;
346 key = JACK_SHM_REGISTRY_KEY;
347 size = sizeof (jack_shm_registry_t) * MAX_SHM_ID;
348
349 jack_shm_lock_registry ();
350
351 /* try without IPC_CREAT to check if it already exists */
352
353 if ((shmid = shmget (key, size, shmflags)) < 0) {
354 if (errno == ENOENT) {
355 if ((shmid = shmget (key, size, shmflags|IPC_CREAT)) < 0) {
356 jack_error ("cannot create shm registry segment (%s)",
357 strerror (errno));
358 goto out;
359 }
360
361 new_registry = TRUE;
362
363 } else {
364
365 jack_error ("cannot use existing shm registry segment (%s)",
366 strerror (errno));
367 goto out;
368 }
369 }
370
371 if ((jack_shm_registry = shmat (shmid, 0, 0)) < 0) {
372 jack_error ("cannot attach shm registry segment (%s)",
373 strerror (errno));
374 goto out;
375 }
376
377 if (new_registry) {
378 int i;
379 memset (jack_shm_registry, 0, size);
380 for (i = 0; i < MAX_SHM_ID; ++i) {
381 jack_shm_registry[i].index = i;
382 }
383 fprintf (stderr, "JACK compiled with System V SHM support\n");
384 }
385
386 ret = 0;
387
388 out:
389 jack_shm_unlock_registry ();
390 return ret;
391 }
392
393 void
394 jack_destroy_shm (jack_shm_info_t* si)
395 {
396 shmctl (jack_shm_registry[si->index].id, IPC_RMID, NULL);
397 jack_release_shm_info (si->index);
398 }
399
400 void
401 jack_release_shm (jack_shm_info_t* si)
402 {
403 if (si->attached_at != MAP_FAILED) {
404 shmdt (si->attached_at);
405 }
406 }
407
408 int
409 jack_shmalloc (const char* name_not_used, jack_shmsize_t size, jack_shm_info_t* si)
410 {
411 int shmflags;
412 int shmid;
413 jack_shm_registry_t* registry;
414
415 if ((registry = jack_get_free_shm_info ()) == NULL) {
416 return -1;
417 }
418
419 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
420
421 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) < 0) {
422 jack_error ("cannot create shm segment %s (%s)",
423 name_not_used, strerror (errno));
424 return -1;
425 }
426
427 registry->size = size;
428 registry->id = shmid;
429 registry->allocator = getpid();
430
431 si->index = registry->index;
432 si->attached_at = MAP_FAILED; /* segment not attached */
433
434 return 0;
435 }
436
437 int
438 jack_attach_shm (jack_shm_info_t* si)
439 {
440 if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
441 jack_error ("cannot attach shm segment (%s)",
442 strerror (errno));
443 jack_release_shm_info (si->index);
444 return -1;
445 }
446 return 0;
447 }
448
449 int
450 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
451 {
452 /* There is no way to resize a System V shm segment. So, we
453 * delete it and allocate a new one. This is tricky, because
454 * the old segment will not disappear until all the clients
455 * have released it. We can only do what we can from here.
456 */
457
458 jack_release_shm (si);
459 jack_destroy_shm (si);
460
461 if (jack_shmalloc ("not used", size, si)) {
462 return -1;
463 }
464
465 return jack_attach_shm (si);
466 }
467
468 #endif /* !USE_POSIX_SHM */
469
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.