Better isolation of server and clients system resources to allow starting the server...
[jack2.git] / common / shm.c
blob840699b117e89f2da9bb92c705bdbd5768355498
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
16 * Copyright (C) 2006-2007 Grame
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 #include "JackConstants.h"
36 #ifdef WIN32
37 #include <process.h>
38 #else
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <signal.h>
45 #include <limits.h>
46 #include <errno.h>
47 #include <dirent.h>
48 #include <sys/mman.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/shm.h>
52 #include <sys/sem.h>
53 #include <stdlib.h>
55 #endif
57 #include "shm.h"
58 #include "JackError.h"
60 static int GetUID()
62 #ifdef WIN32
63 return _getpid();
64 //#error "No getuid function available"
65 #else
66 return getuid();
67 #endif
71 #ifdef USE_POSIX_SHM
72 static jack_shmtype_t jack_shmtype = shm_POSIX;
73 #elif WIN32
74 static jack_shmtype_t jack_shmtype = shm_WIN32;
75 #else
76 static jack_shmtype_t jack_shmtype = shm_SYSV;
77 #endif
79 /* interface-dependent forward declarations */
80 static int jack_access_registry (jack_shm_info_t *ri);
81 static int jack_create_registry (jack_shm_info_t *ri);
82 static void jack_remove_shm (jack_shm_id_t *id);
84 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
85 * common interface-independent section
86 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88 /* The JACK SHM registry is a chunk of memory for keeping track of the
89 * shared memory used by each active JACK server. This allows the
90 * server to clean up shared memory when it exits. To avoid memory
91 * leakage due to kill -9, crashes or debugger-driven exits, this
92 * cleanup is also done when a new instance of that server starts.
95 /* per-process global data for the SHM interfaces */
96 static jack_shm_id_t registry_id; /* SHM id for the registry */
98 #ifdef WIN32
99 static jack_shm_info_t registry_info = {/* SHM info for the registry */
100 JACK_SHM_NULL_INDEX,
101 NULL
103 #else
104 static jack_shm_info_t registry_info = { /* SHM info for the registry */
105 .index = JACK_SHM_NULL_INDEX,
106 .attached_at = MAP_FAILED
109 #endif
111 /* pointers to registry header and array */
112 static jack_shm_header_t *jack_shm_header = NULL;
113 static jack_shm_registry_t *jack_shm_registry = NULL;
114 static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
116 /* jack_shm_lock_registry() serializes updates to the shared memory
117 * segment JACK uses to keep track of the SHM segments allocated to
118 * all its processes, including multiple servers.
120 * This is not a high-contention lock, but it does need to work across
121 * multiple processes. High transaction rates and realtime safety are
122 * not required. Any solution needs to at least be portable to POSIX
123 * and POSIX-like systems.
125 * We must be particularly careful to ensure that the lock be released
126 * if the owning process terminates abnormally. Otherwise, a segfault
127 * or kill -9 at the wrong moment could prevent JACK from ever running
128 * again on that machine until after a reboot.
131 #define JACK_SEMAPHORE_KEY 0x282929
132 #ifndef USE_POSIX_SHM
133 #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
134 #endif
136 static int semid = -1;
138 #ifdef WIN32
140 // steph TODO
141 static void
142 semaphore_init () {}
144 static void
145 semaphore_add (int value) {}
147 #else
148 /* all semaphore errors are fatal -- issue message, but do not return */
149 static void
150 semaphore_error (char *msg)
152 jack_error ("Fatal JACK semaphore error: %s (%s)",
153 msg, strerror (errno));
154 abort ();
157 static void
158 semaphore_init ()
160 key_t semkey = JACK_SEMAPHORE_KEY;
161 struct sembuf sbuf;
162 int create_flags = IPC_CREAT | IPC_EXCL
163 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
165 /* Get semaphore ID associated with this key. */
166 if ((semid = semget(semkey, 0, 0)) == -1) {
168 /* Semaphore does not exist - Create. */
169 if ((semid = semget(semkey, 1, create_flags)) != -1) {
171 /* Initialize the semaphore, allow one owner. */
172 sbuf.sem_num = 0;
173 sbuf.sem_op = 1;
174 sbuf.sem_flg = 0;
175 if (semop(semid, &sbuf, 1) == -1) {
176 semaphore_error ("semop");
179 } else if (errno == EEXIST) {
180 if ((semid = semget(semkey, 0, 0)) == -1) {
181 semaphore_error ("semget");
184 } else {
185 semaphore_error ("semget creation");
190 static inline void
191 semaphore_add (int value)
193 struct sembuf sbuf;
195 sbuf.sem_num = 0;
196 sbuf.sem_op = value;
197 sbuf.sem_flg = SEM_UNDO;
198 if (semop(semid, &sbuf, 1) == -1) {
199 semaphore_error ("semop");
203 #endif
205 static void
206 jack_shm_lock_registry (void)
208 if (semid == -1)
209 semaphore_init ();
211 semaphore_add (-1);
214 static void
215 jack_shm_unlock_registry (void)
217 semaphore_add (1);
220 static void
221 jack_shm_init_registry ()
223 /* registry must be locked */
224 int i;
226 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
228 jack_shm_header->magic = JACK_SHM_MAGIC;
229 //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
230 jack_shm_header->type = jack_shmtype;
231 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
232 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
233 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
235 for (i = 0; i < MAX_SHM_ID; ++i) {
236 jack_shm_registry[i].index = i;
240 static int
241 jack_shm_validate_registry ()
243 /* registry must be locked */
245 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
246 //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
247 && (jack_shm_header->type == jack_shmtype)
248 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
249 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
250 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
252 return 0; /* registry OK */
255 return -1;
258 /* set a unique per-user, per-server shm prefix string
260 * According to the POSIX standard:
262 * "The name argument conforms to the construction rules for a
263 * pathname. If name begins with the slash character, then processes
264 * calling shm_open() with the same value of name refer to the same
265 * shared memory object, as long as that name has not been
266 * removed. If name does not begin with the slash character, the
267 * effect is implementation-defined. The interpretation of slash
268 * characters other than the leading slash character in name is
269 * implementation-defined."
271 * Since the Linux implementation does not allow slashes *within* the
272 * name, in the interest of portability we use colons instead.
274 static void
275 jack_set_server_prefix (const char *server_name)
277 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
278 "jack-%d:%s:", GetUID(), server_name);
281 /* gain server addressability to shared memory registration segment
283 * returns: 0 if successful
285 static int
286 jack_server_initialize_shm (int new_registry)
288 int rc;
290 if (jack_shm_header)
291 return 0; /* already initialized */
293 jack_shm_lock_registry ();
295 rc = jack_access_registry (&registry_info);
297 if (new_registry) {
298 jack_remove_shm (&registry_id);
299 rc = ENOENT;
302 switch (rc) {
303 case ENOENT: /* registry does not exist */
304 rc = jack_create_registry (&registry_info);
305 break;
306 case 0: /* existing registry */
307 if (jack_shm_validate_registry () == 0)
308 break;
309 /* else it was invalid, so fall through */
310 case EINVAL: /* bad registry */
311 /* Apparently, this registry was created by an older
312 * JACK version. Delete it so we can try again. */
313 jack_release_shm (&registry_info);
314 jack_remove_shm (&registry_id);
315 if ((rc = jack_create_registry (&registry_info)) != 0) {
316 jack_error ("incompatible shm registry (%s)",
317 strerror (errno));
318 #ifndef USE_POSIX_SHM
319 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
320 JACK_SHM_REGISTRY_KEY);
321 #endif
323 break;
324 default: /* failure return code */
325 break;
328 jack_shm_unlock_registry ();
329 return rc;
332 /* gain client addressability to shared memory registration segment
334 * NOTE: this function is no longer used for server initialization,
335 * instead it calls jack_register_server().
337 * returns: 0 if successful
340 jack_initialize_shm (const char *server_name)
342 int rc;
344 if (jack_shm_header)
345 return 0; /* already initialized */
347 jack_set_server_prefix (server_name);
349 jack_shm_lock_registry ();
350 if ((rc = jack_access_registry (&registry_info)) == 0) {
351 if ((rc = jack_shm_validate_registry ()) != 0) {
352 jack_error ("Incompatible shm registry, "
353 "are jackd and libjack in sync?");
356 jack_shm_unlock_registry ();
358 return rc;
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
433 jack_register_server (const char *server_name, int new_registry)
435 int i, res = 0;
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 (new_registry))
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 res = 0; /* it's me */
462 goto unlock;
465 /* see if server still exists */
466 #ifndef WIN32 // steph TO CHECK
467 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
468 res = EEXIST; /* other server running */
469 goto unlock;
471 #endif
473 /* it's gone, reclaim this entry */
474 memset (&jack_shm_header->server[i], 0,
475 sizeof (jack_shm_server_t));
478 /* find a free entry */
479 for (i = 0; i < MAX_SERVERS; i++) {
480 if (jack_shm_header->server[i].pid == 0)
481 break;
484 if (i >= MAX_SERVERS){
485 res = ENOSPC; /* out of space */
486 goto unlock;
490 /* claim it */
491 jack_shm_header->server[i].pid = my_pid;
492 strncpy (jack_shm_header->server[i].name,
493 jack_shm_server_prefix,
494 JACK_SERVER_NAME_SIZE);
496 unlock:
497 jack_shm_unlock_registry ();
498 return 0;
501 /* release server_name registration */
502 void
503 jack_unregister_server (const char *server_name /* unused */)
505 int i;
507 #ifdef WIN32
508 int my_pid = _getpid();
509 #else
510 pid_t my_pid = getpid();
511 #endif
513 jack_shm_lock_registry ();
515 for (i = 0; i < MAX_SERVERS; i++) {
516 if (jack_shm_header->server[i].pid == my_pid) {
517 memset (&jack_shm_header->server[i], 0,
518 sizeof (jack_shm_server_t));
522 jack_shm_unlock_registry ();
525 /* called for server startup and termination */
527 jack_cleanup_shm ()
529 int i;
530 int destroy;
531 jack_shm_info_t copy;
533 #ifdef WIN32
534 int my_pid = _getpid();
535 #else
536 pid_t my_pid = getpid();
537 #endif
539 jack_shm_lock_registry ();
541 for (i = 0; i < MAX_SHM_ID; i++) {
542 jack_shm_registry_t* r;
544 r = &jack_shm_registry[i];
545 memcpy (&copy, r, sizeof (jack_shm_info_t));
546 destroy = FALSE;
548 /* ignore unused entries */
549 if (r->allocator == 0)
550 continue;
552 /* is this my shm segment? */
553 if (r->allocator == my_pid) {
555 /* allocated by this process, so unattach
556 and destroy. */
557 jack_release_shm (&copy);
558 destroy = TRUE;
560 } else {
562 /* see if allocator still exists */
563 #ifdef WIN32 // steph
564 jack_info("TODO: kill API not available !!");
565 #else
566 if (kill (r->allocator, 0)) {
567 if (errno == ESRCH) {
568 /* allocator no longer exists,
569 * so destroy */
570 destroy = TRUE;
573 #endif
576 if (destroy) {
578 int index = copy.index;
580 if ((index >= 0) && (index < MAX_SHM_ID)) {
581 jack_remove_shm (&jack_shm_registry[index].id);
582 jack_release_shm_entry (index);
584 r->size = 0;
585 r->allocator = 0;
589 jack_shm_unlock_registry ();
590 return TRUE;
593 /* resize a shared memory segment
595 * There is no way to resize a System V shm segment. Resizing is
596 * possible with POSIX shm, but not with the non-conformant Mac OS X
597 * implementation. Since POSIX shm is mainly used on that platform,
598 * it's simpler to treat them both the same.
600 * So, we always resize by deleting and reallocating. This is
601 * tricky, because the old segment will not disappear until
602 * all the clients have released it. We only do what we can
603 * from here.
605 * This is not done under a single lock. I don't even want to think
606 * about all the things that could possibly go wrong if multple
607 * processes tried to resize the same segment concurrently. That
608 * probably doesn't happen.
611 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
613 jack_shm_id_t id;
615 /* The underlying type of `id' differs for SYSV and POSIX */
616 memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
618 jack_release_shm (si);
619 jack_destroy_shm (si);
621 if (jack_shmalloc ((char *) id, size, si)) {
622 return -1;
625 return jack_attach_shm (si);
628 #ifdef USE_POSIX_SHM
630 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
631 * POSIX interface-dependent functions
632 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
634 /* gain addressability to existing SHM registry segment
636 * sets up global registry pointers, if successful
638 * returns: 0 if existing registry accessed successfully
639 * ENOENT if registry does not exist
640 * EINVAL if registry exists, but has the wrong size
642 static int
643 jack_access_registry (jack_shm_info_t *ri)
645 /* registry must be locked */
646 int shm_fd;
648 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
650 /* try to open an existing segment */
651 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
652 int rc = errno;
653 if (errno != ENOENT) {
654 jack_error ("Cannot open existing shm registry segment"
655 " (%s)", strerror (errno));
657 close (shm_fd);
658 return rc;
661 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
662 PROT_READ|PROT_WRITE,
663 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
664 jack_error ("Cannot mmap shm registry segment (%s)",
665 strerror (errno));
666 close (shm_fd);
667 return EINVAL;
670 /* set up global pointers */
671 ri->index = JACK_SHM_REGISTRY_INDEX;
672 jack_shm_header = ri->attached_at;
673 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
675 close (shm_fd); // steph
676 return 0;
679 /* create a new SHM registry segment
681 * sets up global registry pointers, if successful
683 * returns: 0 if registry created successfully
684 * nonzero error code if unable to allocate a new registry
686 static int
687 jack_create_registry (jack_shm_info_t *ri)
689 /* registry must be locked */
690 int shm_fd;
692 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
694 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
695 int rc = errno;
696 jack_error ("Cannot create shm registry segment (%s)",
697 strerror (errno));
698 return rc;
701 /* Previous shm_open result depends of the actual value of umask, force correct file permisssion here */
702 if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
703 jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
706 /* Set the desired segment size. NOTE: the non-conformant Mac
707 * OS X POSIX shm only allows ftruncate() on segment creation.
709 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
710 int rc = errno;
711 jack_error ("Cannot set registry size (%s)", strerror (errno));
712 jack_remove_shm (&registry_id);
713 close (shm_fd);
714 return rc;
717 if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
718 PROT_READ|PROT_WRITE,
719 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
720 jack_error ("Cannot mmap shm registry segment (%s)",
721 strerror (errno));
722 jack_remove_shm (&registry_id);
723 close (shm_fd);
724 return EINVAL;
727 /* set up global pointers */
728 ri->index = JACK_SHM_REGISTRY_INDEX;
729 jack_shm_header = ri->attached_at;
730 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
732 /* initialize registry contents */
733 jack_shm_init_registry ();
734 close (shm_fd); // steph
735 return 0;
738 static void
739 jack_remove_shm (jack_shm_id_t *id)
741 /* registry may or may not be locked */
742 shm_unlink ((char *) id);
745 void
746 jack_release_shm (jack_shm_info_t* si)
748 /* registry may or may not be locked */
749 if (si->attached_at != MAP_FAILED) {
750 munmap (si->attached_at, jack_shm_registry[si->index].size);
754 /* allocate a POSIX shared memory segment */
756 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
758 jack_shm_registry_t* registry;
759 int shm_fd;
760 int rc = -1;
761 char name[SHM_NAME_MAX+1];
763 jack_shm_lock_registry ();
765 if ((registry = jack_get_free_shm_info ()) == NULL) {
766 jack_error ("shm registry full");
767 goto unlock;
770 /* On Mac OS X, the maximum length of a shared memory segment
771 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
772 * defined by the standard). Unfortunately, Apple sets this
773 * value so small (about 31 bytes) that it is useless for
774 * actual names. So, we construct a short name from the
775 * registry index for uniqueness and ignore the shm_name
776 * parameter. Bah!
778 snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index);
780 if (strlen (name) >= sizeof (registry->id)) {
781 jack_error ("shm segment name too long %s", name);
782 goto unlock;
785 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
786 jack_error ("Cannot create shm segment %s (%s)",
787 name, strerror (errno));
788 goto unlock;
791 if (ftruncate (shm_fd, size) < 0) {
792 jack_error ("Cannot set size of engine shm "
793 "registry 0 (%s)",
794 strerror (errno));
795 close (shm_fd);
796 goto unlock;
799 close (shm_fd);
800 registry->size = size;
801 strncpy (registry->id, name, sizeof (registry->id));
802 registry->allocator = getpid();
803 si->index = registry->index;
804 si->attached_at = MAP_FAILED; /* not attached */
805 rc = 0; /* success */
807 unlock:
808 jack_shm_unlock_registry ();
809 return rc;
813 jack_attach_shm (jack_shm_info_t* si)
815 int shm_fd;
816 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
818 if ((shm_fd = shm_open (registry->id,
819 O_RDWR, 0666)) < 0) {
820 jack_error ("Cannot open shm segment %s (%s)", registry->id,
821 strerror (errno));
822 return -1;
825 if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
826 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
827 jack_error ("Cannot mmap shm segment %s (%s)",
828 registry->id,
829 strerror (errno));
830 close (shm_fd);
831 return -1;
834 close (shm_fd);
835 return 0;
839 jack_attach_shm_read (jack_shm_info_t* si)
841 int shm_fd;
842 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
844 if ((shm_fd = shm_open (registry->id,
845 O_RDONLY, 0666)) < 0) {
846 jack_error ("Cannot open shm segment %s (%s)", registry->id,
847 strerror (errno));
848 return -1;
851 if ((si->attached_at = mmap (0, registry->size, PROT_READ,
852 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
853 jack_error ("Cannot mmap shm segment %s (%s)",
854 registry->id,
855 strerror (errno));
856 close (shm_fd);
857 return -1;
860 close (shm_fd);
861 return 0;
864 #elif WIN32
866 static int
867 jack_access_registry (jack_shm_info_t *ri)
869 /* registry must be locked */
870 HANDLE shm_fd;
871 LPSECURITY_ATTRIBUTES sec = 0;
873 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
875 /* try to open an existing segment */
877 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
878 int rc = GetLastError();
879 if (rc != ERROR_FILE_NOT_FOUND) {
880 jack_error ("Cannot open existing shm registry segment (%ld)", rc);
882 return rc;
885 if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
886 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
887 jack_remove_shm (&registry_id);
888 CloseHandle (shm_fd);
889 return EINVAL;
892 /* set up global pointers */
893 ri->index = JACK_SHM_REGISTRY_INDEX;
894 jack_shm_header = ri->attached_at;
895 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
897 //CloseHandle(shm_fd); // TO CHECK
898 return 0;
901 static int
902 jack_create_registry (jack_shm_info_t *ri)
904 /* registry must be locked */
905 HANDLE shm_fd;
907 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
909 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
910 0, PAGE_READWRITE,
911 0, JACK_SHM_REGISTRY_SIZE,
912 registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
913 int rc = GetLastError();
914 jack_error ("Cannot create shm registry segment (%ld)", rc);
915 return rc;
918 if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
919 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
920 jack_remove_shm (&registry_id);
921 CloseHandle (shm_fd);
922 return EINVAL;
925 /* set up global pointers */
926 ri->index = JACK_SHM_REGISTRY_INDEX;
927 jack_shm_header = ri->attached_at;
928 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
930 /* initialize registry contents */
931 jack_shm_init_registry ();
933 //CloseHandle(shm_fd); // TO CHECK
934 return 0;
937 static void
938 jack_remove_shm (jack_shm_id_t *id)
940 /* nothing to do */
943 void
944 jack_release_shm (jack_shm_info_t* si)
946 /* registry may or may not be locked */
947 if (si->attached_at != NULL) {
948 UnmapViewOfFile (si->attached_at);
953 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
955 jack_shm_registry_t* registry;
956 HANDLE shm_fd;
957 int rc = -1;
958 char name[SHM_NAME_MAX+1];
960 jack_shm_lock_registry ();
962 if ((registry = jack_get_free_shm_info ()) == NULL) {
963 jack_error ("shm registry full");
964 goto unlock;
967 snprintf (name, sizeof (name), "jack-%d-%d", GetUID(), registry->index);
969 if (strlen (name) >= sizeof (registry->id)) {
970 jack_error ("shm segment name too long %s", name);
971 goto unlock;
974 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
975 0, PAGE_READWRITE,
976 0, size,
977 name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
978 int rc = GetLastError();
979 jack_error ("Cannot create shm segment (%ld)",rc);
980 goto unlock;
983 //CloseHandle (shm_fd); // TO CHECK
985 registry->size = size;
986 strncpy (registry->id, name, sizeof (registry->id));
987 registry->allocator = _getpid();
988 si->index = registry->index;
989 si->attached_at = NULL; /* not attached */
990 rc = 0; /* success */
992 unlock:
993 jack_shm_unlock_registry ();
994 return rc;
998 jack_attach_shm (jack_shm_info_t* si)
1000 HANDLE shm_fd;
1001 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1003 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1004 int rc = GetLastError();
1005 jack_error ("Cannot open shm segment (%ld)",rc);
1006 return -1;
1009 if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
1010 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
1011 jack_remove_shm (&registry_id);
1012 CloseHandle (shm_fd);
1013 return -1;
1016 //CloseHandle (shm_fd); // TO CHECK
1017 return 0;
1021 jack_attach_shm_read (jack_shm_info_t* si)
1023 HANDLE shm_fd;
1024 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1026 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1027 int rc = GetLastError();
1028 jack_error ("Cannot open shm segment (%ld)",rc);
1029 return -1;
1032 if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
1033 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
1034 jack_remove_shm (&registry_id);
1035 CloseHandle (shm_fd);
1036 return -1;
1039 //CloseHandle (shm_fd); // TO CHECK
1040 return 0;
1043 #else
1045 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1046 * System V interface-dependent functions
1047 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1049 /* gain addressability to existing SHM registry segment
1051 * sets up global registry pointers, if successful
1053 * returns: 0 if existing registry accessed successfully
1054 * ENOENT if registry does not exist
1055 * EINVAL if registry exists, but has the wrong size
1056 * other nonzero error code if unable to access registry
1058 static int
1059 jack_access_registry (jack_shm_info_t *ri)
1061 /* registry must be locked */
1063 /* try without IPC_CREAT to get existing segment */
1064 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1065 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
1067 switch (errno) {
1069 case ENOENT: /* segment does not exist */
1070 return ENOENT;
1072 case EINVAL: /* segment exists, but too small */
1073 /* attempt minimum size access */
1074 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
1075 return EINVAL;
1077 default: /* or other error */
1078 jack_error ("unable to access shm registry (%s)",
1079 strerror (errno));
1080 return errno;
1084 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
1085 jack_error ("Cannot attach shm registry segment (%s)",
1086 strerror (errno));
1087 return EINVAL;
1090 /* set up global pointers */
1091 ri->index = JACK_SHM_REGISTRY_INDEX;
1092 jack_shm_header = ri->attached_at;
1093 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1094 return 0;
1097 /* create a new SHM registry segment
1099 * sets up global registry pointers, if successful
1101 * returns: 0 if registry created successfully
1102 * nonzero error code if unable to allocate a new registry
1104 static int
1105 jack_create_registry (jack_shm_info_t *ri)
1107 /* registry must be locked */
1108 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1109 JACK_SHM_REGISTRY_SIZE,
1110 0666|IPC_CREAT)) < 0) {
1111 jack_error ("Cannot create shm registry segment (%s)",
1112 strerror (errno));
1113 return errno;
1116 if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
1117 jack_error ("Cannot attach shm registry segment (%s)",
1118 strerror (errno));
1119 return EINVAL;
1122 /* set up global pointers */
1123 ri->index = JACK_SHM_REGISTRY_INDEX;
1124 jack_shm_header = ri->attached_at;
1125 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1127 /* initialize registry contents */
1128 jack_shm_init_registry ();
1129 return 0;
1132 static void
1133 jack_remove_shm (jack_shm_id_t *id)
1135 /* registry may or may not be locked */
1136 shmctl (*id, IPC_RMID, NULL);
1139 void
1140 jack_release_shm (jack_shm_info_t* si)
1142 /* registry may or may not be locked */
1143 if (si->attached_at != MAP_FAILED) {
1144 shmdt (si->attached_at);
1149 jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
1150 jack_shm_info_t* si)
1152 int shmflags;
1153 int shmid;
1154 int rc = -1;
1155 jack_shm_registry_t* registry;
1157 jack_shm_lock_registry ();
1159 if ((registry = jack_get_free_shm_info ())) {
1161 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
1163 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
1165 registry->size = size;
1166 registry->id = shmid;
1167 registry->allocator = getpid();
1168 si->index = registry->index;
1169 si->attached_at = MAP_FAILED; /* not attached */
1170 rc = 0;
1172 } else {
1173 jack_error ("Cannot create shm segment %s (%s)",
1174 name_not_used, strerror (errno));
1178 jack_shm_unlock_registry ();
1179 return rc;
1183 jack_attach_shm (jack_shm_info_t* si)
1185 if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
1186 jack_error ("Cannot attach shm segment (%s)",
1187 strerror (errno));
1188 jack_release_shm_info (si->index);
1189 return -1;
1191 return 0;
1194 #endif /* !USE_POSIX_SHM */