FIx doxygen and user facing and non-facing typos
[jack2.git] / common / shm.c
blob35ec90fca719d547167b6aaa689ee8a0ea87df56
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
8 * - Windows implementation
10 * The implementation used is determined by whether USE_POSIX_SHM was
11 * set in the ./configure step.
15 Copyright (C) 2001-2003 Paul Davis
16 Copyright (C) 2005-2012 Grame
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU Lesser General Public License as published by
20 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
28 You should have received a copy of the GNU Lesser General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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>
55 #include "promiscuous.h"
57 #endif
59 #include "shm.h"
60 #include "JackError.h"
62 static int GetUID()
64 #ifdef WIN32
65 return _getpid();
66 //#error "No getuid function available"
67 #else
68 return geteuid();
69 #endif
72 static int GetPID()
74 #ifdef WIN32
75 return _getpid();
76 #else
77 return getpid();
78 #endif
81 #ifdef USE_POSIX_SHM
82 static jack_shmtype_t jack_shmtype = shm_POSIX;
83 #elif WIN32
84 static jack_shmtype_t jack_shmtype = shm_WIN32;
85 #else
86 static jack_shmtype_t jack_shmtype = shm_SYSV;
87 #endif
89 /* interface-dependent forward declarations */
90 static int jack_access_registry (jack_shm_info_t *ri);
91 static int jack_create_registry (jack_shm_info_t *ri);
92 static void jack_remove_shm (jack_shm_id_t *id);
94 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
95 * common interface-independent section
96 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
98 /* The JACK SHM registry is a chunk of memory for keeping track of the
99 * shared memory used by each active JACK server. This allows the
100 * server to clean up shared memory when it exits. To avoid memory
101 * leakage due to kill -9, crashes or debugger-driven exits, this
102 * cleanup is also done when a new instance of that server starts.
105 /* per-process global data for the SHM interfaces */
106 static jack_shm_id_t registry_id; /* SHM id for the registry */
108 #ifdef WIN32
109 static jack_shm_info_t registry_info = {/* SHM info for the registry */
110 JACK_SHM_NULL_INDEX,
111 NULL
113 #else
114 static jack_shm_info_t registry_info = { /* SHM info for the registry */
115 .index = JACK_SHM_NULL_INDEX,
116 .ptr.attached_at = MAP_FAILED
118 #endif
120 /* pointers to registry header and array */
121 static jack_shm_header_t *jack_shm_header = NULL;
122 static jack_shm_registry_t *jack_shm_registry = NULL;
123 static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE+1] = "";
125 /* jack_shm_lock_registry() serializes updates to the shared memory
126 * segment JACK uses to keep track of the SHM segments allocated to
127 * all its processes, including multiple servers.
129 * This is not a high-contention lock, but it does need to work across
130 * multiple processes. High transaction rates and realtime safety are
131 * not required. Any solution needs to at least be portable to POSIX
132 * and POSIX-like systems.
134 * We must be particularly careful to ensure that the lock be released
135 * if the owning process terminates abnormally. Otherwise, a segfault
136 * or kill -9 at the wrong moment could prevent JACK from ever running
137 * again on that machine until after a reboot.
140 #define JACK_SEMAPHORE_KEY 0x282929
141 #ifndef USE_POSIX_SHM
142 #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
143 #endif
145 static int semid = -1;
147 #ifdef WIN32
149 #include <psapi.h>
150 #include <lmcons.h>
152 static BOOL check_process_running(DWORD process_id)
154 DWORD aProcesses[2048], cbNeeded, cProcesses;
155 unsigned int i;
157 // Enumerate all processes
158 if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
159 return FALSE;
162 // Calculate how many process identifiers were returned.
163 cProcesses = cbNeeded / sizeof(DWORD);
165 for (i = 0; i < cProcesses; i++) {
166 if (aProcesses[i] == process_id) {
167 // Process process_id is running...
168 return TRUE;
171 return FALSE;
174 static int
175 semaphore_init () {return 0;}
177 static int
178 semaphore_add (int value) {return 0;}
180 #else
181 /* all semaphore errors are fatal -- issue message, but do not return */
182 static void
183 semaphore_error (char *msg)
185 jack_error ("JACK semaphore error: %s (%s)",
186 msg, strerror (errno));
189 static int
190 semaphore_init ()
192 key_t semkey = JACK_SEMAPHORE_KEY;
193 struct sembuf sbuf;
194 int create_flags = IPC_CREAT | IPC_EXCL
195 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
197 /* Get semaphore ID associated with this key. */
198 if ((semid = semget(semkey, 0, 0)) == -1) {
200 /* Semaphore does not exist - Create. */
201 if ((semid = semget(semkey, 1, create_flags)) != -1) {
203 /* Initialize the semaphore, allow one owner. */
204 sbuf.sem_num = 0;
205 sbuf.sem_op = 1;
206 sbuf.sem_flg = 0;
207 if (semop(semid, &sbuf, 1) == -1) {
208 semaphore_error ("semop");
209 return -1;
212 } else if (errno == EEXIST) {
213 if ((semid = semget(semkey, 0, 0)) == -1) {
214 semaphore_error ("semget");
215 return -1;
218 } else {
219 semaphore_error ("semget creation");
220 return -1;
224 return 0;
227 static inline int
228 semaphore_add (int value)
230 struct sembuf sbuf;
232 sbuf.sem_num = 0;
233 sbuf.sem_op = value;
234 sbuf.sem_flg = SEM_UNDO;
236 if (semop(semid, &sbuf, 1) == -1) {
237 semaphore_error ("semop");
238 return -1;
241 return 0;
244 #endif
246 static int
247 jack_shm_lock_registry (void)
249 if (semid == -1) {
250 if (semaphore_init () < 0)
251 return -1;
254 return semaphore_add (-1);
257 static void
258 jack_shm_unlock_registry (void)
260 semaphore_add (1);
263 static void
264 jack_shm_init_registry ()
266 /* registry must be locked */
267 int i;
269 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
271 jack_shm_header->magic = JACK_SHM_MAGIC;
272 //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
273 jack_shm_header->type = jack_shmtype;
274 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
275 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
276 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
278 for (i = 0; i < MAX_SHM_ID; ++i) {
279 jack_shm_registry[i].index = i;
283 static int
284 jack_shm_validate_registry ()
286 /* registry must be locked */
288 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
289 //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
290 && (jack_shm_header->type == jack_shmtype)
291 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
292 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
293 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
295 return 0; /* registry OK */
298 return -1;
301 /* set a unique per-user, per-server shm prefix string
303 * According to the POSIX standard:
305 * "The name argument conforms to the construction rules for a
306 * pathname. If name begins with the slash character, then processes
307 * calling shm_open() with the same value of name refer to the same
308 * shared memory object, as long as that name has not been
309 * removed. If name does not begin with the slash character, the
310 * effect is implementation-defined. The interpretation of slash
311 * characters other than the leading slash character in name is
312 * implementation-defined."
314 * Since the Linux implementation does not allow slashes *within* the
315 * name, in the interest of portability we use colons instead.
317 static void
318 jack_set_server_prefix (const char *server_name)
320 #ifdef WIN32
321 char buffer[UNLEN+1]={0};
322 DWORD len = UNLEN+1;
323 GetUserName(buffer, &len);
324 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
325 "jack-%s:%s:", buffer, server_name);
326 #else
327 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
328 "jack-%d:%s:", GetUID(), server_name);
329 #endif
332 /* gain server addressability to shared memory registration segment
334 * returns: 0 if successful
336 static int
337 jack_server_initialize_shm (int new_registry)
339 int rc;
341 if (jack_shm_header)
342 return 0; /* already initialized */
344 if (jack_shm_lock_registry () < 0) {
345 jack_error ("jack_shm_lock_registry fails...");
346 return -1;
349 rc = jack_access_registry (&registry_info);
351 if (new_registry) {
352 jack_remove_shm (&registry_id);
353 rc = ENOENT;
356 switch (rc) {
357 case ENOENT: /* registry does not exist */
358 rc = jack_create_registry (&registry_info);
359 break;
360 case 0: /* existing registry */
361 if (jack_shm_validate_registry () == 0)
362 break;
363 /* else it was invalid, so fall through */
364 case EINVAL: /* bad registry */
365 /* Apparently, this registry was created by an older
366 * JACK version. Delete it so we can try again. */
367 jack_release_shm (&registry_info);
368 jack_remove_shm (&registry_id);
369 if ((rc = jack_create_registry (&registry_info)) != 0) {
370 jack_error ("incompatible shm registry (%s)",
371 strerror (errno));
372 #ifndef USE_POSIX_SHM
373 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
374 JACK_SHM_REGISTRY_KEY);
375 #endif
377 break;
378 default: /* failure return code */
379 break;
382 jack_shm_unlock_registry ();
383 return rc;
386 /* gain client addressability to shared memory registration segment
388 * NOTE: this function is no longer used for server initialization,
389 * instead it calls jack_register_server().
391 * returns: 0 if successful
394 jack_initialize_shm (const char *server_name)
396 int rc;
398 if (jack_shm_header)
399 return 0; /* already initialized */
401 jack_set_server_prefix (server_name);
403 if (jack_shm_lock_registry () < 0) {
404 jack_error ("jack_shm_lock_registry fails...");
405 return -1;
408 if ((rc = jack_access_registry (&registry_info)) == 0) {
409 if ((rc = jack_shm_validate_registry ()) != 0) {
410 jack_error ("Incompatible shm registry, "
411 "are jackd and libjack in sync?");
414 jack_shm_unlock_registry ();
416 return rc;
420 char* jack_shm_addr (jack_shm_info_t* si)
422 return (char*)si->ptr.attached_at;
425 void
426 jack_destroy_shm (jack_shm_info_t* si)
428 /* must NOT have the registry locked */
429 if (si->index == JACK_SHM_NULL_INDEX)
430 return; /* segment not allocated */
432 jack_remove_shm (&jack_shm_registry[si->index].id);
433 jack_release_shm_info (si->index);
436 jack_shm_registry_t *
437 jack_get_free_shm_info ()
439 /* registry must be locked */
440 jack_shm_registry_t* si = NULL;
441 int i;
443 for (i = 0; i < MAX_SHM_ID; ++i) {
444 if (jack_shm_registry[i].size == 0) {
445 break;
449 if (i < MAX_SHM_ID) {
450 si = &jack_shm_registry[i];
453 return si;
456 static void
457 jack_release_shm_entry (jack_shm_registry_index_t index)
459 /* the registry must be locked */
460 jack_shm_registry[index].size = 0;
461 jack_shm_registry[index].allocator = 0;
462 memset (&jack_shm_registry[index].id, 0,
463 sizeof (jack_shm_registry[index].id));
467 jack_release_shm_info (jack_shm_registry_index_t index)
469 /* must NOT have the registry locked */
470 if (jack_shm_registry[index].allocator == GetPID()) {
471 if (jack_shm_lock_registry () < 0) {
472 jack_error ("jack_shm_lock_registry fails...");
473 return -1;
475 jack_release_shm_entry (index);
476 jack_shm_unlock_registry ();
479 return 0;
482 /* Claim server_name for this process.
484 * returns 0 if successful
485 * EEXIST if server_name was already active for this user
486 * ENOSPC if server registration limit reached
487 * ENOMEM if unable to access shared memory registry
490 jack_register_server (const char *server_name, int new_registry)
492 int i, res = 0;
494 jack_set_server_prefix (server_name);
496 if (jack_server_initialize_shm (new_registry))
497 return ENOMEM;
499 if (jack_shm_lock_registry () < 0) {
500 jack_error ("jack_shm_lock_registry fails...");
501 return -1;
504 /* See if server_name already registered. Since server names
505 * are per-user, we register the unique server prefix string.
507 for (i = 0; i < MAX_SERVERS; i++) {
509 if (strncmp (jack_shm_header->server[i].name,
510 jack_shm_server_prefix,
511 JACK_SERVER_NAME_SIZE) != 0)
512 continue; /* no match */
514 if (jack_shm_header->server[i].pid == GetPID()){
515 res = 0; /* it's me */
516 goto unlock;
519 /* see if server still exists */
520 #ifdef WIN32
521 if (check_process_running(jack_shm_header->server[i].pid)) {
522 res = EEXIST; /* other server running */
523 goto unlock;
525 #else
526 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
527 res = EEXIST; /* other server running */
528 goto unlock;
530 #endif
532 /* it's gone, reclaim this entry */
533 memset (&jack_shm_header->server[i], 0,
534 sizeof (jack_shm_server_t));
537 /* find a free entry */
538 for (i = 0; i < MAX_SERVERS; i++) {
539 if (jack_shm_header->server[i].pid == 0)
540 break;
543 if (i >= MAX_SERVERS){
544 res = ENOSPC; /* out of space */
545 goto unlock;
548 /* claim it */
549 jack_shm_header->server[i].pid = GetPID();
550 strncpy (jack_shm_header->server[i].name,
551 jack_shm_server_prefix,
552 JACK_SERVER_NAME_SIZE);
554 unlock:
555 jack_shm_unlock_registry ();
556 return res;
559 /* release server_name registration */
561 jack_unregister_server (const char *server_name /* unused */)
563 int i;
564 if (jack_shm_lock_registry () < 0) {
565 jack_error ("jack_shm_lock_registry fails...");
566 return -1;
569 for (i = 0; i < MAX_SERVERS; i++) {
570 if (jack_shm_header->server[i].pid == GetPID()) {
571 memset (&jack_shm_header->server[i], 0,
572 sizeof (jack_shm_server_t));
576 jack_shm_unlock_registry ();
577 return 0;
580 /* called for server startup and termination */
582 jack_cleanup_shm ()
584 int i;
585 int destroy;
586 jack_shm_info_t copy;
588 if (jack_shm_lock_registry () < 0) {
589 jack_error ("jack_shm_lock_registry fails...");
590 return -1;
593 for (i = 0; i < MAX_SHM_ID; i++) {
594 jack_shm_registry_t* r;
596 r = &jack_shm_registry[i];
597 memcpy (&copy, r, sizeof (jack_shm_info_t));
598 destroy = FALSE;
600 /* ignore unused entries */
601 if (r->allocator == 0)
602 continue;
604 /* is this my shm segment? */
605 if (r->allocator == GetPID()) {
607 /* allocated by this process, so unattach
608 and destroy. */
609 jack_release_shm (&copy);
610 destroy = TRUE;
612 } else {
614 /* see if allocator still exists */
615 #ifdef WIN32
616 //jack_info("TODO: kill API not available !!");
617 #else
618 if (kill (r->allocator, 0)) {
619 if (errno == ESRCH) {
620 /* allocator no longer exists,
621 * so destroy */
622 destroy = TRUE;
625 #endif
628 if (destroy) {
630 int index = copy.index;
632 if ((index >= 0) && (index < MAX_SHM_ID)) {
633 jack_remove_shm (&jack_shm_registry[index].id);
634 jack_release_shm_entry (index);
636 r->size = 0;
637 r->allocator = 0;
641 jack_shm_unlock_registry ();
642 return TRUE;
645 /* resize a shared memory segment
647 * There is no way to resize a System V shm segment. Resizing is
648 * possible with POSIX shm, but not with the non-conformant Mac OS X
649 * implementation. Since POSIX shm is mainly used on that platform,
650 * it's simpler to treat them both the same.
652 * So, we always resize by deleting and reallocating. This is
653 * tricky, because the old segment will not disappear until
654 * all the clients have released it. We only do what we can
655 * from here.
657 * This is not done under a single lock. I don't even want to think
658 * about all the things that could possibly go wrong if multiple
659 * processes tried to resize the same segment concurrently. That
660 * probably doesn't happen.
663 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
665 jack_shm_id_t id;
667 /* The underlying type of `id' differs for SYSV and POSIX */
668 memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
670 jack_release_shm (si);
671 jack_destroy_shm (si);
673 if (jack_shmalloc ((char *) id, size, si)) {
674 return -1;
677 return jack_attach_shm (si);
681 jack_attach_lib_shm (jack_shm_info_t* si)
683 int res = jack_attach_shm(si);
684 if (res == 0)
685 si->size = jack_shm_registry[si->index].size; // Keep size in si struct
686 return res;
690 jack_attach_lib_shm_read (jack_shm_info_t* si)
692 int res = jack_attach_shm_read(si);
693 if (res == 0)
694 si->size = jack_shm_registry[si->index].size; // Keep size in si struct
695 return res;
698 #ifdef USE_POSIX_SHM
700 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
701 * POSIX interface-dependent functions
702 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
704 /* gain addressability to existing SHM registry segment
706 * sets up global registry pointers, if successful
708 * returns: 0 if existing registry accessed successfully
709 * ENOENT if registry does not exist
710 * EINVAL if registry exists, but has the wrong size
712 static int
713 jack_access_registry (jack_shm_info_t *ri)
715 /* registry must be locked */
716 int shm_fd;
718 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
720 /* try to open an existing segment */
721 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
722 int rc = errno;
723 if (errno != ENOENT) {
724 jack_error ("Cannot open existing shm registry segment"
725 " (%s)", strerror (errno));
727 close (shm_fd);
728 return rc;
731 if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
732 PROT_READ|PROT_WRITE,
733 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
734 jack_error ("Cannot mmap shm registry segment (%s)",
735 strerror (errno));
736 close (shm_fd);
737 return EINVAL;
740 /* set up global pointers */
741 ri->index = JACK_SHM_REGISTRY_INDEX;
742 jack_shm_header = ri->ptr.attached_at;
743 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
745 close (shm_fd);
746 return 0;
749 /* create a new SHM registry segment
751 * sets up global registry pointers, if successful
753 * returns: 0 if registry created successfully
754 * nonzero error code if unable to allocate a new registry
756 static int
757 jack_create_registry (jack_shm_info_t *ri)
759 /* registry must be locked */
760 int shm_fd;
762 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
764 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
765 int rc = errno;
766 jack_error ("Cannot create shm registry segment (%s)",
767 strerror (errno));
768 return rc;
771 /* Previous shm_open result depends of the actual value of umask, force correct file permission here */
772 if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
773 jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
776 /* Set the desired segment size. NOTE: the non-conformant Mac
777 * OS X POSIX shm only allows ftruncate() on segment creation.
779 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
780 int rc = errno;
781 jack_error ("Cannot set registry size (%s)", strerror (errno));
782 jack_remove_shm (&registry_id);
783 close (shm_fd);
784 return rc;
787 if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
788 PROT_READ|PROT_WRITE,
789 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
790 jack_error ("Cannot mmap shm registry segment (%s)",
791 strerror (errno));
792 jack_remove_shm (&registry_id);
793 close (shm_fd);
794 return EINVAL;
797 /* set up global pointers */
798 ri->index = JACK_SHM_REGISTRY_INDEX;
799 jack_shm_header = ri->ptr.attached_at;
800 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
802 /* initialize registry contents */
803 jack_shm_init_registry ();
804 close (shm_fd);
805 return 0;
808 static void
809 jack_remove_shm (jack_shm_id_t *id)
811 /* registry may or may not be locked */
812 shm_unlink ((char *) id);
815 void
816 jack_release_shm (jack_shm_info_t* si)
818 /* registry may or may not be locked */
819 if (si->ptr.attached_at != MAP_FAILED) {
820 munmap (si->ptr.attached_at, jack_shm_registry[si->index].size);
824 void
825 jack_release_lib_shm (jack_shm_info_t* si)
827 /* registry may or may not be locked */
828 if (si->ptr.attached_at != MAP_FAILED) {
829 munmap (si->ptr.attached_at, si->size);
833 /* allocate a POSIX shared memory segment */
835 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
837 jack_shm_registry_t* registry;
838 int shm_fd;
839 int rc = -1;
840 char name[SHM_NAME_MAX+1];
841 const char* promiscuous;
843 if (jack_shm_lock_registry () < 0) {
844 jack_error ("jack_shm_lock_registry fails...");
845 return -1;
848 if ((registry = jack_get_free_shm_info ()) == NULL) {
849 jack_error ("shm registry full");
850 goto unlock;
853 /* On Mac OS X, the maximum length of a shared memory segment
854 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
855 * defined by the standard). Unfortunately, Apple sets this
856 * value so small (about 31 bytes) that it is useless for
857 * actual names. So, we construct a short name from the
858 * registry index for uniqueness and ignore the shm_name
859 * parameter. Bah!
861 snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index);
863 if (strlen (name) >= sizeof (registry->id)) {
864 jack_error ("shm segment name too long %s", name);
865 goto unlock;
868 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
869 jack_error ("Cannot create shm segment %s (%s)",
870 name, strerror (errno));
871 goto unlock;
874 if (ftruncate (shm_fd, size) < 0) {
875 jack_error ("Cannot set size of engine shm "
876 "registry 0 (%s)",
877 strerror (errno));
878 close (shm_fd);
879 goto unlock;
882 promiscuous = getenv("JACK_PROMISCUOUS_SERVER");
883 if ((promiscuous != NULL) && (jack_promiscuous_perms(shm_fd, name, jack_group2gid(promiscuous)) < 0))
884 goto unlock;
886 close (shm_fd);
887 registry->size = size;
888 strncpy (registry->id, name, sizeof (registry->id));
889 registry->allocator = GetPID();
890 si->index = registry->index;
891 si->ptr.attached_at = MAP_FAILED; /* not attached */
892 rc = 0; /* success */
894 unlock:
895 jack_shm_unlock_registry ();
896 return rc;
900 jack_attach_shm (jack_shm_info_t* si)
902 int shm_fd;
903 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
905 if ((shm_fd = shm_open (registry->id,
906 O_RDWR, 0666)) < 0) {
907 jack_error ("Cannot open shm segment %s (%s)", registry->id,
908 strerror (errno));
909 return -1;
912 if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
913 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
914 jack_error ("Cannot mmap shm segment %s (%s)",
915 registry->id,
916 strerror (errno));
917 close (shm_fd);
918 return -1;
921 close (shm_fd);
922 return 0;
926 jack_attach_shm_read (jack_shm_info_t* si)
928 int shm_fd;
929 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
931 if ((shm_fd = shm_open (registry->id,
932 O_RDONLY, 0666)) < 0) {
933 jack_error ("Cannot open shm segment %s (%s)", registry->id,
934 strerror (errno));
935 return -1;
938 if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ,
939 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
940 jack_error ("Cannot mmap shm segment %s (%s)",
941 registry->id,
942 strerror (errno));
943 close (shm_fd);
944 return -1;
947 close (shm_fd);
948 return 0;
951 #elif WIN32
953 static int
954 jack_access_registry (jack_shm_info_t *ri)
956 /* registry must be locked */
957 HANDLE shm_fd;
958 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
960 /* try to open an existing segment */
962 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
963 int rc = GetLastError();
964 if (rc != ERROR_FILE_NOT_FOUND) {
965 jack_error ("Cannot open existing shm registry segment (%ld)", rc);
967 return rc;
970 if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
971 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
972 jack_remove_shm (&registry_id);
973 CloseHandle (shm_fd);
974 return EINVAL;
977 /* set up global pointers */
978 ri->index = JACK_SHM_REGISTRY_INDEX;
979 jack_shm_header = ri->ptr.attached_at;
980 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
982 //CloseHandle(shm_fd); // TO CHECK
983 return 0;
986 static int
987 jack_create_registry (jack_shm_info_t *ri)
989 /* registry must be locked */
990 HANDLE shm_fd;
992 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
994 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
995 0, PAGE_READWRITE,
996 0, JACK_SHM_REGISTRY_SIZE,
997 registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
998 int rc = GetLastError();
999 jack_error ("Cannot create shm registry segment (%ld)", rc);
1000 return rc;
1003 if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
1004 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
1005 jack_remove_shm (&registry_id);
1006 CloseHandle (shm_fd);
1007 return EINVAL;
1010 /* set up global pointers */
1011 ri->index = JACK_SHM_REGISTRY_INDEX;
1012 jack_shm_header = ri->ptr.attached_at;
1013 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1015 /* initialize registry contents */
1016 jack_shm_init_registry ();
1018 //CloseHandle(shm_fd); // TO CHECK
1019 return 0;
1022 static void
1023 jack_remove_shm (jack_shm_id_t *id)
1025 /* nothing to do */
1028 void
1029 jack_release_shm (jack_shm_info_t* si)
1031 /* registry may or may not be locked */
1032 if (si->ptr.attached_at != NULL) {
1033 UnmapViewOfFile (si->ptr.attached_at);
1037 void
1038 jack_release_lib_shm (jack_shm_info_t* si)
1040 jack_release_shm(si);
1044 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
1046 jack_shm_registry_t* registry;
1047 HANDLE shm_fd;
1048 int rc = -1;
1049 char name[SHM_NAME_MAX+1];
1051 if (jack_shm_lock_registry () < 0) {
1052 jack_error ("jack_shm_lock_registry fails...");
1053 return -1;
1056 if ((registry = jack_get_free_shm_info ()) == NULL) {
1057 jack_error ("shm registry full");
1058 goto unlock;
1061 snprintf (name, sizeof (name), "jack-%d-%d", GetUID(), registry->index);
1063 if (strlen (name) >= sizeof (registry->id)) {
1064 jack_error ("shm segment name too long %s", name);
1065 goto unlock;
1068 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
1069 0, PAGE_READWRITE,
1070 0, size,
1071 name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
1072 int rc = GetLastError();
1073 jack_error ("Cannot create shm segment (%ld)",rc);
1074 goto unlock;
1077 //CloseHandle (shm_fd); // TO CHECK
1079 registry->size = size;
1080 strncpy (registry->id, name, sizeof (registry->id));
1081 registry->allocator = _getpid();
1082 si->index = registry->index;
1083 si->ptr.attached_at = NULL; /* not attached */
1084 rc = 0; /* success */
1086 unlock:
1087 jack_shm_unlock_registry ();
1088 return rc;
1092 jack_attach_shm (jack_shm_info_t* si)
1094 HANDLE shm_fd;
1095 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1097 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1098 int rc = GetLastError();
1099 jack_error ("Cannot open shm segment (%ld)",rc);
1100 return -1;
1103 if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
1104 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
1105 jack_remove_shm (&registry_id);
1106 CloseHandle (shm_fd);
1107 return -1;
1110 //CloseHandle (shm_fd); // TO CHECK
1111 return 0;
1115 jack_attach_shm_read (jack_shm_info_t* si)
1117 HANDLE shm_fd;
1118 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1120 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1121 int rc = GetLastError();
1122 jack_error ("Cannot open shm segment (%ld)",rc);
1123 return -1;
1126 if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
1127 jack_error("Cannot mmap shm segment (%ld)", GetLastError());
1128 jack_remove_shm(&registry_id);
1129 CloseHandle(shm_fd);
1130 return -1;
1133 //CloseHandle (shm_fd); // TO CHECK
1134 return 0;
1137 #else
1139 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1140 * System V interface-dependent functions
1141 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1143 /* gain addressability to existing SHM registry segment
1145 * sets up global registry pointers, if successful
1147 * returns: 0 if existing registry accessed successfully
1148 * ENOENT if registry does not exist
1149 * EINVAL if registry exists, but has the wrong size
1150 * other nonzero error code if unable to access registry
1152 static int
1153 jack_access_registry (jack_shm_info_t *ri)
1155 /* registry must be locked */
1157 /* try without IPC_CREAT to get existing segment */
1158 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1159 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
1161 switch (errno) {
1163 case ENOENT: /* segment does not exist */
1164 return ENOENT;
1166 case EINVAL: /* segment exists, but too small */
1167 /* attempt minimum size access */
1168 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
1169 return EINVAL;
1171 default: /* or other error */
1172 jack_error ("unable to access shm registry (%s)",
1173 strerror (errno));
1174 return errno;
1178 if ((ri->ptr.attached_at = shmat (registry_id, 0, 0)) < 0) {
1179 jack_error ("Cannot attach shm registry segment (%s)",
1180 strerror (errno));
1181 return EINVAL;
1184 /* set up global pointers */
1185 ri->index = JACK_SHM_REGISTRY_INDEX;
1186 jack_shm_header = ri->ptr.attached_at;
1187 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1188 return 0;
1191 /* create a new SHM registry segment
1193 * sets up global registry pointers, if successful
1195 * returns: 0 if registry created successfully
1196 * nonzero error code if unable to allocate a new registry
1198 static int
1199 jack_create_registry (jack_shm_info_t *ri)
1201 /* registry must be locked */
1202 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1203 JACK_SHM_REGISTRY_SIZE,
1204 0666|IPC_CREAT)) < 0) {
1205 jack_error ("Cannot create shm registry segment (%s)",
1206 strerror (errno));
1207 return errno;
1210 if ((ri->ptr.attached_at = shmat (registry_id, 0, 0)) < 0) {
1211 jack_error ("Cannot attach shm registry segment (%s)",
1212 strerror (errno));
1213 return EINVAL;
1216 /* set up global pointers */
1217 ri->index = JACK_SHM_REGISTRY_INDEX;
1218 jack_shm_header = ri->ptr.attached_at;
1219 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1221 /* initialize registry contents */
1222 jack_shm_init_registry ();
1223 return 0;
1226 static void
1227 jack_remove_shm (jack_shm_id_t *id)
1229 /* registry may or may not be locked */
1230 shmctl (*id, IPC_RMID, NULL);
1233 void
1234 jack_release_shm (jack_shm_info_t* si)
1236 /* registry may or may not be locked */
1237 if (si->ptr.attached_at != MAP_FAILED) {
1238 shmdt (si->ptr.attached_at);
1242 void
1243 jack_release_lib_shm (jack_shm_info_t* si)
1245 jack_release_shm(si);
1249 jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
1250 jack_shm_info_t* si)
1252 int shmflags;
1253 int shmid;
1254 int rc = -1;
1255 jack_shm_registry_t* registry;
1257 if (jack_shm_lock_registry () < 0) {
1258 jack_error ("jack_shm_lock_registry fails...");
1259 return -1;
1262 if ((registry = jack_get_free_shm_info ())) {
1264 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
1266 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
1268 registry->size = size;
1269 registry->id = shmid;
1270 registry->allocator = getpid();
1271 si->index = registry->index;
1272 si->ptr.attached_at = MAP_FAILED; /* not attached */
1273 rc = 0;
1275 } else {
1276 jack_error ("Cannot create shm segment %s (%s)",
1277 name_not_used, strerror (errno));
1281 jack_shm_unlock_registry ();
1282 return rc;
1286 jack_attach_shm (jack_shm_info_t* si)
1288 if ((si->ptr.attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
1289 jack_error ("Cannot attach shm segment (%s)",
1290 strerror (errno));
1291 jack_release_shm_info (si->index);
1292 return -1;
1294 return 0;
1298 jack_attach_shm_read (jack_shm_info_t* si)
1300 if ((si->ptr.attached_at = shmat (jack_shm_registry[si->index].id, 0, SHM_RDONLY)) < 0) {
1301 jack_error ("Cannot attach shm segment (%s)",
1302 strerror (errno));
1303 jack_release_shm_info (si->index);
1304 return -1;
1306 return 0;
1309 #endif /* !USE_POSIX_SHM */