Merge pull request #23 from jackaudio/device_reservation_fixes
[jack2.git] / common / shm.c
blob22d7984008612c63dc8f654e0246da3cfaa18657
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>
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 #include <psapi.h>
149 #include <lmcons.h>
151 static BOOL check_process_running(DWORD process_id)
153 DWORD aProcesses[2048], cbNeeded, cProcesses;
154 unsigned int i;
156 // Enumerate all processes
157 if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
158 return FALSE;
161 // Calculate how many process identifiers were returned.
162 cProcesses = cbNeeded / sizeof(DWORD);
164 for (i = 0; i < cProcesses; i++) {
165 if (aProcesses[i] == process_id) {
166 // Process process_id is running...
167 return TRUE;
170 return FALSE;
173 static int
174 semaphore_init () {return 0;}
176 static int
177 semaphore_add (int value) {return 0;}
179 #else
180 /* all semaphore errors are fatal -- issue message, but do not return */
181 static void
182 semaphore_error (char *msg)
184 jack_error ("JACK semaphore error: %s (%s)",
185 msg, strerror (errno));
188 static int
189 semaphore_init ()
191 key_t semkey = JACK_SEMAPHORE_KEY;
192 struct sembuf sbuf;
193 int create_flags = IPC_CREAT | IPC_EXCL
194 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
196 /* Get semaphore ID associated with this key. */
197 if ((semid = semget(semkey, 0, 0)) == -1) {
199 /* Semaphore does not exist - Create. */
200 if ((semid = semget(semkey, 1, create_flags)) != -1) {
202 /* Initialize the semaphore, allow one owner. */
203 sbuf.sem_num = 0;
204 sbuf.sem_op = 1;
205 sbuf.sem_flg = 0;
206 if (semop(semid, &sbuf, 1) == -1) {
207 semaphore_error ("semop");
208 return -1;
211 } else if (errno == EEXIST) {
212 if ((semid = semget(semkey, 0, 0)) == -1) {
213 semaphore_error ("semget");
214 return -1;
217 } else {
218 semaphore_error ("semget creation");
219 return -1;
223 return 0;
226 static inline int
227 semaphore_add (int value)
229 struct sembuf sbuf;
231 sbuf.sem_num = 0;
232 sbuf.sem_op = value;
233 sbuf.sem_flg = SEM_UNDO;
235 if (semop(semid, &sbuf, 1) == -1) {
236 semaphore_error ("semop");
237 return -1;
240 return 0;
243 #endif
245 static int
246 jack_shm_lock_registry (void)
248 if (semid == -1) {
249 if (semaphore_init () < 0)
250 return -1;
253 return semaphore_add (-1);
256 static void
257 jack_shm_unlock_registry (void)
259 semaphore_add (1);
262 static void
263 jack_shm_init_registry ()
265 /* registry must be locked */
266 int i;
268 memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
270 jack_shm_header->magic = JACK_SHM_MAGIC;
271 //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
272 jack_shm_header->type = jack_shmtype;
273 jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
274 jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
275 jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
277 for (i = 0; i < MAX_SHM_ID; ++i) {
278 jack_shm_registry[i].index = i;
282 static int
283 jack_shm_validate_registry ()
285 /* registry must be locked */
287 if ((jack_shm_header->magic == JACK_SHM_MAGIC)
288 //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
289 && (jack_shm_header->type == jack_shmtype)
290 && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
291 && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
292 && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
294 return 0; /* registry OK */
297 return -1;
300 /* set a unique per-user, per-server shm prefix string
302 * According to the POSIX standard:
304 * "The name argument conforms to the construction rules for a
305 * pathname. If name begins with the slash character, then processes
306 * calling shm_open() with the same value of name refer to the same
307 * shared memory object, as long as that name has not been
308 * removed. If name does not begin with the slash character, the
309 * effect is implementation-defined. The interpretation of slash
310 * characters other than the leading slash character in name is
311 * implementation-defined."
313 * Since the Linux implementation does not allow slashes *within* the
314 * name, in the interest of portability we use colons instead.
316 static void
317 jack_set_server_prefix (const char *server_name)
319 #ifdef WIN32
320 char buffer[UNLEN+1]={0};
321 DWORD len = UNLEN+1;
322 GetUserName(buffer, &len);
323 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
324 "jack-%s:%s:", buffer, server_name);
325 #else
326 snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
327 "jack-%d:%s:", GetUID(), server_name);
328 #endif
331 /* gain server addressability to shared memory registration segment
333 * returns: 0 if successful
335 static int
336 jack_server_initialize_shm (int new_registry)
338 int rc;
340 if (jack_shm_header)
341 return 0; /* already initialized */
343 if (jack_shm_lock_registry () < 0) {
344 jack_error ("jack_shm_lock_registry fails...");
345 return -1;
348 rc = jack_access_registry (&registry_info);
350 if (new_registry) {
351 jack_remove_shm (&registry_id);
352 rc = ENOENT;
355 switch (rc) {
356 case ENOENT: /* registry does not exist */
357 rc = jack_create_registry (&registry_info);
358 break;
359 case 0: /* existing registry */
360 if (jack_shm_validate_registry () == 0)
361 break;
362 /* else it was invalid, so fall through */
363 case EINVAL: /* bad registry */
364 /* Apparently, this registry was created by an older
365 * JACK version. Delete it so we can try again. */
366 jack_release_shm (&registry_info);
367 jack_remove_shm (&registry_id);
368 if ((rc = jack_create_registry (&registry_info)) != 0) {
369 jack_error ("incompatible shm registry (%s)",
370 strerror (errno));
371 #ifndef USE_POSIX_SHM
372 jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
373 JACK_SHM_REGISTRY_KEY);
374 #endif
376 break;
377 default: /* failure return code */
378 break;
381 jack_shm_unlock_registry ();
382 return rc;
385 /* gain client addressability to shared memory registration segment
387 * NOTE: this function is no longer used for server initialization,
388 * instead it calls jack_register_server().
390 * returns: 0 if successful
393 jack_initialize_shm (const char *server_name)
395 int rc;
397 if (jack_shm_header)
398 return 0; /* already initialized */
400 jack_set_server_prefix (server_name);
402 if (jack_shm_lock_registry () < 0) {
403 jack_error ("jack_shm_lock_registry fails...");
404 return -1;
407 if ((rc = jack_access_registry (&registry_info)) == 0) {
408 if ((rc = jack_shm_validate_registry ()) != 0) {
409 jack_error ("Incompatible shm registry, "
410 "are jackd and libjack in sync?");
413 jack_shm_unlock_registry ();
415 return rc;
419 char* jack_shm_addr (jack_shm_info_t* si)
421 return (char*)si->ptr.attached_at;
424 void
425 jack_destroy_shm (jack_shm_info_t* si)
427 /* must NOT have the registry locked */
428 if (si->index == JACK_SHM_NULL_INDEX)
429 return; /* segment not allocated */
431 jack_remove_shm (&jack_shm_registry[si->index].id);
432 jack_release_shm_info (si->index);
435 jack_shm_registry_t *
436 jack_get_free_shm_info ()
438 /* registry must be locked */
439 jack_shm_registry_t* si = NULL;
440 int i;
442 for (i = 0; i < MAX_SHM_ID; ++i) {
443 if (jack_shm_registry[i].size == 0) {
444 break;
448 if (i < MAX_SHM_ID) {
449 si = &jack_shm_registry[i];
452 return si;
455 static void
456 jack_release_shm_entry (jack_shm_registry_index_t index)
458 /* the registry must be locked */
459 jack_shm_registry[index].size = 0;
460 jack_shm_registry[index].allocator = 0;
461 memset (&jack_shm_registry[index].id, 0,
462 sizeof (jack_shm_registry[index].id));
466 jack_release_shm_info (jack_shm_registry_index_t index)
468 /* must NOT have the registry locked */
469 if (jack_shm_registry[index].allocator == GetPID()) {
470 if (jack_shm_lock_registry () < 0) {
471 jack_error ("jack_shm_lock_registry fails...");
472 return -1;
474 jack_release_shm_entry (index);
475 jack_shm_unlock_registry ();
478 return 0;
481 /* Claim server_name for this process.
483 * returns 0 if successful
484 * EEXIST if server_name was already active for this user
485 * ENOSPC if server registration limit reached
486 * ENOMEM if unable to access shared memory registry
489 jack_register_server (const char *server_name, int new_registry)
491 int i, res = 0;
493 jack_set_server_prefix (server_name);
495 if (jack_server_initialize_shm (new_registry))
496 return ENOMEM;
498 if (jack_shm_lock_registry () < 0) {
499 jack_error ("jack_shm_lock_registry fails...");
500 return -1;
503 /* See if server_name already registered. Since server names
504 * are per-user, we register the unique server prefix string.
506 for (i = 0; i < MAX_SERVERS; i++) {
508 if (strncmp (jack_shm_header->server[i].name,
509 jack_shm_server_prefix,
510 JACK_SERVER_NAME_SIZE) != 0)
511 continue; /* no match */
513 if (jack_shm_header->server[i].pid == GetPID()){
514 res = 0; /* it's me */
515 goto unlock;
518 /* see if server still exists */
519 #ifdef WIN32
520 if (check_process_running(jack_shm_header->server[i].pid)) {
521 res = EEXIST; /* other server running */
522 goto unlock;
524 #else
525 if (kill (jack_shm_header->server[i].pid, 0) == 0) {
526 res = EEXIST; /* other server running */
527 goto unlock;
529 #endif
531 /* it's gone, reclaim this entry */
532 memset (&jack_shm_header->server[i], 0,
533 sizeof (jack_shm_server_t));
536 /* find a free entry */
537 for (i = 0; i < MAX_SERVERS; i++) {
538 if (jack_shm_header->server[i].pid == 0)
539 break;
542 if (i >= MAX_SERVERS){
543 res = ENOSPC; /* out of space */
544 goto unlock;
547 /* claim it */
548 jack_shm_header->server[i].pid = GetPID();
549 strncpy (jack_shm_header->server[i].name,
550 jack_shm_server_prefix,
551 JACK_SERVER_NAME_SIZE);
553 unlock:
554 jack_shm_unlock_registry ();
555 return res;
558 /* release server_name registration */
560 jack_unregister_server (const char *server_name /* unused */)
562 int i;
563 if (jack_shm_lock_registry () < 0) {
564 jack_error ("jack_shm_lock_registry fails...");
565 return -1;
568 for (i = 0; i < MAX_SERVERS; i++) {
569 if (jack_shm_header->server[i].pid == GetPID()) {
570 memset (&jack_shm_header->server[i], 0,
571 sizeof (jack_shm_server_t));
575 jack_shm_unlock_registry ();
576 return 0;
579 /* called for server startup and termination */
581 jack_cleanup_shm ()
583 int i;
584 int destroy;
585 jack_shm_info_t copy;
587 if (jack_shm_lock_registry () < 0) {
588 jack_error ("jack_shm_lock_registry fails...");
589 return -1;
592 for (i = 0; i < MAX_SHM_ID; i++) {
593 jack_shm_registry_t* r;
595 r = &jack_shm_registry[i];
596 memcpy (&copy, r, sizeof (jack_shm_info_t));
597 destroy = FALSE;
599 /* ignore unused entries */
600 if (r->allocator == 0)
601 continue;
603 /* is this my shm segment? */
604 if (r->allocator == GetPID()) {
606 /* allocated by this process, so unattach
607 and destroy. */
608 jack_release_shm (&copy);
609 destroy = TRUE;
611 } else {
613 /* see if allocator still exists */
614 #ifdef WIN32 // steph
615 //jack_info("TODO: kill API not available !!");
616 #else
617 if (kill (r->allocator, 0)) {
618 if (errno == ESRCH) {
619 /* allocator no longer exists,
620 * so destroy */
621 destroy = TRUE;
624 #endif
627 if (destroy) {
629 int index = copy.index;
631 if ((index >= 0) && (index < MAX_SHM_ID)) {
632 jack_remove_shm (&jack_shm_registry[index].id);
633 jack_release_shm_entry (index);
635 r->size = 0;
636 r->allocator = 0;
640 jack_shm_unlock_registry ();
641 return TRUE;
644 /* resize a shared memory segment
646 * There is no way to resize a System V shm segment. Resizing is
647 * possible with POSIX shm, but not with the non-conformant Mac OS X
648 * implementation. Since POSIX shm is mainly used on that platform,
649 * it's simpler to treat them both the same.
651 * So, we always resize by deleting and reallocating. This is
652 * tricky, because the old segment will not disappear until
653 * all the clients have released it. We only do what we can
654 * from here.
656 * This is not done under a single lock. I don't even want to think
657 * about all the things that could possibly go wrong if multple
658 * processes tried to resize the same segment concurrently. That
659 * probably doesn't happen.
662 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
664 jack_shm_id_t id;
666 /* The underlying type of `id' differs for SYSV and POSIX */
667 memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
669 jack_release_shm (si);
670 jack_destroy_shm (si);
672 if (jack_shmalloc ((char *) id, size, si)) {
673 return -1;
676 return jack_attach_shm (si);
680 jack_attach_lib_shm (jack_shm_info_t* si)
682 int res = jack_attach_shm(si);
683 if (res == 0)
684 si->size = jack_shm_registry[si->index].size; // Keep size in si struct
685 return res;
689 jack_attach_lib_shm_read (jack_shm_info_t* si)
691 int res = jack_attach_shm_read(si);
692 if (res == 0)
693 si->size = jack_shm_registry[si->index].size; // Keep size in si struct
694 return res;
697 #ifdef USE_POSIX_SHM
699 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
700 * POSIX interface-dependent functions
701 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
703 /* gain addressability to existing SHM registry segment
705 * sets up global registry pointers, if successful
707 * returns: 0 if existing registry accessed successfully
708 * ENOENT if registry does not exist
709 * EINVAL if registry exists, but has the wrong size
711 static int
712 jack_access_registry (jack_shm_info_t *ri)
714 /* registry must be locked */
715 int shm_fd;
717 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
719 /* try to open an existing segment */
720 if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
721 int rc = errno;
722 if (errno != ENOENT) {
723 jack_error ("Cannot open existing shm registry segment"
724 " (%s)", strerror (errno));
726 close (shm_fd);
727 return rc;
730 if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
731 PROT_READ|PROT_WRITE,
732 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
733 jack_error ("Cannot mmap shm registry segment (%s)",
734 strerror (errno));
735 close (shm_fd);
736 return EINVAL;
739 /* set up global pointers */
740 ri->index = JACK_SHM_REGISTRY_INDEX;
741 jack_shm_header = ri->ptr.attached_at;
742 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
744 close (shm_fd); // steph
745 return 0;
748 /* create a new SHM registry segment
750 * sets up global registry pointers, if successful
752 * returns: 0 if registry created successfully
753 * nonzero error code if unable to allocate a new registry
755 static int
756 jack_create_registry (jack_shm_info_t *ri)
758 /* registry must be locked */
759 int shm_fd;
761 strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
763 if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
764 int rc = errno;
765 jack_error ("Cannot create shm registry segment (%s)",
766 strerror (errno));
767 return rc;
770 /* Previous shm_open result depends of the actual value of umask, force correct file permisssion here */
771 if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
772 jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
775 /* Set the desired segment size. NOTE: the non-conformant Mac
776 * OS X POSIX shm only allows ftruncate() on segment creation.
778 if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
779 int rc = errno;
780 jack_error ("Cannot set registry size (%s)", strerror (errno));
781 jack_remove_shm (&registry_id);
782 close (shm_fd);
783 return rc;
786 if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
787 PROT_READ|PROT_WRITE,
788 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
789 jack_error ("Cannot mmap shm registry segment (%s)",
790 strerror (errno));
791 jack_remove_shm (&registry_id);
792 close (shm_fd);
793 return EINVAL;
796 /* set up global pointers */
797 ri->index = JACK_SHM_REGISTRY_INDEX;
798 jack_shm_header = ri->ptr.attached_at;
799 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
801 /* initialize registry contents */
802 jack_shm_init_registry ();
803 close (shm_fd); // steph
804 return 0;
807 static void
808 jack_remove_shm (jack_shm_id_t *id)
810 /* registry may or may not be locked */
811 shm_unlink ((char *) id);
814 void
815 jack_release_shm (jack_shm_info_t* si)
817 /* registry may or may not be locked */
818 if (si->ptr.attached_at != MAP_FAILED) {
819 munmap (si->ptr.attached_at, jack_shm_registry[si->index].size);
823 void
824 jack_release_lib_shm (jack_shm_info_t* si)
826 /* registry may or may not be locked */
827 if (si->ptr.attached_at != MAP_FAILED) {
828 munmap (si->ptr.attached_at, si->size);
832 /* allocate a POSIX shared memory segment */
834 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
836 jack_shm_registry_t* registry;
837 int shm_fd;
838 int rc = -1;
839 char name[SHM_NAME_MAX+1];
841 if (jack_shm_lock_registry () < 0) {
842 jack_error ("jack_shm_lock_registry fails...");
843 return -1;
846 if ((registry = jack_get_free_shm_info ()) == NULL) {
847 jack_error ("shm registry full");
848 goto unlock;
851 /* On Mac OS X, the maximum length of a shared memory segment
852 * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
853 * defined by the standard). Unfortunately, Apple sets this
854 * value so small (about 31 bytes) that it is useless for
855 * actual names. So, we construct a short name from the
856 * registry index for uniqueness and ignore the shm_name
857 * parameter. Bah!
859 snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index);
861 if (strlen (name) >= sizeof (registry->id)) {
862 jack_error ("shm segment name too long %s", name);
863 goto unlock;
866 if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
867 jack_error ("Cannot create shm segment %s (%s)",
868 name, strerror (errno));
869 goto unlock;
872 if (ftruncate (shm_fd, size) < 0) {
873 jack_error ("Cannot set size of engine shm "
874 "registry 0 (%s)",
875 strerror (errno));
876 close (shm_fd);
877 goto unlock;
880 close (shm_fd);
881 registry->size = size;
882 strncpy (registry->id, name, sizeof (registry->id));
883 registry->allocator = GetPID();
884 si->index = registry->index;
885 si->ptr.attached_at = MAP_FAILED; /* not attached */
886 rc = 0; /* success */
888 unlock:
889 jack_shm_unlock_registry ();
890 return rc;
894 jack_attach_shm (jack_shm_info_t* si)
896 int shm_fd;
897 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
899 if ((shm_fd = shm_open (registry->id,
900 O_RDWR, 0666)) < 0) {
901 jack_error ("Cannot open shm segment %s (%s)", registry->id,
902 strerror (errno));
903 return -1;
906 if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
907 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
908 jack_error ("Cannot mmap shm segment %s (%s)",
909 registry->id,
910 strerror (errno));
911 close (shm_fd);
912 return -1;
915 close (shm_fd);
916 return 0;
920 jack_attach_shm_read (jack_shm_info_t* si)
922 int shm_fd;
923 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
925 if ((shm_fd = shm_open (registry->id,
926 O_RDONLY, 0666)) < 0) {
927 jack_error ("Cannot open shm segment %s (%s)", registry->id,
928 strerror (errno));
929 return -1;
932 if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ,
933 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
934 jack_error ("Cannot mmap shm segment %s (%s)",
935 registry->id,
936 strerror (errno));
937 close (shm_fd);
938 return -1;
941 close (shm_fd);
942 return 0;
945 #elif WIN32
947 static int
948 jack_access_registry (jack_shm_info_t *ri)
950 /* registry must be locked */
951 HANDLE shm_fd;
952 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
954 /* try to open an existing segment */
956 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
957 int rc = GetLastError();
958 if (rc != ERROR_FILE_NOT_FOUND) {
959 jack_error ("Cannot open existing shm registry segment (%ld)", rc);
961 return rc;
964 if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
965 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
966 jack_remove_shm (&registry_id);
967 CloseHandle (shm_fd);
968 return EINVAL;
971 /* set up global pointers */
972 ri->index = JACK_SHM_REGISTRY_INDEX;
973 jack_shm_header = ri->ptr.attached_at;
974 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
976 //CloseHandle(shm_fd); // TO CHECK
977 return 0;
980 static int
981 jack_create_registry (jack_shm_info_t *ri)
983 /* registry must be locked */
984 HANDLE shm_fd;
986 strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
988 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
989 0, PAGE_READWRITE,
990 0, JACK_SHM_REGISTRY_SIZE,
991 registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
992 int rc = GetLastError();
993 jack_error ("Cannot create shm registry segment (%ld)", rc);
994 return rc;
997 if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
998 jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
999 jack_remove_shm (&registry_id);
1000 CloseHandle (shm_fd);
1001 return EINVAL;
1004 /* set up global pointers */
1005 ri->index = JACK_SHM_REGISTRY_INDEX;
1006 jack_shm_header = ri->ptr.attached_at;
1007 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1009 /* initialize registry contents */
1010 jack_shm_init_registry ();
1012 //CloseHandle(shm_fd); // TO CHECK
1013 return 0;
1016 static void
1017 jack_remove_shm (jack_shm_id_t *id)
1019 /* nothing to do */
1022 void
1023 jack_release_shm (jack_shm_info_t* si)
1025 /* registry may or may not be locked */
1026 if (si->ptr.attached_at != NULL) {
1027 UnmapViewOfFile (si->ptr.attached_at);
1031 void
1032 jack_release_lib_shm (jack_shm_info_t* si)
1034 jack_release_shm(si);
1038 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
1040 jack_shm_registry_t* registry;
1041 HANDLE shm_fd;
1042 int rc = -1;
1043 char name[SHM_NAME_MAX+1];
1045 if (jack_shm_lock_registry () < 0) {
1046 jack_error ("jack_shm_lock_registry fails...");
1047 return -1;
1050 if ((registry = jack_get_free_shm_info ()) == NULL) {
1051 jack_error ("shm registry full");
1052 goto unlock;
1055 snprintf (name, sizeof (name), "jack-%d-%d", GetUID(), registry->index);
1057 if (strlen (name) >= sizeof (registry->id)) {
1058 jack_error ("shm segment name too long %s", name);
1059 goto unlock;
1062 if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
1063 0, PAGE_READWRITE,
1064 0, size,
1065 name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
1066 int rc = GetLastError();
1067 jack_error ("Cannot create shm segment (%ld)",rc);
1068 goto unlock;
1071 //CloseHandle (shm_fd); // TO CHECK
1073 registry->size = size;
1074 strncpy (registry->id, name, sizeof (registry->id));
1075 registry->allocator = _getpid();
1076 si->index = registry->index;
1077 si->ptr.attached_at = NULL; /* not attached */
1078 rc = 0; /* success */
1080 unlock:
1081 jack_shm_unlock_registry ();
1082 return rc;
1086 jack_attach_shm (jack_shm_info_t* si)
1088 HANDLE shm_fd;
1089 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1091 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1092 int rc = GetLastError();
1093 jack_error ("Cannot open shm segment (%ld)",rc);
1094 return -1;
1097 if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
1098 jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
1099 jack_remove_shm (&registry_id);
1100 CloseHandle (shm_fd);
1101 return -1;
1104 //CloseHandle (shm_fd); // TO CHECK
1105 return 0;
1109 jack_attach_shm_read (jack_shm_info_t* si)
1111 HANDLE shm_fd;
1112 jack_shm_registry_t *registry = &jack_shm_registry[si->index];
1114 if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
1115 int rc = GetLastError();
1116 jack_error ("Cannot open shm segment (%ld)",rc);
1117 return -1;
1120 if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
1121 jack_error("Cannot mmap shm segment (%ld)", GetLastError());
1122 jack_remove_shm(&registry_id);
1123 CloseHandle(shm_fd);
1124 return -1;
1127 //CloseHandle (shm_fd); // TO CHECK
1128 return 0;
1131 #else
1133 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1134 * System V interface-dependent functions
1135 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1137 /* gain addressability to existing SHM registry segment
1139 * sets up global registry pointers, if successful
1141 * returns: 0 if existing registry accessed successfully
1142 * ENOENT if registry does not exist
1143 * EINVAL if registry exists, but has the wrong size
1144 * other nonzero error code if unable to access registry
1146 static int
1147 jack_access_registry (jack_shm_info_t *ri)
1149 /* registry must be locked */
1151 /* try without IPC_CREAT to get existing segment */
1152 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1153 JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
1155 switch (errno) {
1157 case ENOENT: /* segment does not exist */
1158 return ENOENT;
1160 case EINVAL: /* segment exists, but too small */
1161 /* attempt minimum size access */
1162 registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
1163 return EINVAL;
1165 default: /* or other error */
1166 jack_error ("unable to access shm registry (%s)",
1167 strerror (errno));
1168 return errno;
1172 if ((ri->ptr.attached_at = shmat (registry_id, 0, 0)) < 0) {
1173 jack_error ("Cannot attach shm registry segment (%s)",
1174 strerror (errno));
1175 return EINVAL;
1178 /* set up global pointers */
1179 ri->index = JACK_SHM_REGISTRY_INDEX;
1180 jack_shm_header = ri->ptr.attached_at;
1181 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1182 return 0;
1185 /* create a new SHM registry segment
1187 * sets up global registry pointers, if successful
1189 * returns: 0 if registry created successfully
1190 * nonzero error code if unable to allocate a new registry
1192 static int
1193 jack_create_registry (jack_shm_info_t *ri)
1195 /* registry must be locked */
1196 if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
1197 JACK_SHM_REGISTRY_SIZE,
1198 0666|IPC_CREAT)) < 0) {
1199 jack_error ("Cannot create shm registry segment (%s)",
1200 strerror (errno));
1201 return errno;
1204 if ((ri->ptr.attached_at = shmat (registry_id, 0, 0)) < 0) {
1205 jack_error ("Cannot attach shm registry segment (%s)",
1206 strerror (errno));
1207 return EINVAL;
1210 /* set up global pointers */
1211 ri->index = JACK_SHM_REGISTRY_INDEX;
1212 jack_shm_header = ri->ptr.attached_at;
1213 jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
1215 /* initialize registry contents */
1216 jack_shm_init_registry ();
1217 return 0;
1220 static void
1221 jack_remove_shm (jack_shm_id_t *id)
1223 /* registry may or may not be locked */
1224 shmctl (*id, IPC_RMID, NULL);
1227 void
1228 jack_release_shm (jack_shm_info_t* si)
1230 /* registry may or may not be locked */
1231 if (si->ptr.attached_at != MAP_FAILED) {
1232 shmdt (si->ptr.attached_at);
1236 void
1237 jack_release_lib_shm (jack_shm_info_t* si)
1239 jack_release_shm(si);
1243 jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
1244 jack_shm_info_t* si)
1246 int shmflags;
1247 int shmid;
1248 int rc = -1;
1249 jack_shm_registry_t* registry;
1251 if (jack_shm_lock_registry () < 0) {
1252 jack_error ("jack_shm_lock_registry fails...");
1253 return -1;
1256 if ((registry = jack_get_free_shm_info ())) {
1258 shmflags = 0666 | IPC_CREAT | IPC_EXCL;
1260 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
1262 registry->size = size;
1263 registry->id = shmid;
1264 registry->allocator = getpid();
1265 si->index = registry->index;
1266 si->ptr.attached_at = MAP_FAILED; /* not attached */
1267 rc = 0;
1269 } else {
1270 jack_error ("Cannot create shm segment %s (%s)",
1271 name_not_used, strerror (errno));
1275 jack_shm_unlock_registry ();
1276 return rc;
1280 jack_attach_shm (jack_shm_info_t* si)
1282 if ((si->ptr.attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
1283 jack_error ("Cannot attach shm segment (%s)",
1284 strerror (errno));
1285 jack_release_shm_info (si->index);
1286 return -1;
1288 return 0;
1292 jack_attach_shm_read (jack_shm_info_t* si)
1294 if ((si->ptr.attached_at = shmat (jack_shm_registry[si->index].id, 0, SHM_RDONLY)) < 0) {
1295 jack_error ("Cannot attach shm segment (%s)",
1296 strerror (errno));
1297 jack_release_shm_info (si->index);
1298 return -1;
1300 return 0;
1303 #endif /* !USE_POSIX_SHM */