Update OSX install script.
[jack2.git] / common / shm.c
blobfdd3b15130ef9a157c2ba2667ed360285e8fcd35
1 /*
2 * Copyright (C) 2003 Paul Davis
3 * Copyright (C) 2004 Jack O'Quin
4 * Copyright (C) 2006-2007 Grame
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* This module provides a set of abstract shared memory interfaces
23 * with support using both System V and POSIX shared memory
24 * implementations. The code is divided into three sections:
26 * - common (interface-independent) code
27 * - POSIX implementation
28 * - System V implementation
30 * The implementation used is determined by whether USE_POSIX_SHM was
31 * set in the ./configure step.
34 #include "JackConstants.h"
36 #ifdef WIN32
37 #include <process.h>
38 #include <stdio.h>
39 #else
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <signal.h>
46 #include <limits.h>
47 #include <errno.h>
48 #include <dirent.h>
49 #include <sys/mman.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/shm.h>
53 #include <sys/sem.h>
54 #include <stdlib.h>
56 #endif
58 #include "shm.h"
59 #include "JackError.h"
61 static int GetUID()
63 #ifdef WIN32
64 return _getpid();
65 //#error "No getuid function available"
66 #else
67 return getuid();
68 #endif
71 static int GetPID()
73 #ifdef WIN32
74 return _getpid();
75 #else
76 return getpid();
77 #endif
80 #ifdef USE_POSIX_SHM
81 static jack_shmtype_t jack_shmtype = shm_POSIX;
82 #elif WIN32
83 static jack_shmtype_t jack_shmtype = shm_WIN32;
84 #else
85 static jack_shmtype_t jack_shmtype = shm_SYSV;
86 #endif
88 /* interface-dependent forward declarations */
89 static int jack_access_registry (jack_shm_info_t *ri);
90 static int jack_create_registry (jack_shm_info_t *ri);
91 static void jack_remove_shm (jack_shm_id_t *id);
93 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
94 * common interface-independent section
95 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
97 /* The JACK SHM registry is a chunk of memory for keeping track of the
98 * shared memory used by each active JACK server. This allows the
99 * server to clean up shared memory when it exits. To avoid memory
100 * leakage due to kill -9, crashes or debugger-driven exits, this
101 * cleanup is also done when a new instance of that server starts.
104 /* per-process global data for the SHM interfaces */
105 static jack_shm_id_t registry_id; /* SHM id for the registry */
107 #ifdef WIN32
108 static jack_shm_info_t registry_info = {/* SHM info for the registry */
109 JACK_SHM_NULL_INDEX,
110 NULL
112 #else
113 static jack_shm_info_t registry_info = { /* SHM info for the registry */
114 .index = JACK_SHM_NULL_INDEX,
115 .ptr.attached_at = MAP_FAILED
117 #endif
119 /* pointers to registry header and array */
120 static jack_shm_header_t *jack_shm_header = NULL;
121 static jack_shm_registry_t *jack_shm_registry = NULL;
122 static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
124 /* jack_shm_lock_registry() serializes updates to the shared memory
125 * segment JACK uses to keep track of the SHM segments allocated to
126 * all its processes, including multiple servers.
128 * This is not a high-contention lock, but it does need to work across
129 * multiple processes. High transaction rates and realtime safety are
130 * not required. Any solution needs to at least be portable to POSIX
131 * and POSIX-like systems.
133 * We must be particularly careful to ensure that the lock be released
134 * if the owning process terminates abnormally. Otherwise, a segfault
135 * or kill -9 at the wrong moment could prevent JACK from ever running
136 * again on that machine until after a reboot.
139 #define JACK_SEMAPHORE_KEY 0x282929
140 #ifndef USE_POSIX_SHM
141 #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
142 #endif
144 static int semid = -1;
146 #ifdef WIN32
148 static void
149 semaphore_init () {}
151 static void
152 semaphore_add (int value) {}
154 #else
155 /* all semaphore errors are fatal -- issue message, but do not return */
156 static void
157 semaphore_error (char *msg)
159 jack_error ("Fatal JACK semaphore error: %s (%s)",
160 msg, strerror (errno));
161 abort ();
164 static void
165 semaphore_init ()
167 key_t semkey = JACK_SEMAPHORE_KEY;
168 struct sembuf sbuf;
169 int create_flags = IPC_CREAT | IPC_EXCL
170 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
172 /* Get semaphore ID associated with this key. */
173 if ((semid = semget(semkey, 0, 0)) == -1) {
175 /* Semaphore does not exist - Create. */
176 if ((semid = semget(semkey, 1, create_flags)) != -1) {
178 /* Initialize the semaphore, allow one owner. */
179 sbuf.sem_num = 0;
180 sbuf.sem_op = 1;
181 sbuf.sem_flg = 0;
182 if (semop(semid, &sbuf, 1) == -1) {
183 semaphore_error ("semop");
186 } else if (errno == EEXIST) {
187 if ((semid = semget(semkey, 0, 0)) == -1) {
188 semaphore_error ("semget");
191 } else {
192 semaphore_error ("semget creation");
197 static inline void
198 semaphore_add (int value)
200 struct sembuf sbuf;
202 sbuf.sem_num = 0;
203 sbuf.sem_op = value;
204 sbuf.sem_flg = SEM_UNDO;
205 if (semop(semid, &sbuf, 1) == -1) {
206 semaphore_error ("semop");
210 #endif
212 static void
213 jack_shm_lock_registry (void)
215 if (semid == -1)
216 semaphore_init ();
218 semaphore_add (-1);
221 static void
222 jack_shm_unlock_registry (void)
224 semaphore_add (1);
227 static void
228 jack_shm_init_registry ()
230 /* registry must be locked */
231 int i;
233 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
235 jack_shm_header->magic = JACK_SHM_MAGIC;
236 //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
237 jack_shm_header->type = jack_shmtype;
238 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
239 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
240 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
242 for (i = 0; i < MAX_SHM_ID; ++i) {
243 jack_shm_registry[i].index = i;
247 static int
248 jack_shm_validate_registry ()
250 /* registry must be locked */
252 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
253 //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
254 && (jack_shm_header->type == jack_shmtype)
255 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
256 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
257 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
259 return 0; /* registry OK */
262 return -1;
265 /* set a unique per-user, per-server shm prefix string
267 * According to the POSIX standard:
269 * "The name argument conforms to the construction rules for a
270 * pathname. If name begins with the slash character, then processes
271 * calling shm_open() with the same value of name refer to the same
272 * shared memory object, as long as that name has not been
273 * removed. If name does not begin with the slash character, the
274 * effect is implementation-defined. The interpretation of slash
275 * characters other than the leading slash character in name is
276 * implementation-defined."
278 * Since the Linux implementation does not allow slashes *within* the
279 * name, in the interest of portability we use colons instead.
281 static void
282 jack_set_server_prefix (const char *server_name)
284 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
285 "jack-%d:%s:", GetUID(), server_name);
288 /* gain server addressability to shared memory registration segment
290 * returns: 0 if successful
292 static int
293 jack_server_initialize_shm (int new_registry)
295 int rc;
297 if (jack_shm_header)
298 return 0; /* already initialized */
300 jack_shm_lock_registry ();
302 rc = jack_access_registry (&registry_info);
304 if (new_registry) {
305 jack_remove_shm (&registry_id);
306 rc = ENOENT;
309 switch (rc) {
310 case ENOENT: /* registry does not exist */
311 rc = jack_create_registry (&registry_info);
312 break;
313 case 0: /* existing registry */
314 if (jack_shm_validate_registry () == 0)
315 break;
316 /* else it was invalid, so fall through */
317 case EINVAL: /* bad registry */
318 /* Apparently, this registry was created by an older
319 * JACK version. Delete it so we can try again. */
320 jack_release_shm (&registry_info);
321 jack_remove_shm (&registry_id);
322 if ((rc = jack_create_registry (&registry_info)) != 0) {
323 jack_error ("incompatible shm registry (%s)",
324 strerror (errno));
325 #ifndef USE_POSIX_SHM
326 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
327 JACK_SHM_REGISTRY_KEY);
328 #endif
330 break;
331 default: /* failure return code */
332 break;
335 jack_shm_unlock_registry ();
336 return rc;
339 /* gain client addressability to shared memory registration segment
341 * NOTE: this function is no longer used for server initialization,
342 * instead it calls jack_register_server().
344 * returns: 0 if successful
347 jack_initialize_shm (const char *server_name)
349 int rc;
351 if (jack_shm_header)
352 return 0; /* already initialized */
354 jack_set_server_prefix (server_name);
356 jack_shm_lock_registry ();
357 if ((rc = jack_access_registry (&registry_info)) == 0) {
358 if ((rc = jack_shm_validate_registry ()) != 0) {
359 jack_error ("Incompatible shm registry, "
360 "are jackd and libjack in sync?");
363 jack_shm_unlock_registry ();
365 return rc;
369 char* jack_shm_addr (jack_shm_info_t* si)
371 return (char*)si->ptr.attached_at;
374 void
375 jack_destroy_shm (jack_shm_info_t* si)
377 /* must NOT have the registry locked */
378 if (si->index == JACK_SHM_NULL_INDEX)
379 return; /* segment not allocated */
381 jack_remove_shm (&jack_shm_registry[si->index].id);
382 jack_release_shm_info (si->index);
385 jack_shm_registry_t *
386 jack_get_free_shm_info ()
388 /* registry must be locked */
389 jack_shm_registry_t* si = NULL;
390 int i;
392 for (i = 0; i < MAX_SHM_ID; ++i) {
393 if (jack_shm_registry[i].size == 0) {
394 break;
398 if (i < MAX_SHM_ID) {
399 si = &jack_shm_registry[i];
402 return si;
405 static void
406 jack_release_shm_entry (jack_shm_registry_index_t index)
408 /* the registry must be locked */
409 jack_shm_registry[index].size = 0;
410 jack_shm_registry[index].allocator = 0;
411 memset (&jack_shm_registry[index].id, 0,
412 sizeof (jack_shm_registry[index].id));
415 void
416 jack_release_shm_info (jack_shm_registry_index_t index)
418 /* must NOT have the registry locked */
419 if (jack_shm_registry[index].allocator == GetPID()) {
420 jack_shm_lock_registry ();
421 jack_release_shm_entry (index);
422 jack_shm_unlock_registry ();
426 /* Claim server_name for this process.
428 * returns 0 if successful
429 * EEXIST if server_name was already active for this user
430 * ENOSPC if server registration limit reached
431 * ENOMEM if unable to access shared memory registry
434 jack_register_server (const char *server_name, int new_registry)
436 int i, res = 0;
438 jack_set_server_prefix (server_name);
440 if (jack_server_initialize_shm (new_registry))
441 return ENOMEM;
443 jack_shm_lock_registry ();
445 /* See if server_name already registered. Since server names
446 * are per-user, we register the unique server prefix string.
448 for (i = 0; i < MAX_SERVERS; i++) {
450 if (strncmp (jack_shm_header->server[i].name,
451 jack_shm_server_prefix,
452 JACK_SERVER_NAME_SIZE) != 0)
453 continue; /* no match */
455 if (jack_shm_header->server[i].pid == GetPID()){
456 res = 0; /* it's me */
457 goto unlock;
460 /* see if server still exists */
461 #ifndef WIN32 // steph TO CHECK
462 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
463 res = EEXIST; /* other server running */
464 goto unlock;
466 #endif
468 /* it's gone, reclaim this entry */
469 memset (&jack_shm_header->server[i], 0,
470 sizeof (jack_shm_server_t));
473 /* find a free entry */
474 for (i = 0; i < MAX_SERVERS; i++) {
475 if (jack_shm_header->server[i].pid == 0)
476 break;
479 if (i >= MAX_SERVERS){
480 res = ENOSPC; /* out of space */
481 goto unlock;
484 /* claim it */
485 jack_shm_header->server[i].pid = GetPID();
486 strncpy (jack_shm_header->server[i].name,
487 jack_shm_server_prefix,
488 JACK_SERVER_NAME_SIZE);
490 unlock:
491 jack_shm_unlock_registry ();
492 return 0;
495 /* release server_name registration */
496 void
497 jack_unregister_server (const char *server_name /* unused */)
499 int i;
500 jack_shm_lock_registry ();
502 for (i = 0; i < MAX_SERVERS; i++) {
503 if (jack_shm_header->server[i].pid == GetPID()) {
504 memset (&jack_shm_header->server[i], 0,
505 sizeof (jack_shm_server_t));
509 jack_shm_unlock_registry ();
512 /* called for server startup and termination */
514 jack_cleanup_shm ()
516 int i;
517 int destroy;
518 jack_shm_info_t copy;
520 jack_shm_lock_registry ();
522 for (i = 0; i < MAX_SHM_ID; i++) {
523 jack_shm_registry_t* r;
525 r = &jack_shm_registry[i];
526 memcpy (&copy, r, sizeof (jack_shm_info_t));
527 destroy = FALSE;
529 /* ignore unused entries */
530 if (r->allocator == 0)
531 continue;
533 /* is this my shm segment? */
534 if (r->allocator == GetPID()) {
536 /* allocated by this process, so unattach
537 and destroy. */
538 jack_release_shm (&copy);
539 destroy = TRUE;
541 } else {
543 /* see if allocator still exists */
544 #ifdef WIN32 // steph
545 jack_info("TODO: kill API not available !!");
546 #else
547 if (kill (r->allocator, 0)) {
548 if (errno == ESRCH) {
549 /* allocator no longer exists,
550 * so destroy */
551 destroy = TRUE;
554 #endif
557 if (destroy) {
559 int index = copy.index;
561 if ((index >= 0) && (index < MAX_SHM_ID)) {
562 jack_remove_shm (&jack_shm_registry[index].id);
563 jack_release_shm_entry (index);
565 r->size = 0;
566 r->allocator = 0;
570 jack_shm_unlock_registry ();
571 return TRUE;
574 /* resize a shared memory segment
576 * There is no way to resize a System V shm segment. Resizing is
577 * possible with POSIX shm, but not with the non-conformant Mac OS X
578 * implementation. Since POSIX shm is mainly used on that platform,
579 * it's simpler to treat them both the same.
581 * So, we always resize by deleting and reallocating. This is
582 * tricky, because the old segment will not disappear until
583 * all the clients have released it. We only do what we can
584 * from here.
586 * This is not done under a single lock. I don't even want to think
587 * about all the things that could possibly go wrong if multple
588 * processes tried to resize the same segment concurrently. That
589 * probably doesn't happen.
592 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
594 jack_shm_id_t id;
596 /* The underlying type of `id' differs for SYSV and POSIX */
597 memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
599 jack_release_shm (si);
600 jack_destroy_shm (si);
602 if (jack_shmalloc ((char *) id, size, si)) {
603 return -1;
606 return jack_attach_shm (si);
609 #ifdef USE_POSIX_SHM
611 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
612 * POSIX interface-dependent functions
613 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
615 /* gain addressability to existing SHM registry segment
617 * sets up global registry pointers, if successful
619 * returns: 0 if existing registry accessed successfully
620 * ENOENT if registry does not exist
621 * EINVAL if registry exists, but has the wrong size
623 static int
624 jack_access_registry (jack_shm_info_t *ri)
626 /* registry must be locked */
627 int shm_fd;
629 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
631 /* try to open an existing segment */
632 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
633 int rc = errno;
634 if (errno != ENOENT) {
635 jack_error ("Cannot open existing shm registry segment"
636 " (%s)", strerror (errno));
638 close (shm_fd);
639 return rc;
642 if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
643 PROT_READ|PROT_WRITE,
644 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
645 jack_error ("Cannot mmap shm registry segment (%s)",
646 strerror (errno));
647 close (shm_fd);
648 return EINVAL;
651 /* set up global pointers */
652 ri->index = JACK_SHM_REGISTRY_INDEX;
653 jack_shm_header = ri->ptr.attached_at;
654 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
656 close (shm_fd); // steph
657 return 0;
660 /* create a new SHM registry segment
662 * sets up global registry pointers, if successful
664 * returns: 0 if registry created successfully
665 * nonzero error code if unable to allocate a new registry
667 static int
668 jack_create_registry (jack_shm_info_t *ri)
670 /* registry must be locked */
671 int shm_fd;
673 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
675 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
676 int rc = errno;
677 jack_error ("Cannot create shm registry segment (%s)",
678 strerror (errno));
679 return rc;
682 /* Previous shm_open result depends of the actual value of umask, force correct file permisssion here */
683 if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
684 jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
687 /* Set the desired segment size. NOTE: the non-conformant Mac
688 * OS X POSIX shm only allows ftruncate() on segment creation.
690 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
691 int rc = errno;
692 jack_error ("Cannot set registry size (%s)", strerror (errno));
693 jack_remove_shm (&registry_id);
694 close (shm_fd);
695 return rc;
698 if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
699 PROT_READ|PROT_WRITE,
700 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
701 jack_error ("Cannot mmap shm registry segment (%s)",
702 strerror (errno));
703 jack_remove_shm (&registry_id);
704 close (shm_fd);
705 return EINVAL;
708 /* set up global pointers */
709 ri->index = JACK_SHM_REGISTRY_INDEX;
710 jack_shm_header = ri->ptr.attached_at;
711 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
713 /* initialize registry contents */
714 jack_shm_init_registry ();
715 close (shm_fd); // steph
716 return 0;
719 static void
720 jack_remove_shm (jack_shm_id_t *id)
722 /* registry may or may not be locked */
723 shm_unlink ((char *) id);
726 void
727 jack_release_shm (jack_shm_info_t* si)
729 /* registry may or may not be locked */
730 if (si->ptr.attached_at != MAP_FAILED) {
731 munmap (si->ptr.attached_at, jack_shm_registry[si->index].size);
735 /* allocate a POSIX shared memory segment */
737 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
739 jack_shm_registry_t* registry;
740 int shm_fd;
741 int rc = -1;
742 char name[SHM_NAME_MAX+1];
744 jack_shm_lock_registry ();
746 if ((registry = jack_get_free_shm_info ()) == NULL) {
747 jack_error ("shm registry full");
748 goto unlock;
751 /* On Mac OS X, the maximum length of a shared memory segment
752 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
753 * defined by the standard). Unfortunately, Apple sets this
754 * value so small (about 31 bytes) that it is useless for
755 * actual names. So, we construct a short name from the
756 * registry index for uniqueness and ignore the shm_name
757 * parameter. Bah!
759 snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index);
761 if (strlen (name) >= sizeof (registry->id)) {
762 jack_error ("shm segment name too long %s", name);
763 goto unlock;
766 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
767 jack_error ("Cannot create shm segment %s (%s)",
768 name, strerror (errno));
769 goto unlock;
772 if (ftruncate (shm_fd, size) < 0) {
773 jack_error ("Cannot set size of engine shm "
774 "registry 0 (%s)",
775 strerror (errno));
776 close (shm_fd);
777 goto unlock;
780 close (shm_fd);
781 registry->size = size;
782 strncpy (registry->id, name, sizeof (registry->id));
783 registry->allocator = getpid();
784 si->index = registry->index;
785 si->ptr.attached_at = MAP_FAILED; /* not attached */
786 rc = 0; /* success */
788 unlock:
789 jack_shm_unlock_registry ();
790 return rc;
794 jack_attach_shm (jack_shm_info_t* si)
796 int shm_fd;
797 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
799 if ((shm_fd = shm_open (registry->id,
800 O_RDWR, 0666)) < 0) {
801 jack_error ("Cannot open shm segment %s (%s)", registry->id,
802 strerror (errno));
803 return -1;
806 if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
807 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
808 jack_error ("Cannot mmap shm segment %s (%s)",
809 registry->id,
810 strerror (errno));
811 close (shm_fd);
812 return -1;
815 close (shm_fd);
816 return 0;
820 jack_attach_shm_read (jack_shm_info_t* si)
822 int shm_fd;
823 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
825 if ((shm_fd = shm_open (registry->id,
826 O_RDONLY, 0666)) < 0) {
827 jack_error ("Cannot open shm segment %s (%s)", registry->id,
828 strerror (errno));
829 return -1;
832 if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ,
833 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
834 jack_error ("Cannot mmap shm segment %s (%s)",
835 registry->id,
836 strerror (errno));
837 close (shm_fd);
838 return -1;
841 close (shm_fd);
842 return 0;
845 #elif WIN32
847 static int
848 jack_access_registry (jack_shm_info_t *ri)
850 /* registry must be locked */
851 HANDLE shm_fd;
852 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
854 /* try to open an existing segment */
856 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
857 int rc = GetLastError();
858 if (rc != ERROR_FILE_NOT_FOUND) {
859 jack_error ("Cannot open existing shm registry segment (%ld)", rc);
861 return rc;
864 if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
865 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
866 jack_remove_shm (&registry_id);
867 CloseHandle (shm_fd);
868 return EINVAL;
871 /* set up global pointers */
872 ri->index = JACK_SHM_REGISTRY_INDEX;
873 jack_shm_header = ri->ptr.attached_at;
874 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
876 //CloseHandle(shm_fd); // TO CHECK
877 return 0;
880 static int
881 jack_create_registry (jack_shm_info_t *ri)
883 /* registry must be locked */
884 HANDLE shm_fd;
886 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
888 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
889 0, PAGE_READWRITE,
890 0, JACK_SHM_REGISTRY_SIZE,
891 registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
892 int rc = GetLastError();
893 jack_error ("Cannot create shm registry segment (%ld)", rc);
894 return rc;
897 if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
898 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
899 jack_remove_shm (&registry_id);
900 CloseHandle (shm_fd);
901 return EINVAL;
904 /* set up global pointers */
905 ri->index = JACK_SHM_REGISTRY_INDEX;
906 jack_shm_header = ri->ptr.attached_at;
907 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
909 /* initialize registry contents */
910 jack_shm_init_registry ();
912 //CloseHandle(shm_fd); // TO CHECK
913 return 0;
916 static void
917 jack_remove_shm (jack_shm_id_t *id)
919 /* nothing to do */
922 void
923 jack_release_shm (jack_shm_info_t* si)
925 /* registry may or may not be locked */
926 if (si->ptr.attached_at != NULL) {
927 UnmapViewOfFile (si->ptr.attached_at);
932 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
934 jack_shm_registry_t* registry;
935 HANDLE shm_fd;
936 int rc = -1;
937 char name[SHM_NAME_MAX+1];
939 jack_shm_lock_registry ();
941 if ((registry = jack_get_free_shm_info ()) == NULL) {
942 jack_error ("shm registry full");
943 goto unlock;
946 snprintf (name, sizeof (name), "jack-%d-%d", GetUID(), registry->index);
948 if (strlen (name) >= sizeof (registry->id)) {
949 jack_error ("shm segment name too long %s", name);
950 goto unlock;
953 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
954 0, PAGE_READWRITE,
955 0, size,
956 name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
957 int rc = GetLastError();
958 jack_error ("Cannot create shm segment (%ld)",rc);
959 goto unlock;
962 //CloseHandle (shm_fd); // TO CHECK
964 registry->size = size;
965 strncpy (registry->id, name, sizeof (registry->id));
966 registry->allocator = _getpid();
967 si->index = registry->index;
968 si->ptr.attached_at = NULL; /* not attached */
969 rc = 0; /* success */
971 unlock:
972 jack_shm_unlock_registry ();
973 return rc;
977 jack_attach_shm (jack_shm_info_t* si)
979 HANDLE shm_fd;
980 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
982 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
983 int rc = GetLastError();
984 jack_error ("Cannot open shm segment (%ld)",rc);
985 return -1;
988 if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
989 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
990 jack_remove_shm (&registry_id);
991 CloseHandle (shm_fd);
992 return -1;
995 //CloseHandle (shm_fd); // TO CHECK
996 return 0;
1000 jack_attach_shm_read (jack_shm_info_t* si)
1002 HANDLE shm_fd;
1003 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1005 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1006 int rc = GetLastError();
1007 jack_error ("Cannot open shm segment (%ld)",rc);
1008 return -1;
1011 if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
1012 jack_error("Cannot mmap shm segment (%ld)", GetLastError());
1013 jack_remove_shm(&registry_id);
1014 CloseHandle(shm_fd);
1015 return -1;
1018 //CloseHandle (shm_fd); // TO CHECK
1019 return 0;
1022 #else
1024 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1025 * System V interface-dependent functions
1026 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1028 /* gain addressability to existing SHM registry segment
1030 * sets up global registry pointers, if successful
1032 * returns: 0 if existing registry accessed successfully
1033 * ENOENT if registry does not exist
1034 * EINVAL if registry exists, but has the wrong size
1035 * other nonzero error code if unable to access registry
1037 static int
1038 jack_access_registry (jack_shm_info_t *ri)
1040 /* registry must be locked */
1042 /* try without IPC_CREAT to get existing segment */
1043 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1044 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
1046 switch (errno) {
1048 case ENOENT: /* segment does not exist */
1049 return ENOENT;
1051 case EINVAL: /* segment exists, but too small */
1052 /* attempt minimum size access */
1053 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
1054 return EINVAL;
1056 default: /* or other error */
1057 jack_error ("unable to access shm registry (%s)",
1058 strerror (errno));
1059 return errno;
1063 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
1064 jack_error ("Cannot attach shm registry segment (%s)",
1065 strerror (errno));
1066 return EINVAL;
1069 /* set up global pointers */
1070 ri->index = JACK_SHM_REGISTRY_INDEX;
1071 jack_shm_header = ri->attached_at;
1072 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1073 return 0;
1076 /* create a new SHM registry segment
1078 * sets up global registry pointers, if successful
1080 * returns: 0 if registry created successfully
1081 * nonzero error code if unable to allocate a new registry
1083 static int
1084 jack_create_registry (jack_shm_info_t *ri)
1086 /* registry must be locked */
1087 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1088 JACK_SHM_REGISTRY_SIZE,
1089 0666|IPC_CREAT)) < 0) {
1090 jack_error ("Cannot create shm registry segment (%s)",
1091 strerror (errno));
1092 return errno;
1095 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
1096 jack_error ("Cannot attach shm registry segment (%s)",
1097 strerror (errno));
1098 return EINVAL;
1101 /* set up global pointers */
1102 ri->index = JACK_SHM_REGISTRY_INDEX;
1103 jack_shm_header = ri->attached_at;
1104 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1106 /* initialize registry contents */
1107 jack_shm_init_registry ();
1108 return 0;
1111 static void
1112 jack_remove_shm (jack_shm_id_t *id)
1114 /* registry may or may not be locked */
1115 shmctl (*id, IPC_RMID, NULL);
1118 void
1119 jack_release_shm (jack_shm_info_t* si)
1121 /* registry may or may not be locked */
1122 if (si->attached_at != MAP_FAILED) {
1123 shmdt (si->attached_at);
1128 jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
1129 jack_shm_info_t* si)
1131 int shmflags;
1132 int shmid;
1133 int rc = -1;
1134 jack_shm_registry_t* registry;
1136 jack_shm_lock_registry ();
1138 if ((registry = jack_get_free_shm_info ())) {
1140 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
1142 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
1144 registry->size = size;
1145 registry->id = shmid;
1146 registry->allocator = getpid();
1147 si->index = registry->index;
1148 si->attached_at = MAP_FAILED; /* not attached */
1149 rc = 0;
1151 } else {
1152 jack_error ("Cannot create shm segment %s (%s)",
1153 name_not_used, strerror (errno));
1157 jack_shm_unlock_registry ();
1158 return rc;
1162 jack_attach_shm (jack_shm_info_t* si)
1164 if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
1165 jack_error ("Cannot attach shm segment (%s)",
1166 strerror (errno));
1167 jack_release_shm_info (si->index);
1168 return -1;
1170 return 0;
1173 #endif /* !USE_POSIX_SHM */