no more dither when converting from float to 24 bit values - i am not sure how this...
[jack.git] / libjack / shm.c
blobbc0a8cd29a57aaaf3ebaaf28851219e1e4180b86
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 #define JACK_SEMAPHORE_KEY 0x282929
104 #ifndef USE_POSIX_SHM
105 #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
106 #endif
108 static int semid = -1;
110 /* all semaphore errors are fatal -- issue message, but do not return */
111 static void
112 semaphore_error (char *msg)
114 jack_error ("Fatal JACK semaphore error: %s (%s)",
115 msg, strerror (errno));
116 abort ();
119 static void
120 semaphore_init ()
122 key_t semkey = JACK_SEMAPHORE_KEY;
123 struct sembuf sbuf;
124 int create_flags = IPC_CREAT | IPC_EXCL
125 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
127 /* Get semaphore ID associated with this key. */
128 if ((semid = semget(semkey, 0, 0)) == -1) {
130 /* Semaphore does not exist - Create. */
131 if ((semid = semget(semkey, 1, create_flags)) != -1) {
133 /* Initialize the semaphore, allow one owner. */
134 sbuf.sem_num = 0;
135 sbuf.sem_op = 1;
136 sbuf.sem_flg = 0;
137 if (semop(semid, &sbuf, 1) == -1) {
138 semaphore_error ("semop");
141 } else if (errno == EEXIST) {
142 if ((semid = semget(semkey, 0, 0)) == -1) {
143 semaphore_error ("semget");
146 } else {
147 semaphore_error ("semget creation");
152 static inline void
153 semaphore_add (int value)
155 struct sembuf sbuf;
157 sbuf.sem_num = 0;
158 sbuf.sem_op = value;
159 sbuf.sem_flg = SEM_UNDO;
160 if (semop(semid, &sbuf, 1) == -1) {
161 semaphore_error ("semop");
165 static void
166 jack_shm_lock_registry (void)
168 if (semid == -1)
169 semaphore_init ();
171 semaphore_add (-1);
174 static void
175 jack_shm_unlock_registry (void)
177 semaphore_add (1);
180 static void
181 jack_shm_init_registry ()
183 /* registry must be locked */
184 int i;
186 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
188 jack_shm_header->magic = JACK_SHM_MAGIC;
189 jack_shm_header->protocol = jack_protocol_version;
190 jack_shm_header->type = jack_shmtype;
191 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
192 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
193 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
195 for (i = 0; i < MAX_SHM_ID; ++i) {
196 jack_shm_registry[i].index = i;
200 static int
201 jack_shm_validate_registry ()
203 /* registry must be locked */
205 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
206 && (jack_shm_header->protocol == jack_protocol_version)
207 && (jack_shm_header->type == jack_shmtype)
208 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
209 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
210 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
212 return 0; /* registry OK */
215 return -1;
218 /* set a unique per-user, per-server shm prefix string
220 * According to the POSIX standard:
222 * "The name argument conforms to the construction rules for a
223 * pathname. If name begins with the slash character, then processes
224 * calling shm_open() with the same value of name refer to the same
225 * shared memory object, as long as that name has not been
226 * removed. If name does not begin with the slash character, the
227 * effect is implementation-defined. The interpretation of slash
228 * characters other than the leading slash character in name is
229 * implementation-defined."
231 * Since the Linux implementation does not allow slashes *within* the
232 * name, in the interest of portability we use colons instead.
234 static void
235 jack_set_server_prefix (const char *server_name)
237 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
238 "/jack-%d:%s:", getuid (), server_name);
241 /* gain server addressability to shared memory registration segment
243 * returns: 0 if successful
245 static int
246 jack_server_initialize_shm (int new_registry)
248 int rc;
250 if (jack_shm_header)
251 return 0; /* already initialized */
253 jack_shm_lock_registry ();
255 rc = jack_access_registry (&registry_info);
257 if (new_registry) {
258 jack_remove_shm (&registry_id);
259 rc = ENOENT;
262 switch (rc) {
263 case ENOENT: /* registry does not exist */
264 rc = jack_create_registry (&registry_info);
265 break;
266 case 0: /* existing registry */
267 if (jack_shm_validate_registry () == 0)
268 break;
269 /* else it was invalid, so fall through */
270 case EINVAL: /* bad registry */
271 /* Apparently, this registry was created by an older
272 * JACK version. Delete it so we can try again. */
273 jack_release_shm (&registry_info);
274 jack_remove_shm (&registry_id);
275 if ((rc = jack_create_registry (&registry_info)) != 0) {
276 jack_error ("incompatible shm registry (%s)",
277 strerror (errno));
278 #ifndef USE_POSIX_SHM
279 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
280 JACK_SHM_REGISTRY_KEY);
281 #endif
283 break;
284 default: /* failure return code */
285 break;
288 jack_shm_unlock_registry ();
289 return rc;
292 /* gain client addressability to shared memory registration segment
294 * NOTE: this function is no longer used for server initialization,
295 * instead it calls jack_register_server().
297 * returns: 0 if successful
300 jack_initialize_shm (const char *server_name)
302 int rc;
304 if (jack_shm_header)
305 return 0; /* already initialized */
307 jack_set_server_prefix (server_name);
309 jack_shm_lock_registry ();
311 if ((rc = jack_access_registry (&registry_info)) == 0) {
312 if ((rc = jack_shm_validate_registry ()) != 0) {
313 jack_error ("Incompatible shm registry, "
314 "are jackd and libjack in sync?");
317 jack_shm_unlock_registry ();
319 return rc;
322 void
323 jack_destroy_shm (jack_shm_info_t* si)
325 /* must NOT have the registry locked */
326 if (si->index == JACK_SHM_NULL_INDEX)
327 return; /* segment not allocated */
329 jack_remove_shm (&jack_shm_registry[si->index].id);
330 jack_release_shm_info (si->index);
333 jack_shm_registry_t *
334 jack_get_free_shm_info ()
336 /* registry must be locked */
337 jack_shm_registry_t* si = NULL;
338 int i;
340 for (i = 0; i < MAX_SHM_ID; ++i) {
341 if (jack_shm_registry[i].size == 0) {
342 break;
346 if (i < MAX_SHM_ID) {
347 si = &jack_shm_registry[i];
350 return si;
353 static inline void
354 jack_release_shm_entry (jack_shm_registry_index_t index)
356 /* the registry must be locked */
357 jack_shm_registry[index].size = 0;
358 jack_shm_registry[index].allocator = 0;
359 memset (&jack_shm_registry[index].id, 0,
360 sizeof (jack_shm_registry[index].id));
363 void
364 jack_release_shm_info (jack_shm_registry_index_t index)
366 /* must NOT have the registry locked */
367 if (jack_shm_registry[index].allocator == getpid()) {
368 jack_shm_lock_registry ();
369 jack_release_shm_entry (index);
370 jack_shm_unlock_registry ();
374 /* Claim server_name for this process.
376 * returns 0 if successful
377 * EEXIST if server_name was already active for this user
378 * ENOSPC if server registration limit reached
379 * ENOMEM if unable to access shared memory registry
382 jack_register_server (const char *server_name, int new_registry)
384 int i;
385 pid_t my_pid = getpid ();
387 jack_set_server_prefix (server_name);
389 jack_info ("JACK compiled with %s SHM support.", JACK_SHM_TYPE);
391 if (jack_server_initialize_shm (new_registry))
392 return ENOMEM;
394 jack_shm_lock_registry ();
396 /* See if server_name already registered. Since server names
397 * are per-user, we register the unique server prefix string.
399 for (i = 0; i < MAX_SERVERS; i++) {
401 if (strncmp (jack_shm_header->server[i].name,
402 jack_shm_server_prefix,
403 JACK_SERVER_NAME_SIZE) != 0)
404 continue; /* no match */
406 if (jack_shm_header->server[i].pid == my_pid)
407 return 0; /* it's me */
409 /* see if server still exists */
410 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
411 return EEXIST; /* other server running */
414 /* it's gone, reclaim this entry */
415 memset (&jack_shm_header->server[i], 0,
416 sizeof (jack_shm_server_t));
419 /* find a free entry */
420 for (i = 0; i < MAX_SERVERS; i++) {
421 if (jack_shm_header->server[i].pid == 0)
422 break;
425 if (i >= MAX_SERVERS)
426 return ENOSPC; /* out of space */
428 /* claim it */
429 jack_shm_header->server[i].pid = my_pid;
430 strncpy (jack_shm_header->server[i].name,
431 jack_shm_server_prefix,
432 JACK_SERVER_NAME_SIZE);
434 jack_shm_unlock_registry ();
436 return 0;
439 /* release server_name registration */
440 void
441 jack_unregister_server (const char *server_name /* unused */)
443 int i;
444 pid_t my_pid = getpid ();
446 jack_shm_lock_registry ();
448 for (i = 0; i < MAX_SERVERS; i++) {
449 if (jack_shm_header->server[i].pid == my_pid) {
450 memset (&jack_shm_header->server[i], 0,
451 sizeof (jack_shm_server_t));
455 jack_shm_unlock_registry ();
458 /* called for server startup and termination */
460 jack_cleanup_shm ()
462 int i;
463 int destroy;
464 jack_shm_info_t copy;
465 pid_t my_pid = getpid ();
467 jack_shm_lock_registry ();
469 for (i = 0; i < MAX_SHM_ID; i++) {
470 jack_shm_registry_t* r;
472 r = &jack_shm_registry[i];
473 memcpy (&copy, r, sizeof (jack_shm_info_t));
474 destroy = FALSE;
476 /* ignore unused entries */
477 if (r->allocator == 0)
478 continue;
480 /* is this my shm segment? */
481 if (r->allocator == my_pid) {
483 /* allocated by this process, so unattach
484 and destroy. */
485 jack_release_shm (&copy);
486 destroy = TRUE;
488 } else {
490 /* see if allocator still exists */
491 if (kill (r->allocator, 0)) {
492 if (errno == ESRCH) {
493 /* allocator no longer exists,
494 * so destroy */
495 destroy = TRUE;
500 if (destroy) {
502 int index = copy.index;
504 if ((index >= 0) && (index < MAX_SHM_ID)) {
505 jack_remove_shm (&jack_shm_registry[index].id);
506 jack_release_shm_entry (index);
508 r->size = 0;
509 r->allocator = 0;
513 jack_shm_unlock_registry ();
515 return TRUE;
518 /* resize a shared memory segment
520 * There is no way to resize a System V shm segment. Resizing is
521 * possible with POSIX shm, but not with the non-conformant Mac OS X
522 * implementation. Since POSIX shm is mainly used on that platform,
523 * it's simpler to treat them both the same.
525 * So, we always resize by deleting and reallocating. This is
526 * tricky, because the old segment will not disappear until
527 * all the clients have released it. We only do what we can
528 * from here.
530 * This is not done under a single lock. I don't even want to think
531 * about all the things that could possibly go wrong if multple
532 * processes tried to resize the same segment concurrently. That
533 * probably doesn't happen.
536 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
538 jack_release_shm (si);
539 jack_destroy_shm (si);
541 if (jack_shmalloc (size, si)) {
542 return -1;
545 return jack_attach_shm (si);
548 #ifdef USE_POSIX_SHM
550 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
551 * POSIX interface-dependent functions
552 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
554 /* gain addressability to existing SHM registry segment
556 * sets up global registry pointers, if successful
558 * returns: 0 if existing registry accessed successfully
559 * ENOENT if registry does not exist
560 * EINVAL if registry exists, but has the wrong size
562 static int
563 jack_access_registry (jack_shm_info_t *ri)
565 /* registry must be locked */
566 int shm_fd;
568 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
570 /* try to open an existing segment */
571 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
572 int rc = errno;
573 if (errno != ENOENT) {
574 jack_error ("cannot open existing shm registry segment"
575 " (%s)", strerror (errno));
577 close (shm_fd);
578 return rc;
581 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
582 PROT_READ|PROT_WRITE,
583 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
584 jack_error ("cannot mmap shm registry segment (%s)",
585 strerror (errno));
586 close (shm_fd);
587 return EINVAL;
590 /* set up global pointers */
591 ri->index = JACK_SHM_REGISTRY_INDEX;
592 jack_shm_header = ri->attached_at;
593 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
595 return 0;
598 /* create a new SHM registry segment
600 * sets up global registry pointers, if successful
602 * returns: 0 if registry created successfully
603 * nonzero error code if unable to allocate a new registry
605 static int
606 jack_create_registry (jack_shm_info_t *ri)
608 /* registry must be locked */
609 int shm_fd;
611 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
613 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
614 int rc = errno;
615 jack_error ("cannot create shm registry segment (%s)",
616 strerror (errno));
617 return rc;
620 /* Set the desired segment size. NOTE: the non-conformant Mac
621 * OS X POSIX shm only allows ftruncate() on segment creation.
623 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
624 int rc = errno;
625 jack_error ("cannot set registry size (%s)", strerror (errno));
626 jack_remove_shm (&registry_id);
627 close (shm_fd);
628 return rc;
631 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
632 PROT_READ|PROT_WRITE,
633 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
634 jack_error ("cannot mmap shm registry segment (%s)",
635 strerror (errno));
636 jack_remove_shm (&registry_id);
637 close (shm_fd);
638 return EINVAL;
641 /* set up global pointers */
642 ri->index = JACK_SHM_REGISTRY_INDEX;
643 jack_shm_header = ri->attached_at;
644 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
646 /* initialize registry contents */
647 jack_shm_init_registry ();
649 return 0;
652 static void
653 jack_remove_shm (jack_shm_id_t *id)
655 /* registry may or may not be locked */
656 shm_unlink ((char *) id);
659 void
660 jack_release_shm (jack_shm_info_t* si)
662 /* registry may or may not be locked */
663 if (si->attached_at != MAP_FAILED) {
664 munmap (si->attached_at, jack_shm_registry[si->index].size);
668 /* allocate a POSIX shared memory segment */
670 jack_shmalloc (jack_shmsize_t size, jack_shm_info_t* si)
672 jack_shm_registry_t* registry;
673 int shm_fd;
674 int rc = -1;
675 char name[SHM_NAME_MAX+1];
677 jack_shm_lock_registry ();
679 if ((registry = jack_get_free_shm_info ()) == NULL) {
680 jack_error ("shm registry full");
681 goto unlock;
684 /* On Mac OS X, the maximum length of a shared memory segment
685 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
686 * defined by the standard). Unfortunately, Apple sets this
687 * value so small (about 31 bytes) that it is useless for
688 * actual names. So, we construct a short name from the
689 * registry index for uniqueness.
691 snprintf (name, sizeof (name), "/jack-%d", registry->index);
693 if (strlen (name) >= sizeof (registry->id)) {
694 jack_error ("shm segment name too long %s", name);
695 goto unlock;
698 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
699 jack_error ("cannot create shm segment %s (%s)",
700 name, strerror (errno));
701 goto unlock;
704 if (ftruncate (shm_fd, size) < 0) {
705 jack_error ("cannot set size of engine shm "
706 "registry 0 (%s)",
707 strerror (errno));
708 close (shm_fd);
709 goto unlock;
712 close (shm_fd);
713 registry->size = size;
714 strncpy (registry->id, name, sizeof (registry->id));
715 registry->allocator = getpid();
716 si->index = registry->index;
717 si->attached_at = MAP_FAILED; /* not attached */
718 rc = 0; /* success */
720 unlock:
721 jack_shm_unlock_registry ();
722 return rc;
726 jack_attach_shm (jack_shm_info_t* si)
728 int shm_fd;
729 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
731 if ((shm_fd = shm_open (registry->id,
732 O_RDWR, 0666)) < 0) {
733 jack_error ("cannot open shm segment %s (%s)", registry->id,
734 strerror (errno));
735 return -1;
738 if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
739 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
740 jack_error ("cannot mmap shm segment %s (%s)",
741 registry->id,
742 strerror (errno));
743 close (shm_fd);
744 return -1;
747 close (shm_fd);
749 return 0;
752 #else
754 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
755 * System V interface-dependent functions
756 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
758 /* gain addressability to existing SHM registry segment
760 * sets up global registry pointers, if successful
762 * returns: 0 if existing registry accessed successfully
763 * ENOENT if registry does not exist
764 * EINVAL if registry exists, but has the wrong size
765 * other nonzero error code if unable to access registry
767 static int
768 jack_access_registry (jack_shm_info_t *ri)
770 /* registry must be locked */
772 /* try without IPC_CREAT to get existing segment */
773 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
774 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
776 switch (errno) {
778 case ENOENT: /* segment does not exist */
779 return ENOENT;
781 case EINVAL: /* segment exists, but too small */
782 /* attempt minimum size access */
783 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
784 return EINVAL;
786 default: /* or other error */
787 jack_error ("unable to access shm registry (%s)",
788 strerror (errno));
789 return errno;
793 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
794 jack_error ("cannot attach shm registry segment (%s)",
795 strerror (errno));
796 return EINVAL;
799 /* set up global pointers */
800 ri->index = JACK_SHM_REGISTRY_INDEX;
801 jack_shm_header = ri->attached_at;
802 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
804 return 0;
807 /* create a new SHM registry segment
809 * sets up global registry pointers, if successful
811 * returns: 0 if registry created successfully
812 * nonzero error code if unable to allocate a new registry
814 static int
815 jack_create_registry (jack_shm_info_t *ri)
817 /* registry must be locked */
818 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
819 JACK_SHM_REGISTRY_SIZE,
820 0666|IPC_CREAT)) < 0) {
821 jack_error ("cannot create shm registry segment (%s)",
822 strerror (errno));
823 return errno;
826 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
827 jack_error ("cannot attach shm registry segment (%s)",
828 strerror (errno));
829 return EINVAL;
832 /* set up global pointers */
833 ri->index = JACK_SHM_REGISTRY_INDEX;
834 jack_shm_header = ri->attached_at;
835 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
837 /* initialize registry contents */
838 jack_shm_init_registry ();
840 return 0;
843 static void
844 jack_remove_shm (jack_shm_id_t *id)
846 /* registry may or may not be locked */
847 shmctl (*id, IPC_RMID, NULL);
850 void
851 jack_release_shm (jack_shm_info_t* si)
853 /* registry may or may not be locked */
854 if (si->attached_at != MAP_FAILED) {
855 shmdt (si->attached_at);
860 jack_shmalloc (jack_shmsize_t size, jack_shm_info_t* si)
862 int shmflags;
863 int shmid;
864 int rc = -1;
865 jack_shm_registry_t* registry;
867 jack_shm_lock_registry ();
869 if ((registry = jack_get_free_shm_info ())) {
871 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
873 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
875 registry->size = size;
876 registry->id = shmid;
877 registry->allocator = getpid();
878 si->index = registry->index;
879 si->attached_at = MAP_FAILED; /* not attached */
880 rc = 0;
882 } else {
883 jack_error ("cannot create shm segment (%s)",
884 strerror (errno));
888 jack_shm_unlock_registry ();
890 return rc;
894 jack_attach_shm (jack_shm_info_t* si)
896 if ((si->attached_at = shmat (jack_shm_registry[si->index].id,
897 0, 0)) < 0) {
898 jack_error ("cannot attach shm segment (%s)",
899 strerror (errno));
900 jack_release_shm_info (si->index);
901 return -1;
903 return 0;
906 #endif /* !USE_POSIX_SHM */