Cleanup
[jack2.git] / common / shm.c
blob1c0ad93903197a0947c425598e6a2185360fcbfa
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.
31 * $Id: shm.c,v 1.8.2.16 2006/08/28 10:10:16 letz Exp $
34 #ifdef WIN32
35 #include <process.h>
36 #else
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <signal.h>
43 #include <limits.h>
44 #include <errno.h>
45 #include <dirent.h>
46 #include <sys/mman.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/shm.h>
50 #include <sys/sem.h>
51 #include <stdlib.h>
53 #endif
55 #include "shm.h"
56 #include "JackError.h"
58 #ifdef USE_POSIX_SHM
59 static jack_shmtype_t jack_shmtype = shm_POSIX;
60 #elif WIN32
61 static jack_shmtype_t jack_shmtype = shm_WIN32;
62 #else
63 static jack_shmtype_t jack_shmtype = shm_SYSV;
64 #endif
66 /* interface-dependent forward declarations */
67 static int jack_access_registry (jack_shm_info_t *ri);
68 static int jack_create_registry (jack_shm_info_t *ri);
69 static void jack_remove_shm (jack_shm_id_t *id);
71 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
72 * common interface-independent section
73 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 /* The JACK SHM registry is a chunk of memory for keeping track of the
76 * shared memory used by each active JACK server. This allows the
77 * server to clean up shared memory when it exits. To avoid memory
78 * leakage due to kill -9, crashes or debugger-driven exits, this
79 * cleanup is also done when a new instance of that server starts.
82 /* per-process global data for the SHM interfaces */
83 static jack_shm_id_t registry_id; /* SHM id for the registry */
85 #ifdef WIN32
86 static jack_shm_info_t registry_info = {/* SHM info for the registry */
87 JACK_SHM_NULL_INDEX,
88 NULL
89 };
90 #else
91 static jack_shm_info_t registry_info = { /* SHM info for the registry */
92 .index = JACK_SHM_NULL_INDEX,
93 .attached_at = MAP_FAILED
96 #endif
98 /* pointers to registry header and array */
99 static jack_shm_header_t *jack_shm_header = NULL;
100 static jack_shm_registry_t *jack_shm_registry = NULL;
101 static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
103 /* jack_shm_lock_registry() serializes updates to the shared memory
104 * segment JACK uses to keep track of the SHM segements allocated to
105 * all its processes, including multiple servers.
107 * This is not a high-contention lock, but it does need to work across
108 * multiple processes. High transaction rates and realtime safety are
109 * not required. Any solution needs to at least be portable to POSIX
110 * and POSIX-like systems.
112 * We must be particularly careful to ensure that the lock be released
113 * if the owning process terminates abnormally. Otherwise, a segfault
114 * or kill -9 at the wrong moment could prevent JACK from ever running
115 * again on that machine until after a reboot.
118 #define JACK_SEMAPHORE_KEY 0x282929
119 #ifndef USE_POSIX_SHM
120 #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
121 #endif
123 static int semid = -1;
125 #ifdef WIN32
127 // steph TODO
128 static void
129 semaphore_init () {}
131 static void
132 semaphore_add (int value) {}
134 #else
135 /* all semaphore errors are fatal -- issue message, but do not return */
136 static void
137 semaphore_error (char *msg)
139 jack_error ("Fatal JACK semaphore error: %s (%s)",
140 msg, strerror (errno));
141 abort ();
144 static void
145 semaphore_init ()
147 key_t semkey = JACK_SEMAPHORE_KEY;
148 struct sembuf sbuf;
149 int create_flags = IPC_CREAT | IPC_EXCL
150 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
152 /* Get semaphore ID associated with this key. */
153 if ((semid = semget(semkey, 0, 0)) == -1) {
155 /* Semaphore does not exist - Create. */
156 if ((semid = semget(semkey, 1, create_flags)) != -1) {
158 /* Initialize the semaphore, allow one owner. */
159 sbuf.sem_num = 0;
160 sbuf.sem_op = 1;
161 sbuf.sem_flg = 0;
162 if (semop(semid, &sbuf, 1) == -1) {
163 semaphore_error ("semop");
166 } else if (errno == EEXIST) {
167 if ((semid = semget(semkey, 0, 0)) == -1) {
168 semaphore_error ("semget");
171 } else {
172 semaphore_error ("semget creation");
177 static inline void
178 semaphore_add (int value)
180 struct sembuf sbuf;
182 sbuf.sem_num = 0;
183 sbuf.sem_op = value;
184 sbuf.sem_flg = SEM_UNDO;
185 if (semop(semid, &sbuf, 1) == -1) {
186 semaphore_error ("semop");
190 #endif
192 static void
193 jack_shm_lock_registry (void)
195 if (semid == -1)
196 semaphore_init ();
198 semaphore_add (-1);
201 static void
202 jack_shm_unlock_registry (void)
204 semaphore_add (1);
207 static void
208 jack_shm_init_registry ()
210 /* registry must be locked */
211 int i;
213 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
215 jack_shm_header->magic = JACK_SHM_MAGIC;
216 //jack_shm_header->protocol = jack_protocol_version; // steph
217 jack_shm_header->type = jack_shmtype;
218 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
219 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
220 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
222 for (i = 0; i < MAX_SHM_ID; ++i) {
223 jack_shm_registry[i].index = i;
227 static int
228 jack_shm_validate_registry ()
230 /* registry must be locked */
232 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
233 //&& (jack_shm_header->protocol == jack_protocol_version) // steph
234 && (jack_shm_header->type == jack_shmtype)
235 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
236 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
237 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
239 return 0; /* registry OK */
242 return -1;
245 /* set a unique per-user, per-server shm prefix string
247 * According to the POSIX standard:
249 * "The name argument conforms to the construction rules for a
250 * pathname. If name begins with the slash character, then processes
251 * calling shm_open() with the same value of name refer to the same
252 * shared memory object, as long as that name has not been
253 * removed. If name does not begin with the slash character, the
254 * effect is implementation-defined. The interpretation of slash
255 * characters other than the leading slash character in name is
256 * implementation-defined."
258 * Since the Linux implementation does not allow slashes *within* the
259 * name, in the interest of portability we use colons instead.
261 static void
262 jack_set_server_prefix (const char *server_name)
264 #ifdef WIN32
265 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
266 "jack-%d:%s:", _getpid (), server_name); // steph TO CHECK
267 #else
268 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
269 "/jack-%d:%s:", getuid (), server_name);
270 #endif
274 /* gain server addressability to shared memory registration segment
276 * returns: 0 if successful
278 static int
279 jack_server_initialize_shm (void)
281 int rc;
283 if (jack_shm_header)
284 return 0; /* already initialized */
286 jack_shm_lock_registry ();
288 rc = jack_access_registry (&registry_info);
290 switch (rc) {
291 case ENOENT: /* registry does not exist */
292 rc = jack_create_registry (&registry_info);
293 break;
294 case 0: /* existing registry */
295 if (jack_shm_validate_registry () == 0)
296 break;
297 /* else it was invalid, so fall through */
298 case EINVAL: /* bad registry */
299 /* Apparently, this registry was created by an older
300 * JACK version. Delete it so we can try again. */
301 jack_release_shm (&registry_info);
302 jack_remove_shm (&registry_id);
303 if ((rc = jack_create_registry (&registry_info)) != 0) {
304 jack_error ("incompatible shm registry (%s)",
305 strerror (errno));
306 #ifndef USE_POSIX_SHM
307 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
308 JACK_SHM_REGISTRY_KEY);
309 #endif
311 break;
312 default: /* failure return code */
313 break;
316 jack_shm_unlock_registry ();
317 return rc;
320 /* gain client addressability to shared memory registration segment
322 * NOTE: this function is no longer used for server initialization,
323 * instead it calls jack_register_server().
325 * returns: 0 if successful
328 jack_initialize_shm (const char *server_name)
330 int rc;
332 if (jack_shm_header)
333 return 0; /* already initialized */
335 jack_set_server_prefix (server_name);
337 jack_shm_lock_registry ();
338 if ((rc = jack_access_registry (&registry_info)) == 0) {
339 if ((rc = jack_shm_validate_registry ()) != 0) {
340 jack_error ("Incompatible shm registry, "
341 "are jackd and libjack in sync?");
344 jack_shm_unlock_registry ();
346 return rc;
350 // steph
352 int jack_initialize_shm_server()
354 return jack_initialize_shm("default");
357 int jack_initialize_shm_client()
359 return jack_initialize_shm("default");
362 char* jack_shm_addr (jack_shm_info_t* si)
364 return (char*)si->attached_at;
367 void
368 jack_destroy_shm (jack_shm_info_t* si)
370 /* must NOT have the registry locked */
371 if (si->index == JACK_SHM_NULL_INDEX)
372 return; /* segment not allocated */
374 jack_remove_shm (&jack_shm_registry[si->index].id);
375 jack_release_shm_info (si->index);
378 jack_shm_registry_t *
379 jack_get_free_shm_info ()
381 /* registry must be locked */
382 jack_shm_registry_t* si = NULL;
383 int i;
385 for (i = 0; i < MAX_SHM_ID; ++i) {
386 if (jack_shm_registry[i].size == 0) {
387 break;
391 if (i < MAX_SHM_ID) {
392 si = &jack_shm_registry[i];
395 return si;
398 static void
399 jack_release_shm_entry (jack_shm_registry_index_t index)
401 /* the registry must be locked */
402 jack_shm_registry[index].size = 0;
403 jack_shm_registry[index].allocator = 0;
404 memset (&jack_shm_registry[index].id, 0,
405 sizeof (jack_shm_registry[index].id));
408 void
409 jack_release_shm_info (jack_shm_registry_index_t index)
411 #ifdef WIN32
412 int my_pid = _getpid();
413 #else
414 pid_t my_pid = getpid();
415 #endif
417 /* must NOT have the registry locked */
418 if (jack_shm_registry[index].allocator == my_pid) {
419 jack_shm_lock_registry ();
420 jack_release_shm_entry (index);
421 jack_shm_unlock_registry ();
425 /* Claim server_name for this process.
427 * returns 0 if successful
428 * EEXIST if server_name was already active for this user
429 * ENOSPC if server registration limit reached
430 * ENOMEM if unable to access shared memory registry
432 EXPORT int
433 jack_register_server (const char *server_name)
435 int i;
437 #ifdef WIN32
438 int my_pid = _getpid();
439 #else
440 pid_t my_pid = getpid();
441 #endif
443 jack_set_server_prefix (server_name);
445 if (jack_server_initialize_shm ())
446 return ENOMEM;
448 jack_shm_lock_registry ();
450 /* See if server_name already registered. Since server names
451 * are per-user, we register the unique server prefix string.
453 for (i = 0; i < MAX_SERVERS; i++) {
455 if (strncmp (jack_shm_header->server[i].name,
456 jack_shm_server_prefix,
457 JACK_SERVER_NAME_SIZE) != 0)
458 continue; /* no match */
460 if (jack_shm_header->server[i].pid == my_pid)
461 return 0; /* it's me */
463 /* see if server still exists */
464 #ifndef WIN32 // steph TO CHECK
465 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
466 return EEXIST; /* other server running */
468 #endif
470 /* it's gone, reclaim this entry */
471 memset (&jack_shm_header->server[i], 0,
472 sizeof (jack_shm_server_t));
475 /* find a free entry */
476 for (i = 0; i < MAX_SERVERS; i++) {
477 if (jack_shm_header->server[i].pid == 0)
478 break;
481 if (i >= MAX_SERVERS)
482 return ENOSPC; /* out of space */
484 /* claim it */
485 jack_shm_header->server[i].pid = my_pid;
486 strncpy (jack_shm_header->server[i].name,
487 jack_shm_server_prefix,
488 JACK_SERVER_NAME_SIZE);
490 jack_shm_unlock_registry ();
491 return 0;
494 /* release server_name registration */
495 EXPORT void
496 jack_unregister_server (const char *server_name /* unused */)
498 int i;
500 #ifdef WIN32
501 int my_pid = _getpid();
502 #else
503 pid_t my_pid = getpid();
504 #endif
506 jack_shm_lock_registry ();
508 for (i = 0; i < MAX_SERVERS; i++) {
509 if (jack_shm_header->server[i].pid == my_pid) {
510 memset (&jack_shm_header->server[i], 0,
511 sizeof (jack_shm_server_t));
515 jack_shm_unlock_registry ();
518 /* called for server startup and termination */
519 EXPORT int
520 jack_cleanup_shm ()
522 int i;
523 int destroy;
524 jack_shm_info_t copy;
526 #ifdef WIN32
527 int my_pid = _getpid();
528 #else
529 pid_t my_pid = getpid();
530 #endif
532 jack_shm_lock_registry ();
534 for (i = 0; i < MAX_SHM_ID; i++) {
535 jack_shm_registry_t* r;
537 r = &jack_shm_registry[i];
538 memcpy (&copy, r, sizeof (jack_shm_info_t));
539 destroy = FALSE;
541 /* ignore unused entries */
542 if (r->allocator == 0)
543 continue;
545 /* is this my shm segment? */
546 if (r->allocator == my_pid) {
548 /* allocated by this process, so unattach
549 and destroy. */
550 jack_release_shm (&copy);
551 destroy = TRUE;
553 } else {
555 /* see if allocator still exists */
556 #ifdef WIN32 // steph
557 printf("TODO: kill API not available !!\n");
558 #else
559 if (kill (r->allocator, 0)) {
560 if (errno == ESRCH) {
561 /* allocator no longer exists,
562 * so destroy */
563 destroy = TRUE;
566 #endif
569 if (destroy) {
571 int index = copy.index;
573 if ((index >= 0) && (index < MAX_SHM_ID)) {
574 jack_remove_shm (&jack_shm_registry[index].id);
575 jack_release_shm_entry (index);
577 r->size = 0;
578 r->allocator = 0;
582 jack_shm_unlock_registry ();
583 return TRUE;
586 /* resize a shared memory segment
588 * There is no way to resize a System V shm segment. Resizing is
589 * possible with POSIX shm, but not with the non-conformant Mac OS X
590 * implementation. Since POSIX shm is mainly used on that platform,
591 * it's simpler to treat them both the same.
593 * So, we always resize by deleting and reallocating. This is
594 * tricky, because the old segment will not disappear until
595 * all the clients have released it. We only do what we can
596 * from here.
598 * This is not done under a single lock. I don't even want to think
599 * about all the things that could possibly go wrong if multple
600 * processes tried to resize the same segment concurrently. That
601 * probably doesn't happen.
604 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
606 jack_shm_id_t id;
608 /* The underlying type of `id' differs for SYSV and POSIX */
609 memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
611 jack_release_shm (si);
612 jack_destroy_shm (si);
614 if (jack_shmalloc ((char *) id, size, si)) {
615 return -1;
618 return jack_attach_shm (si);
621 #ifdef USE_POSIX_SHM
623 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
624 * POSIX interface-dependent functions
625 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
627 /* gain addressability to existing SHM registry segment
629 * sets up global registry pointers, if successful
631 * returns: 0 if existing registry accessed successfully
632 * ENOENT if registry does not exist
633 * EINVAL if registry exists, but has the wrong size
635 static int
636 jack_access_registry (jack_shm_info_t *ri)
638 /* registry must be locked */
639 int shm_fd;
641 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
643 /* try to open an existing segment */
644 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
645 int rc = errno;
646 if (errno != ENOENT) {
647 jack_error ("Cannot open existing shm registry segment"
648 " (%s)", strerror (errno));
650 close (shm_fd);
651 return rc;
654 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
655 PROT_READ|PROT_WRITE,
656 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
657 jack_error ("Cannot mmap shm registry segment (%s)",
658 strerror (errno));
659 close (shm_fd);
660 return EINVAL;
663 /* set up global pointers */
664 ri->index = JACK_SHM_REGISTRY_INDEX;
665 jack_shm_header = ri->attached_at;
666 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
668 close (shm_fd); // steph
669 return 0;
672 /* create a new SHM registry segment
674 * sets up global registry pointers, if successful
676 * returns: 0 if registry created successfully
677 * nonzero error code if unable to allocate a new registry
679 static int
680 jack_create_registry (jack_shm_info_t *ri)
682 /* registry must be locked */
683 int shm_fd;
685 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
687 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
688 int rc = errno;
689 jack_error ("Cannot create shm registry segment (%s)",
690 strerror (errno));
691 return rc;
694 /* Set the desired segment size. NOTE: the non-conformant Mac
695 * OS X POSIX shm only allows ftruncate() on segment creation.
697 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
698 int rc = errno;
699 jack_error ("Cannot set registry size (%s)", strerror (errno));
700 jack_remove_shm (&registry_id);
701 close (shm_fd);
702 return rc;
705 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
706 PROT_READ|PROT_WRITE,
707 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
708 jack_error ("Cannot mmap shm registry segment (%s)",
709 strerror (errno));
710 jack_remove_shm (&registry_id);
711 close (shm_fd);
712 return EINVAL;
715 /* set up global pointers */
716 ri->index = JACK_SHM_REGISTRY_INDEX;
717 jack_shm_header = ri->attached_at;
718 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
720 /* initialize registry contents */
721 jack_shm_init_registry ();
722 close (shm_fd); // steph
723 return 0;
726 static void
727 jack_remove_shm (jack_shm_id_t *id)
729 /* registry may or may not be locked */
730 shm_unlink ((char *) id);
733 void
734 jack_release_shm (jack_shm_info_t* si)
736 /* registry may or may not be locked */
737 if (si->attached_at != MAP_FAILED) {
738 munmap (si->attached_at, jack_shm_registry[si->index].size);
742 /* allocate a POSIX shared memory segment */
744 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
746 jack_shm_registry_t* registry;
747 int shm_fd;
748 int rc = -1;
749 char name[SHM_NAME_MAX+1];
751 jack_shm_lock_registry ();
753 if ((registry = jack_get_free_shm_info ()) == NULL) {
754 jack_error ("shm registry full");
755 goto unlock;
758 /* On Mac OS X, the maximum length of a shared memory segment
759 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
760 * defined by the standard). Unfortunately, Apple sets this
761 * value so small (about 31 bytes) that it is useless for
762 * actual names. So, we construct a short name from the
763 * registry index for uniqueness and ignore the shm_name
764 * parameter. Bah!
766 snprintf (name, sizeof (name), "/jack-%d", registry->index);
768 if (strlen (name) >= sizeof (registry->id)) {
769 jack_error ("shm segment name too long %s", name);
770 goto unlock;
773 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
774 jack_error ("Cannot create shm segment %s (%s)",
775 name, strerror (errno));
776 goto unlock;
779 if (ftruncate (shm_fd, size) < 0) {
780 jack_error ("Cannot set size of engine shm "
781 "registry 0 (%s)",
782 strerror (errno));
783 close (shm_fd);
784 goto unlock;
787 close (shm_fd);
788 registry->size = size;
789 strncpy (registry->id, name, sizeof (registry->id));
790 registry->allocator = getpid();
791 si->index = registry->index;
792 si->attached_at = MAP_FAILED; /* not attached */
793 rc = 0; /* success */
795 unlock:
796 jack_shm_unlock_registry ();
797 return rc;
801 jack_attach_shm (jack_shm_info_t* si)
803 int shm_fd;
804 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
806 if ((shm_fd = shm_open (registry->id,
807 O_RDWR, 0666)) < 0) {
808 jack_error ("Cannot open shm segment %s (%s)", registry->id,
809 strerror (errno));
810 return -1;
813 if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
814 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
815 jack_error ("Cannot mmap shm segment %s (%s)",
816 registry->id,
817 strerror (errno));
818 close (shm_fd);
819 return -1;
822 close (shm_fd);
823 return 0;
827 jack_attach_shm_read (jack_shm_info_t* si)
829 int shm_fd;
830 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
832 if ((shm_fd = shm_open (registry->id,
833 O_RDONLY, 0666)) < 0) {
834 jack_error ("Cannot open shm segment %s (%s)", registry->id,
835 strerror (errno));
836 return -1;
839 if ((si->attached_at = mmap (0, registry->size, PROT_READ,
840 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
841 jack_error ("Cannot mmap shm segment %s (%s)",
842 registry->id,
843 strerror (errno));
844 close (shm_fd);
845 return -1;
848 close (shm_fd);
849 return 0;
852 #elif WIN32
854 static int
855 jack_access_registry (jack_shm_info_t *ri)
857 /* registry must be locked */
858 HANDLE shm_fd;
859 LPSECURITY_ATTRIBUTES sec = 0;
861 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
863 /* try to open an existing segment */
865 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
866 int rc = GetLastError();
867 if (rc != ERROR_FILE_NOT_FOUND) {
868 jack_error ("Cannot open existing shm registry segment (%ld)", rc);
870 return rc;
873 if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
874 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
875 jack_remove_shm (&registry_id);
876 CloseHandle (shm_fd);
877 return EINVAL;
880 /* set up global pointers */
881 ri->index = JACK_SHM_REGISTRY_INDEX;
882 jack_shm_header = ri->attached_at;
883 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
885 //CloseHandle(shm_fd); // TO CHECK
886 return 0;
889 static int
890 jack_create_registry (jack_shm_info_t *ri)
892 /* registry must be locked */
893 HANDLE shm_fd;
895 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
897 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
898 0, PAGE_READWRITE,
899 0, JACK_SHM_REGISTRY_SIZE,
900 registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
901 int rc = GetLastError();
902 jack_error ("Cannot create shm registry segment (%ld)", rc);
903 return rc;
906 if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
907 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
908 jack_remove_shm (&registry_id);
909 CloseHandle (shm_fd);
910 return EINVAL;
913 /* set up global pointers */
914 ri->index = JACK_SHM_REGISTRY_INDEX;
915 jack_shm_header = ri->attached_at;
916 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
918 /* initialize registry contents */
919 jack_shm_init_registry ();
921 //CloseHandle(shm_fd); // TO CHECK
922 return 0;
925 static void
926 jack_remove_shm (jack_shm_id_t *id)
928 /* nothing to do */
931 void
932 jack_release_shm (jack_shm_info_t* si)
934 /* registry may or may not be locked */
935 if (si->attached_at != NULL) {
936 UnmapViewOfFile (si->attached_at);
941 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
943 jack_shm_registry_t* registry;
944 HANDLE shm_fd;
945 int rc = -1;
946 char name[SHM_NAME_MAX+1];
948 jack_shm_lock_registry ();
950 if ((registry = jack_get_free_shm_info ()) == NULL) {
951 jack_error ("shm registry full");
952 goto unlock;
955 snprintf (name, sizeof (name), "jack-%d", registry->index);
957 if (strlen (name) >= sizeof (registry->id)) {
958 jack_error ("shm segment name too long %s", name);
959 goto unlock;
962 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
963 0, PAGE_READWRITE,
964 0, size,
965 name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
966 int rc = GetLastError();
967 jack_error ("Cannot create shm segment (%ld)",rc);
968 goto unlock;
971 //CloseHandle (shm_fd); // TO CHECK
973 registry->size = size;
974 strncpy (registry->id, name, sizeof (registry->id));
975 registry->allocator = _getpid();
976 si->index = registry->index;
977 si->attached_at = NULL; /* not attached */
978 rc = 0; /* success */
980 unlock:
981 jack_shm_unlock_registry ();
982 return rc;
986 jack_attach_shm (jack_shm_info_t* si)
988 HANDLE shm_fd;
989 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
991 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
992 int rc = GetLastError();
993 jack_error ("Cannot open shm segment (%ld)",rc);
994 return -1;
997 if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
998 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
999 jack_remove_shm (&registry_id);
1000 CloseHandle (shm_fd);
1001 return -1;
1004 //CloseHandle (shm_fd); // TO CHECK
1005 return 0;
1009 jack_attach_shm_read (jack_shm_info_t* si)
1011 HANDLE shm_fd;
1012 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1014 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1015 int rc = GetLastError();
1016 jack_error ("Cannot open shm segment (%ld)",rc);
1017 return -1;
1020 if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
1021 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
1022 jack_remove_shm (&registry_id);
1023 CloseHandle (shm_fd);
1024 return -1;
1027 //CloseHandle (shm_fd); // TO CHECK
1028 return 0;
1031 #else
1033 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1034 * System V interface-dependent functions
1035 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1037 /* gain addressability to existing SHM registry segment
1039 * sets up global registry pointers, if successful
1041 * returns: 0 if existing registry accessed successfully
1042 * ENOENT if registry does not exist
1043 * EINVAL if registry exists, but has the wrong size
1044 * other nonzero error code if unable to access registry
1046 static int
1047 jack_access_registry (jack_shm_info_t *ri)
1049 /* registry must be locked */
1051 /* try without IPC_CREAT to get existing segment */
1052 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1053 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
1055 switch (errno) {
1057 case ENOENT: /* segment does not exist */
1058 return ENOENT;
1060 case EINVAL: /* segment exists, but too small */
1061 /* attempt minimum size access */
1062 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
1063 return EINVAL;
1065 default: /* or other error */
1066 jack_error ("unable to access shm registry (%s)",
1067 strerror (errno));
1068 return errno;
1072 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
1073 jack_error ("Cannot attach shm registry segment (%s)",
1074 strerror (errno));
1075 return EINVAL;
1078 /* set up global pointers */
1079 ri->index = JACK_SHM_REGISTRY_INDEX;
1080 jack_shm_header = ri->attached_at;
1081 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1082 return 0;
1085 /* create a new SHM registry segment
1087 * sets up global registry pointers, if successful
1089 * returns: 0 if registry created successfully
1090 * nonzero error code if unable to allocate a new registry
1092 static int
1093 jack_create_registry (jack_shm_info_t *ri)
1095 /* registry must be locked */
1096 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1097 JACK_SHM_REGISTRY_SIZE,
1098 0666|IPC_CREAT)) < 0) {
1099 jack_error ("Cannot create shm registry segment (%s)",
1100 strerror (errno));
1101 return errno;
1104 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
1105 jack_error ("Cannot attach shm registry segment (%s)",
1106 strerror (errno));
1107 return EINVAL;
1110 /* set up global pointers */
1111 ri->index = JACK_SHM_REGISTRY_INDEX;
1112 jack_shm_header = ri->attached_at;
1113 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1115 /* initialize registry contents */
1116 jack_shm_init_registry ();
1117 return 0;
1120 static void
1121 jack_remove_shm (jack_shm_id_t *id)
1123 /* registry may or may not be locked */
1124 shmctl (*id, IPC_RMID, NULL);
1127 void
1128 jack_release_shm (jack_shm_info_t* si)
1130 /* registry may or may not be locked */
1131 if (si->attached_at != MAP_FAILED) {
1132 shmdt (si->attached_at);
1137 jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
1138 jack_shm_info_t* si)
1140 int shmflags;
1141 int shmid;
1142 int rc = -1;
1143 jack_shm_registry_t* registry;
1145 jack_shm_lock_registry ();
1147 if ((registry = jack_get_free_shm_info ())) {
1149 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
1151 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
1153 registry->size = size;
1154 registry->id = shmid;
1155 registry->allocator = getpid();
1156 si->index = registry->index;
1157 si->attached_at = MAP_FAILED; /* not attached */
1158 rc = 0;
1160 } else {
1161 jack_error ("Cannot create shm segment %s (%s)",
1162 name_not_used, strerror (errno));
1166 jack_shm_unlock_registry ();
1167 return rc;
1171 jack_attach_shm (jack_shm_info_t* si)
1173 if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
1174 jack_error ("Cannot attach shm segment (%s)",
1175 strerror (errno));
1176 jack_release_shm_info (si->index);
1177 return -1;
1179 return 0;
1182 #endif /* !USE_POSIX_SHM */