check for alsa-lib 1.0.18, now required
[jack.git] / libjack / shm.c
blobe7a631bb3890ba6353a67a7838041bc3f8db0a64
1 /* This module provides a set of abstract shared memory interfaces
2 * with support using both System V and POSIX shared memory
3 * implementations. The code is divided into three sections:
5 * - common (interface-independent) code
6 * - POSIX implementation
7 * - System V implementation
9 * The implementation used is determined by whether USE_POSIX_SHM was
10 * set in the ./configure step.
14 * Copyright (C) 2003 Paul Davis
15 * Copyright (C) 2004 Jack O'Quin
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 #include <config.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <limits.h>
40 #include <errno.h>
41 #include <dirent.h>
42 #include <sys/mman.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sysdeps/ipc.h>
46 #include <sys/shm.h>
47 #include <sys/sem.h>
48 #include <sysdeps/ipc.h>
50 #include <jack/shm.h>
51 #include <jack/internal.h>
52 #include <jack/version.h>
54 #ifdef USE_POSIX_SHM
55 static jack_shmtype_t jack_shmtype = shm_POSIX;
56 #else
57 static jack_shmtype_t jack_shmtype = shm_SYSV;
58 #endif
60 /* interface-dependent forward declarations */
61 static int jack_access_registry (jack_shm_info_t *ri);
62 static int jack_create_registry (jack_shm_info_t *ri);
63 static void jack_remove_shm (jack_shm_id_t *id);
65 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
66 * common interface-independent section
67 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
69 /* The JACK SHM registry is a chunk of memory for keeping track of the
70 * shared memory used by each active JACK server. This allows the
71 * server to clean up shared memory when it exits. To avoid memory
72 * leakage due to kill -9, crashes or debugger-driven exits, this
73 * cleanup is also done when a new instance of that server starts.
76 /* per-process global data for the SHM interfaces */
77 static jack_shm_id_t registry_id; /* SHM id for the registry */
78 static jack_shm_info_t registry_info = { /* SHM info for the registry */
79 .index = JACK_SHM_NULL_INDEX,
80 .attached_at = MAP_FAILED
83 /* pointers to registry header and array */
84 static jack_shm_header_t *jack_shm_header = NULL;
85 static jack_shm_registry_t *jack_shm_registry = NULL;
86 static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
88 /* jack_shm_lock_registry() serializes updates to the shared memory
89 * segment JACK uses to keep track of the SHM segements allocated to
90 * all its processes, including multiple servers.
92 * This is not a high-contention lock, but it does need to work across
93 * multiple processes. High transaction rates and realtime safety are
94 * not required. Any solution needs to at least be portable to POSIX
95 * and POSIX-like systems.
97 * We must be particularly careful to ensure that the lock be released
98 * if the owning process terminates abnormally. Otherwise, a segfault
99 * or kill -9 at the wrong moment could prevent JACK from ever running
100 * again on that machine until after a reboot.
103 #ifndef USE_POSIX_SHM
104 #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
105 #endif
107 static int semid = -1;
109 /* all semaphore errors are fatal -- issue message, but do not return */
110 static void
111 semaphore_error (char *msg)
113 jack_error ("Fatal JACK semaphore error: %s (%s)",
114 msg, strerror (errno));
115 abort ();
118 static void
119 semaphore_init ()
121 key_t semkey = JACK_SEMAPHORE_KEY;
122 struct sembuf sbuf;
123 int create_flags = IPC_CREAT | IPC_EXCL
124 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
126 /* Get semaphore ID associated with this key. */
127 if ((semid = semget(semkey, 0, 0)) == -1) {
129 /* Semaphore does not exist - Create. */
130 if ((semid = semget(semkey, 1, create_flags)) != -1) {
132 /* Initialize the semaphore, allow one owner. */
133 sbuf.sem_num = 0;
134 sbuf.sem_op = 1;
135 sbuf.sem_flg = 0;
136 if (semop(semid, &sbuf, 1) == -1) {
137 semaphore_error ("semop");
140 } else if (errno == EEXIST) {
141 if ((semid = semget(semkey, 0, 0)) == -1) {
142 semaphore_error ("semget");
145 } else {
146 semaphore_error ("semget creation");
151 static inline void
152 semaphore_add (int value)
154 struct sembuf sbuf;
156 sbuf.sem_num = 0;
157 sbuf.sem_op = value;
158 sbuf.sem_flg = SEM_UNDO;
159 if (semop(semid, &sbuf, 1) == -1) {
160 semaphore_error ("semop");
164 static void
165 jack_shm_lock_registry (void)
167 if (semid == -1)
168 semaphore_init ();
170 semaphore_add (-1);
173 static void
174 jack_shm_unlock_registry (void)
176 semaphore_add (1);
179 static void
180 jack_shm_init_registry ()
182 /* registry must be locked */
183 int i;
185 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
187 jack_shm_header->magic = JACK_SHM_MAGIC;
188 jack_shm_header->protocol = jack_protocol_version;
189 jack_shm_header->type = jack_shmtype;
190 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
191 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
192 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
194 for (i = 0; i < MAX_SHM_ID; ++i) {
195 jack_shm_registry[i].index = i;
199 static int
200 jack_shm_validate_registry ()
202 /* registry must be locked */
204 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
205 && (jack_shm_header->protocol == jack_protocol_version)
206 && (jack_shm_header->type == jack_shmtype)
207 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
208 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
209 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
211 return 0; /* registry OK */
214 return -1;
217 /* set a unique per-user, per-server shm prefix string
219 * According to the POSIX standard:
221 * "The name argument conforms to the construction rules for a
222 * pathname. If name begins with the slash character, then processes
223 * calling shm_open() with the same value of name refer to the same
224 * shared memory object, as long as that name has not been
225 * removed. If name does not begin with the slash character, the
226 * effect is implementation-defined. The interpretation of slash
227 * characters other than the leading slash character in name is
228 * implementation-defined."
230 * Since the Linux implementation does not allow slashes *within* the
231 * name, in the interest of portability we use colons instead.
233 static void
234 jack_set_server_prefix (const char *server_name)
236 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
237 "/jack-%d:%s:", getuid (), server_name);
240 /* gain server addressability to shared memory registration segment
242 * returns: 0 if successful
244 static int
245 jack_server_initialize_shm (int new_registry)
247 int rc;
249 if (jack_shm_header)
250 return 0; /* already initialized */
252 jack_shm_lock_registry ();
254 rc = jack_access_registry (&registry_info);
256 if (new_registry) {
257 jack_remove_shm (&registry_id);
258 rc = ENOENT;
261 switch (rc) {
262 case ENOENT: /* registry does not exist */
263 rc = jack_create_registry (&registry_info);
264 break;
265 case 0: /* existing registry */
266 if (jack_shm_validate_registry () == 0)
267 break;
268 /* else it was invalid, so fall through */
269 case EINVAL: /* bad registry */
270 /* Apparently, this registry was created by an older
271 * JACK version. Delete it so we can try again. */
272 jack_release_shm (&registry_info);
273 jack_remove_shm (&registry_id);
274 if ((rc = jack_create_registry (&registry_info)) != 0) {
275 jack_error ("incompatible shm registry (%s)",
276 strerror (errno));
277 #ifndef USE_POSIX_SHM
278 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
279 JACK_SHM_REGISTRY_KEY);
280 #endif
282 break;
283 default: /* failure return code */
284 break;
287 jack_shm_unlock_registry ();
288 return rc;
291 /* gain client addressability to shared memory registration segment
293 * NOTE: this function is no longer used for server initialization,
294 * instead it calls jack_register_server().
296 * returns: 0 if successful
299 jack_initialize_shm (const char *server_name)
301 int rc;
303 if (jack_shm_header)
304 return 0; /* already initialized */
306 jack_set_server_prefix (server_name);
308 jack_shm_lock_registry ();
310 if ((rc = jack_access_registry (&registry_info)) == 0) {
311 if ((rc = jack_shm_validate_registry ()) != 0) {
312 jack_error ("Incompatible shm registry, "
313 "are jackd and libjack in sync?");
316 jack_shm_unlock_registry ();
318 return rc;
321 void
322 jack_destroy_shm (jack_shm_info_t* si)
324 /* must NOT have the registry locked */
325 if (si->index == JACK_SHM_NULL_INDEX)
326 return; /* segment not allocated */
328 jack_remove_shm (&jack_shm_registry[si->index].id);
329 jack_release_shm_info (si->index);
332 jack_shm_registry_t *
333 jack_get_free_shm_info ()
335 /* registry must be locked */
336 jack_shm_registry_t* si = NULL;
337 int i;
339 for (i = 0; i < MAX_SHM_ID; ++i) {
340 if (jack_shm_registry[i].size == 0) {
341 break;
345 if (i < MAX_SHM_ID) {
346 si = &jack_shm_registry[i];
349 return si;
352 static inline void
353 jack_release_shm_entry (jack_shm_registry_index_t index)
355 /* the registry must be locked */
356 jack_shm_registry[index].size = 0;
357 jack_shm_registry[index].allocator = 0;
358 memset (&jack_shm_registry[index].id, 0,
359 sizeof (jack_shm_registry[index].id));
362 void
363 jack_release_shm_info (jack_shm_registry_index_t index)
365 /* must NOT have the registry locked */
366 if (jack_shm_registry[index].allocator == getpid()) {
367 jack_shm_lock_registry ();
368 jack_release_shm_entry (index);
369 jack_shm_unlock_registry ();
373 /* Claim server_name for this process.
375 * returns 0 if successful
376 * EEXIST if server_name was already active for this user
377 * ENOSPC if server registration limit reached
378 * ENOMEM if unable to access shared memory registry
381 jack_register_server (const char *server_name, int new_registry)
383 int i;
384 pid_t my_pid = getpid ();
386 jack_set_server_prefix (server_name);
388 jack_info ("JACK compiled with %s SHM support.", JACK_SHM_TYPE);
390 if (jack_server_initialize_shm (new_registry))
391 return ENOMEM;
393 jack_shm_lock_registry ();
395 /* See if server_name already registered. Since server names
396 * are per-user, we register the unique server prefix string.
398 for (i = 0; i < MAX_SERVERS; i++) {
400 if (strncmp (jack_shm_header->server[i].name,
401 jack_shm_server_prefix,
402 JACK_SERVER_NAME_SIZE) != 0)
403 continue; /* no match */
405 if (jack_shm_header->server[i].pid == my_pid)
406 return 0; /* it's me */
408 /* see if server still exists */
409 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
410 return EEXIST; /* other server running */
413 /* it's gone, reclaim this entry */
414 memset (&jack_shm_header->server[i], 0,
415 sizeof (jack_shm_server_t));
418 /* find a free entry */
419 for (i = 0; i < MAX_SERVERS; i++) {
420 if (jack_shm_header->server[i].pid == 0)
421 break;
424 if (i >= MAX_SERVERS)
425 return ENOSPC; /* out of space */
427 /* claim it */
428 jack_shm_header->server[i].pid = my_pid;
429 strncpy (jack_shm_header->server[i].name,
430 jack_shm_server_prefix,
431 JACK_SERVER_NAME_SIZE);
433 jack_shm_unlock_registry ();
435 return 0;
438 /* release server_name registration */
439 void
440 jack_unregister_server (const char *server_name /* unused */)
442 int i;
443 pid_t my_pid = getpid ();
445 jack_shm_lock_registry ();
447 for (i = 0; i < MAX_SERVERS; i++) {
448 if (jack_shm_header->server[i].pid == my_pid) {
449 memset (&jack_shm_header->server[i], 0,
450 sizeof (jack_shm_server_t));
454 jack_shm_unlock_registry ();
457 /* called for server startup and termination */
459 jack_cleanup_shm ()
461 int i;
462 int destroy;
463 jack_shm_info_t copy;
464 pid_t my_pid = getpid ();
466 jack_shm_lock_registry ();
468 for (i = 0; i < MAX_SHM_ID; i++) {
469 jack_shm_registry_t* r;
471 r = &jack_shm_registry[i];
472 memcpy (&copy, r, sizeof (jack_shm_info_t));
473 destroy = FALSE;
475 /* ignore unused entries */
476 if (r->allocator == 0)
477 continue;
479 /* is this my shm segment? */
480 if (r->allocator == my_pid) {
482 /* allocated by this process, so unattach
483 and destroy. */
484 jack_release_shm (&copy);
485 destroy = TRUE;
487 } else {
489 /* see if allocator still exists */
490 if (kill (r->allocator, 0)) {
491 if (errno == ESRCH) {
492 /* allocator no longer exists,
493 * so destroy */
494 destroy = TRUE;
499 if (destroy) {
501 int index = copy.index;
503 if ((index >= 0) && (index < MAX_SHM_ID)) {
504 jack_remove_shm (&jack_shm_registry[index].id);
505 jack_release_shm_entry (index);
507 r->size = 0;
508 r->allocator = 0;
512 jack_shm_unlock_registry ();
514 return TRUE;
517 /* resize a shared memory segment
519 * There is no way to resize a System V shm segment. Resizing is
520 * possible with POSIX shm, but not with the non-conformant Mac OS X
521 * implementation. Since POSIX shm is mainly used on that platform,
522 * it's simpler to treat them both the same.
524 * So, we always resize by deleting and reallocating. This is
525 * tricky, because the old segment will not disappear until
526 * all the clients have released it. We only do what we can
527 * from here.
529 * This is not done under a single lock. I don't even want to think
530 * about all the things that could possibly go wrong if multple
531 * processes tried to resize the same segment concurrently. That
532 * probably doesn't happen.
535 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
537 jack_release_shm (si);
538 jack_destroy_shm (si);
540 if (jack_shmalloc (size, si)) {
541 return -1;
544 return jack_attach_shm (si);
547 #ifdef USE_POSIX_SHM
549 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
550 * POSIX interface-dependent functions
551 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
553 /* gain addressability to existing SHM registry segment
555 * sets up global registry pointers, if successful
557 * returns: 0 if existing registry accessed successfully
558 * ENOENT if registry does not exist
559 * EINVAL if registry exists, but has the wrong size
561 static int
562 jack_access_registry (jack_shm_info_t *ri)
564 /* registry must be locked */
565 int shm_fd;
567 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
569 /* try to open an existing segment */
570 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
571 int rc = errno;
572 if (errno != ENOENT) {
573 jack_error ("cannot open existing shm registry segment"
574 " (%s)", strerror (errno));
576 close (shm_fd);
577 return rc;
580 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
581 PROT_READ|PROT_WRITE,
582 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
583 jack_error ("cannot mmap shm registry segment (%s)",
584 strerror (errno));
585 close (shm_fd);
586 return EINVAL;
589 /* set up global pointers */
590 ri->index = JACK_SHM_REGISTRY_INDEX;
591 jack_shm_header = ri->attached_at;
592 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
594 return 0;
597 /* create a new SHM registry segment
599 * sets up global registry pointers, if successful
601 * returns: 0 if registry created successfully
602 * nonzero error code if unable to allocate a new registry
604 static int
605 jack_create_registry (jack_shm_info_t *ri)
607 /* registry must be locked */
608 int shm_fd;
610 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
612 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
613 int rc = errno;
614 jack_error ("cannot create shm registry segment (%s)",
615 strerror (errno));
616 return rc;
619 /* Set the desired segment size. NOTE: the non-conformant Mac
620 * OS X POSIX shm only allows ftruncate() on segment creation.
622 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
623 int rc = errno;
624 jack_error ("cannot set registry size (%s)", strerror (errno));
625 jack_remove_shm (&registry_id);
626 close (shm_fd);
627 return rc;
630 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
631 PROT_READ|PROT_WRITE,
632 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
633 jack_error ("cannot mmap shm registry segment (%s)",
634 strerror (errno));
635 jack_remove_shm (&registry_id);
636 close (shm_fd);
637 return EINVAL;
640 /* set up global pointers */
641 ri->index = JACK_SHM_REGISTRY_INDEX;
642 jack_shm_header = ri->attached_at;
643 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
645 /* initialize registry contents */
646 jack_shm_init_registry ();
648 return 0;
651 static void
652 jack_remove_shm (jack_shm_id_t *id)
654 /* registry may or may not be locked */
655 /* note that in many cases the client has already removed
656 the shm segment, so this failing is not an error.
657 XXX it would be good to differentiate between these
658 two conditions.
660 shm_unlink ((char *) id);
663 void
664 jack_release_shm (jack_shm_info_t* si)
666 /* registry may or may not be locked */
667 if (si->attached_at != MAP_FAILED) {
668 munmap (si->attached_at, jack_shm_registry[si->index].size);
672 /* allocate a POSIX shared memory segment */
674 jack_shmalloc (jack_shmsize_t size, jack_shm_info_t* si)
676 jack_shm_registry_t* registry;
677 int shm_fd;
678 int rc = -1;
679 char name[SHM_NAME_MAX+1];
681 jack_shm_lock_registry ();
683 if ((registry = jack_get_free_shm_info ()) == NULL) {
684 jack_error ("shm registry full");
685 goto unlock;
688 /* On Mac OS X, the maximum length of a shared memory segment
689 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
690 * defined by the standard). Unfortunately, Apple sets this
691 * value so small (about 31 bytes) that it is useless for
692 * actual names. So, we construct a short name from the
693 * registry index for uniqueness.
695 snprintf (name, sizeof (name), "/jack-%d", registry->index);
697 if (strlen (name) >= sizeof (registry->id)) {
698 jack_error ("shm segment name too long %s", name);
699 goto unlock;
702 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
703 jack_error ("cannot create shm segment %s (%s)",
704 name, strerror (errno));
705 goto unlock;
708 if (ftruncate (shm_fd, size) < 0) {
709 jack_error ("cannot set size of engine shm "
710 "registry 0 (%s)",
711 strerror (errno));
712 close (shm_fd);
713 goto unlock;
716 close (shm_fd);
717 registry->size = size;
718 strncpy (registry->id, name, sizeof (registry->id));
719 registry->allocator = getpid();
720 si->index = registry->index;
721 si->attached_at = MAP_FAILED; /* not attached */
722 rc = 0; /* success */
724 unlock:
725 jack_shm_unlock_registry ();
726 return rc;
730 jack_attach_shm (jack_shm_info_t* si)
732 int shm_fd;
733 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
735 if ((shm_fd = shm_open (registry->id,
736 O_RDWR, 0666)) < 0) {
737 jack_error ("cannot open shm segment %s (%s)", registry->id,
738 strerror (errno));
739 return -1;
742 if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
743 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
744 jack_error ("cannot mmap shm segment %s (%s)",
745 registry->id,
746 strerror (errno));
747 close (shm_fd);
748 return -1;
751 close (shm_fd);
753 return 0;
756 #else
758 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
759 * System V interface-dependent functions
760 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
762 /* gain addressability to existing SHM registry segment
764 * sets up global registry pointers, if successful
766 * returns: 0 if existing registry accessed successfully
767 * ENOENT if registry does not exist
768 * EINVAL if registry exists, but has the wrong size
769 * other nonzero error code if unable to access registry
771 static int
772 jack_access_registry (jack_shm_info_t *ri)
774 /* registry must be locked */
776 /* try without IPC_CREAT to get existing segment */
777 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
778 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
780 switch (errno) {
782 case ENOENT: /* segment does not exist */
783 return ENOENT;
785 case EINVAL: /* segment exists, but too small */
786 /* attempt minimum size access */
787 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
788 return EINVAL;
790 default: /* or other error */
791 jack_error ("unable to access shm registry (%s)",
792 strerror (errno));
793 return errno;
797 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
798 jack_error ("cannot attach shm registry segment (%s)",
799 strerror (errno));
800 return EINVAL;
803 /* set up global pointers */
804 ri->index = JACK_SHM_REGISTRY_INDEX;
805 jack_shm_header = ri->attached_at;
806 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
808 return 0;
811 /* create a new SHM registry segment
813 * sets up global registry pointers, if successful
815 * returns: 0 if registry created successfully
816 * nonzero error code if unable to allocate a new registry
818 static int
819 jack_create_registry (jack_shm_info_t *ri)
821 /* registry must be locked */
822 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
823 JACK_SHM_REGISTRY_SIZE,
824 0666|IPC_CREAT)) < 0) {
825 jack_error ("cannot create shm registry segment (%s)",
826 strerror (errno));
827 return errno;
830 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
831 jack_error ("cannot attach shm registry segment (%s)",
832 strerror (errno));
833 return EINVAL;
836 /* set up global pointers */
837 ri->index = JACK_SHM_REGISTRY_INDEX;
838 jack_shm_header = ri->attached_at;
839 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
841 /* initialize registry contents */
842 jack_shm_init_registry ();
844 return 0;
847 static void
848 jack_remove_shm (jack_shm_id_t *id)
850 /* registry may or may not be locked */
851 /* this call can fail if we are attempting to
852 remove a segment that was already deleted
853 by the client. XXX i suppose the
854 function should take a "canfail" argument.
856 shmctl (*id, IPC_RMID, NULL);
859 void
860 jack_release_shm (jack_shm_info_t* si)
862 /* registry may or may not be locked */
863 if (si->attached_at != MAP_FAILED) {
864 shmdt (si->attached_at);
869 jack_shmalloc (jack_shmsize_t size, jack_shm_info_t* si)
871 int shmflags;
872 int shmid;
873 int rc = -1;
874 jack_shm_registry_t* registry;
876 jack_shm_lock_registry ();
878 if ((registry = jack_get_free_shm_info ())) {
880 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
882 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
884 registry->size = size;
885 registry->id = shmid;
886 registry->allocator = getpid();
887 si->index = registry->index;
888 si->attached_at = MAP_FAILED; /* not attached */
889 rc = 0;
891 } else {
892 jack_error ("cannot create shm segment (%s)",
893 strerror (errno));
897 jack_shm_unlock_registry ();
899 return rc;
903 jack_attach_shm (jack_shm_info_t* si)
905 if ((si->attached_at = shmat (jack_shm_registry[si->index].id,
906 0, 0)) < 0) {
907 jack_error ("cannot attach shm segment (%s)",
908 strerror (errno));
909 jack_release_shm_info (si->index);
910 return -1;
912 return 0;
915 #endif /* !USE_POSIX_SHM */