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.
43 #include <sys/types.h>
45 #include <sysdeps/ipc.h>
48 #include <sysdeps/ipc.h>
51 #include <jack/internal.h>
52 #include <jack/version.h>
55 static jack_shmtype_t jack_shmtype
= shm_POSIX
;
57 static jack_shmtype_t jack_shmtype
= shm_SYSV
;
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
108 static int semid
= -1;
110 /* all semaphore errors are fatal -- issue message, but do not return */
112 semaphore_error (char *msg
)
114 jack_error ("Fatal JACK semaphore error: %s (%s)",
115 msg
, strerror (errno
));
122 key_t semkey
= JACK_SEMAPHORE_KEY
;
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. */
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");
147 semaphore_error ("semget creation");
153 semaphore_add (int value
)
159 sbuf
.sem_flg
= SEM_UNDO
;
160 if (semop(semid
, &sbuf
, 1) == -1) {
161 semaphore_error ("semop");
166 jack_shm_lock_registry (void)
175 jack_shm_unlock_registry (void)
181 jack_shm_init_registry ()
183 /* registry must be locked */
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
;
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 */
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.
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
246 jack_server_initialize_shm (int new_registry
)
251 return 0; /* already initialized */
253 jack_shm_lock_registry ();
255 rc
= jack_access_registry (®istry_info
);
258 jack_remove_shm (®istry_id
);
263 case ENOENT
: /* registry does not exist */
264 rc
= jack_create_registry (®istry_info
);
266 case 0: /* existing registry */
267 if (jack_shm_validate_registry () == 0)
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 (®istry_info
);
274 jack_remove_shm (®istry_id
);
275 if ((rc
= jack_create_registry (®istry_info
)) != 0) {
276 jack_error ("incompatible shm registry (%s)",
278 #ifndef USE_POSIX_SHM
279 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
280 JACK_SHM_REGISTRY_KEY
);
284 default: /* failure return code */
288 jack_shm_unlock_registry ();
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
)
305 return 0; /* already initialized */
307 jack_set_server_prefix (server_name
);
309 jack_shm_lock_registry ();
311 if ((rc
= jack_access_registry (®istry_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 ();
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
;
340 for (i
= 0; i
< MAX_SHM_ID
; ++i
) {
341 if (jack_shm_registry
[i
].size
== 0) {
346 if (i
< MAX_SHM_ID
) {
347 si
= &jack_shm_registry
[i
];
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
));
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
)
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
))
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)
425 if (i
>= MAX_SERVERS
)
426 return ENOSPC
; /* out of space */
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 ();
439 /* release server_name registration */
441 jack_unregister_server (const char *server_name
/* unused */)
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 */
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 (©
, r
, sizeof (jack_shm_info_t
));
476 /* ignore unused entries */
477 if (r
->allocator
== 0)
480 /* is this my shm segment? */
481 if (r
->allocator
== my_pid
) {
483 /* allocated by this process, so unattach
485 jack_release_shm (©
);
490 /* see if allocator still exists */
491 if (kill (r
->allocator
, 0)) {
492 if (errno
== ESRCH
) {
493 /* allocator no longer exists,
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
);
513 jack_shm_unlock_registry ();
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
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
)) {
545 return jack_attach_shm (si
);
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
563 jack_access_registry (jack_shm_info_t
*ri
)
565 /* registry must be locked */
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) {
573 if (errno
!= ENOENT
) {
574 jack_error ("cannot open existing shm registry segment"
575 " (%s)", strerror (errno
));
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)",
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);
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
606 jack_create_registry (jack_shm_info_t
*ri
)
608 /* registry must be locked */
611 strncpy (registry_id
, "/jack-shm-registry", sizeof (registry_id
));
613 if ((shm_fd
= shm_open (registry_id
, O_RDWR
|O_CREAT
, 0666)) < 0) {
615 jack_error ("cannot create shm registry segment (%s)",
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) {
625 jack_error ("cannot set registry size (%s)", strerror (errno
));
626 jack_remove_shm (®istry_id
);
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)",
636 jack_remove_shm (®istry_id
);
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 ();
653 jack_remove_shm (jack_shm_id_t
*id
)
655 /* registry may or may not be locked */
656 shm_unlink ((char *) id
);
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
;
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");
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
);
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
));
704 if (ftruncate (shm_fd
, size
) < 0) {
705 jack_error ("cannot set size of engine shm "
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 */
721 jack_shm_unlock_registry ();
726 jack_attach_shm (jack_shm_info_t
* si
)
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
,
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)",
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
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) {
778 case ENOENT
: /* segment does not exist */
781 case EINVAL
: /* segment exists, but too small */
782 /* attempt minimum size access */
783 registry_id
= shmget (JACK_SHM_REGISTRY_KEY
, 1, 0666);
786 default: /* or other error */
787 jack_error ("unable to access shm registry (%s)",
793 if ((ri
->attached_at
= shmat (registry_id
, 0, 0)) < 0) {
794 jack_error ("cannot attach shm registry segment (%s)",
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);
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
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)",
826 if ((ri
->attached_at
= shmat (registry_id
, 0, 0)) < 0) {
827 jack_error ("cannot attach shm registry segment (%s)",
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 ();
844 jack_remove_shm (jack_shm_id_t
*id
)
846 /* registry may or may not be locked */
847 shmctl (*id
, IPC_RMID
, NULL
);
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
)
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 */
883 jack_error ("cannot create shm segment (%s)",
888 jack_shm_unlock_registry ();
894 jack_attach_shm (jack_shm_info_t
* si
)
896 if ((si
->attached_at
= shmat (jack_shm_registry
[si
->index
].id
,
898 jack_error ("cannot attach shm segment (%s)",
900 jack_release_shm_info (si
->index
);
906 #endif /* !USE_POSIX_SHM */