|
- /* This module provides a set of abstract shared memory interfaces
- * with support using both System V and POSIX shared memory
- * implementations. The code is divided into three sections:
- *
- * - common (interface-independent) code
- * - POSIX implementation
- * - System V implementation
- * - Windows implementation
- *
- * The implementation used is determined by whether USE_POSIX_SHM was
- * set in the ./configure step.
- */
-
- /*
- Copyright (C) 2001-2003 Paul Davis
- Copyright (C) 2005-2012 Grame
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- */
-
- #include "JackConstants.h"
-
- #ifdef WIN32
- #include <process.h>
- #include <stdio.h>
- #else
-
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <string.h>
- #include <signal.h>
- #include <limits.h>
- #include <errno.h>
- #include <dirent.h>
- #include <sys/mman.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/shm.h>
- #include <sys/sem.h>
- #include <stdlib.h>
- #include "promiscuous.h"
-
- #endif
-
- #include "shm.h"
- #include "JackError.h"
-
- static int GetUID()
- {
- #ifdef WIN32
- return _getpid();
- //#error "No getuid function available"
- #else
- return geteuid();
- #endif
- }
-
- static int GetPID()
- {
- #ifdef WIN32
- return _getpid();
- #else
- return getpid();
- #endif
- }
-
- #ifdef USE_POSIX_SHM
- static const jack_shmtype_t jack_shmtype = shm_POSIX;
- #elif WIN32
- static const jack_shmtype_t jack_shmtype = shm_WIN32;
- #else
- static const jack_shmtype_t jack_shmtype = shm_SYSV;
- #endif
-
- /* interface-dependent forward declarations */
- static int jack_access_registry (jack_shm_info_t *ri);
- static int jack_create_registry (jack_shm_info_t *ri);
- static void jack_remove_shm (const jack_shm_id_t id);
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * common interface-independent section
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
- /* The JACK SHM registry is a chunk of memory for keeping track of the
- * shared memory used by each active JACK server. This allows the
- * server to clean up shared memory when it exits. To avoid memory
- * leakage due to kill -9, crashes or debugger-driven exits, this
- * cleanup is also done when a new instance of that server starts.
- */
-
- /* per-process global data for the SHM interfaces */
- #ifdef USE_POSIX_SHM
- static const jack_shm_id_t registry_id = "/jack-shm-registry";
- #elif WIN32
- static const jack_shm_id_t registry_id = "jack-shm-registry";
- #else
- static jack_shm_id_t registry_id; /* SHM id for the registry */
- #endif
-
- #ifdef WIN32
- static jack_shm_info_t registry_info = {/* SHM info for the registry */
- JACK_SHM_NULL_INDEX,
- 0,
- { NULL }
- };
- #else
- static jack_shm_info_t registry_info = { /* SHM info for the registry */
- .index = JACK_SHM_NULL_INDEX,
- .ptr.attached_at = MAP_FAILED
- };
- #endif
-
- /* pointers to registry header and array */
- static jack_shm_header_t *jack_shm_header = NULL;
- static jack_shm_registry_t *jack_shm_registry = NULL;
-
- /* jack_shm_lock_registry() serializes updates to the shared memory
- * segment JACK uses to keep track of the SHM segments allocated to
- * all its processes, including multiple servers.
- *
- * This is not a high-contention lock, but it does need to work across
- * multiple processes. High transaction rates and realtime safety are
- * not required. Any solution needs to at least be portable to POSIX
- * and POSIX-like systems.
- *
- * We must be particularly careful to ensure that the lock be released
- * if the owning process terminates abnormally. Otherwise, a segfault
- * or kill -9 at the wrong moment could prevent JACK from ever running
- * again on that machine until after a reboot.
- */
-
- #define JACK_SEMAPHORE_KEY 0x282929
- #ifndef USE_POSIX_SHM
- #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
- #endif
-
- static int semid = -1;
-
- #ifdef WIN32
-
- #include <psapi.h>
- #include <lmcons.h>
-
- static BOOL check_process_running(DWORD process_id)
- {
- DWORD aProcesses[2048], cbNeeded, cProcesses;
- unsigned int i;
-
- // Enumerate all processes
- if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
- return FALSE;
- }
-
- // Calculate how many process identifiers were returned.
- cProcesses = cbNeeded / sizeof(DWORD);
-
- for (i = 0; i < cProcesses; i++) {
- if (aProcesses[i] == process_id) {
- // Process process_id is running...
- return TRUE;
- }
- }
- return FALSE;
- }
-
- static int
- semaphore_init () {return 0;}
-
- static int
- semaphore_add (int value) {return 0;}
-
- #else
- /* all semaphore errors are fatal -- issue message, but do not return */
- static void
- semaphore_error (char *msg)
- {
- jack_error ("JACK semaphore error: %s (%s)",
- msg, strerror (errno));
- }
-
- static int
- semaphore_init ()
- {
- key_t semkey = JACK_SEMAPHORE_KEY;
- struct sembuf sbuf;
- int create_flags = IPC_CREAT | IPC_EXCL
- | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
-
- /* Get semaphore ID associated with this key. */
- if ((semid = semget(semkey, 0, 0)) == -1) {
-
- /* Semaphore does not exist - Create. */
- if ((semid = semget(semkey, 1, create_flags)) != -1) {
-
- /* Initialize the semaphore, allow one owner. */
- sbuf.sem_num = 0;
- sbuf.sem_op = 1;
- sbuf.sem_flg = 0;
- if (semop(semid, &sbuf, 1) == -1) {
- semaphore_error ("semop");
- return -1;
- }
-
- } else if (errno == EEXIST) {
- if ((semid = semget(semkey, 0, 0)) == -1) {
- semaphore_error ("semget");
- return -1;
- }
-
- } else {
- semaphore_error ("semget creation");
- return -1;
- }
- }
-
- return 0;
- }
-
- static inline int
- semaphore_add (int value)
- {
- struct sembuf sbuf;
-
- sbuf.sem_num = 0;
- sbuf.sem_op = value;
- sbuf.sem_flg = SEM_UNDO;
-
- if (semop(semid, &sbuf, 1) == -1) {
- semaphore_error ("semop");
- return -1;
- }
-
- return 0;
- }
-
- #endif
-
- static int
- jack_shm_lock_registry (void)
- {
- if (semid == -1) {
- if (semaphore_init () < 0)
- return -1;
- }
-
- return semaphore_add (-1);
- }
-
- static void
- jack_shm_unlock_registry (void)
- {
- semaphore_add (1);
- }
-
- static void
- jack_shm_init_registry ()
- {
- /* registry must be locked */
- int i;
-
- memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
-
- jack_shm_header->magic = JACK_SHM_MAGIC;
- //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
- jack_shm_header->type = jack_shmtype;
- jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
- jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
- jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
-
- for (i = 0; i < MAX_SHM_ID; ++i) {
- jack_shm_registry[i].index = i;
- }
- }
-
- static int
- jack_shm_validate_registry ()
- {
- /* registry must be locked */
-
- if ((jack_shm_header->magic == JACK_SHM_MAGIC)
- //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
- && (jack_shm_header->type == jack_shmtype)
- && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
- && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
- && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
-
- return 0; /* registry OK */
- }
-
- return -1;
- }
-
- /* set a unique per-user, per-server shm prefix string
- *
- * According to the POSIX standard:
- *
- * "The name argument conforms to the construction rules for a
- * pathname. If name begins with the slash character, then processes
- * calling shm_open() with the same value of name refer to the same
- * shared memory object, as long as that name has not been
- * removed. If name does not begin with the slash character, the
- * effect is implementation-defined. The interpretation of slash
- * characters other than the leading slash character in name is
- * implementation-defined."
- *
- * Since the Linux implementation does not allow slashes *within* the
- * name, in the interest of portability we use colons instead.
- */
- static void
- jack_get_server_prefix (const char* const server_name, char* const prefix, const size_t size)
- {
- #ifdef WIN32
- char buffer[UNLEN+1]={0};
- DWORD len = UNLEN+1;
- GetUserName(buffer, &len);
- snprintf (prefix, size,
- "jack-%s:%s:", buffer, server_name);
- #else
- snprintf (prefix, size,
- "jack-%d:%s:", GetUID(), server_name);
- #endif
- }
-
- /* gain server addressability to shared memory registration segment
- *
- * returns: 0 if successful
- */
- static int
- jack_server_initialize_shm (int new_registry)
- {
- int rc;
-
- if (jack_shm_header)
- return 0; /* already initialized */
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- rc = jack_access_registry (®istry_info);
-
- if (new_registry) {
- jack_remove_shm (registry_id);
- rc = ENOENT;
- }
-
- switch (rc) {
- case ENOENT: /* registry does not exist */
- rc = jack_create_registry (®istry_info);
- break;
- case 0: /* existing registry */
- if (jack_shm_validate_registry () == 0)
- break;
- /* else it was invalid, so fall through */
- case EINVAL: /* bad registry */
- /* Apparently, this registry was created by an older
- * JACK version. Delete it so we can try again. */
- jack_release_shm (®istry_info);
- jack_remove_shm (registry_id);
- if ((rc = jack_create_registry (®istry_info)) != 0) {
- jack_error ("incompatible shm registry (%s)",
- strerror (errno));
- #ifndef USE_POSIX_SHM
- jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
- JACK_SHM_REGISTRY_KEY);
- #endif
- }
- break;
- default: /* failure return code */
- break;
- }
-
- jack_shm_unlock_registry ();
- return rc;
- }
-
- /* gain client addressability to shared memory registration segment
- *
- * NOTE: this function is no longer used for server initialization,
- * instead it calls jack_register_server().
- *
- * returns: 0 if successful
- */
- int
- jack_initialize_shm (const char *server_name)
- {
- int rc;
- char server_prefix[JACK_SERVER_NAME_SIZE+1];
-
- if (jack_shm_header)
- return 0; /* already initialized */
-
- jack_get_server_prefix (server_name, server_prefix, sizeof(server_prefix));
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- if ((rc = jack_access_registry (®istry_info)) == 0) {
- if ((rc = jack_shm_validate_registry ()) != 0) {
- jack_error ("Incompatible shm registry, "
- "are jackd and libjack in sync?");
- }
- }
- jack_shm_unlock_registry ();
-
- return rc;
- }
-
-
- char* jack_shm_addr (jack_shm_info_t* si)
- {
- return (char*)si->ptr.attached_at;
- }
-
- void
- jack_destroy_shm (jack_shm_info_t* si)
- {
- /* must NOT have the registry locked */
- if (si->index == JACK_SHM_NULL_INDEX)
- return; /* segment not allocated */
-
- jack_remove_shm (jack_shm_registry[si->index].id);
- jack_release_shm_info (si->index);
- }
-
- jack_shm_registry_t *
- jack_get_free_shm_info ()
- {
- /* registry must be locked */
- jack_shm_registry_t* si = NULL;
- int i;
-
- for (i = 0; i < MAX_SHM_ID; ++i) {
- if (jack_shm_registry[i].size == 0) {
- break;
- }
- }
-
- if (i < MAX_SHM_ID) {
- si = &jack_shm_registry[i];
- }
-
- return si;
- }
-
- static void
- jack_release_shm_entry (jack_shm_registry_index_t index)
- {
- /* the registry must be locked */
- jack_shm_registry[index].size = 0;
- jack_shm_registry[index].allocator = 0;
- memset (&jack_shm_registry[index].id, 0,
- sizeof (jack_shm_registry[index].id));
- }
-
- int
- jack_release_shm_info (jack_shm_registry_index_t index)
- {
- /* must NOT have the registry locked */
- if (jack_shm_registry[index].allocator == GetPID()) {
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
- jack_release_shm_entry (index);
- jack_shm_unlock_registry ();
- }
-
- return 0;
- }
-
- /* Claim server_name for this process.
- *
- * returns 0 if successful
- * EEXIST if server_name was already active for this user
- * ENOSPC if server registration limit reached
- * ENOMEM if unable to access shared memory registry
- */
- int
- jack_register_server (const char *server_name, int new_registry)
- {
- int i, res = 0;
- char server_prefix[JACK_SERVER_NAME_SIZE+1];
-
- jack_get_server_prefix (server_name, server_prefix, sizeof(server_prefix));
-
- if (jack_server_initialize_shm (new_registry))
- return ENOMEM;
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- /* See if server_name already registered. Since server names
- * are per-user, we register the unique server prefix string.
- */
- for (i = 0; i < MAX_SERVERS; i++) {
-
- if (strncmp (jack_shm_header->server[i].name,
- server_prefix,
- sizeof(server_prefix)) != 0)
- continue; /* no match */
-
- if (jack_shm_header->server[i].pid == GetPID()){
- res = 0; /* it's me */
- goto unlock;
- }
-
- /* see if server still exists */
- #ifdef WIN32
- if (check_process_running(jack_shm_header->server[i].pid)) {
- res = EEXIST; /* other server running */
- goto unlock;
- }
- #else
- if (kill (jack_shm_header->server[i].pid, 0) == 0) {
- res = EEXIST; /* other server running */
- goto unlock;
- }
- #endif
-
- /* it's gone, reclaim this entry */
- memset (&jack_shm_header->server[i], 0,
- sizeof (jack_shm_server_t));
- }
-
- /* find a free entry */
- for (i = 0; i < MAX_SERVERS; i++) {
- if (jack_shm_header->server[i].pid == 0)
- break;
- }
-
- if (i >= MAX_SERVERS){
- res = ENOSPC; /* out of space */
- goto unlock;
- }
-
- /* claim it */
- jack_shm_header->server[i].pid = GetPID();
- strncpy (jack_shm_header->server[i].name,
- server_prefix,
- sizeof(server_prefix));
-
- unlock:
- jack_shm_unlock_registry ();
- return res;
- }
-
- /* release server_name registration */
- int
- jack_unregister_server (const char *server_name /* unused */)
- {
- int i;
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- for (i = 0; i < MAX_SERVERS; i++) {
- if (jack_shm_header->server[i].pid == GetPID()) {
- memset (&jack_shm_header->server[i], 0,
- sizeof (jack_shm_server_t));
- }
- }
-
- jack_shm_unlock_registry ();
- return 0;
- }
-
- /* called for server startup and termination */
- int
- jack_cleanup_shm ()
- {
- int i;
- int destroy;
- jack_shm_info_t copy;
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- for (i = 0; i < MAX_SHM_ID; i++) {
- jack_shm_registry_t* r;
-
- r = &jack_shm_registry[i];
- memcpy (©, r, sizeof (jack_shm_info_t));
- destroy = FALSE;
-
- /* ignore unused entries */
- if (r->allocator == 0)
- continue;
-
- /* is this my shm segment? */
- if (r->allocator == GetPID()) {
-
- /* allocated by this process, so unattach
- and destroy. */
- jack_release_shm (©);
- destroy = TRUE;
-
- } else {
-
- /* see if allocator still exists */
- #ifdef WIN32
- //jack_info("TODO: kill API not available !!");
- #else
- if (kill (r->allocator, 0)) {
- if (errno == ESRCH) {
- /* allocator no longer exists,
- * so destroy */
- destroy = TRUE;
- }
- }
- #endif
- }
-
- if (destroy) {
-
- int index = copy.index;
-
- if ((index >= 0) && (index < MAX_SHM_ID)) {
- jack_remove_shm (jack_shm_registry[index].id);
- jack_release_shm_entry (index);
- }
- r->size = 0;
- r->allocator = 0;
- }
- }
-
- jack_shm_unlock_registry ();
- return TRUE;
- }
-
- /* resize a shared memory segment
- *
- * There is no way to resize a System V shm segment. Resizing is
- * possible with POSIX shm, but not with the non-conformant Mac OS X
- * implementation. Since POSIX shm is mainly used on that platform,
- * it's simpler to treat them both the same.
- *
- * So, we always resize by deleting and reallocating. This is
- * tricky, because the old segment will not disappear until
- * all the clients have released it. We only do what we can
- * from here.
- *
- * This is not done under a single lock. I don't even want to think
- * about all the things that could possibly go wrong if multiple
- * processes tried to resize the same segment concurrently. That
- * probably doesn't happen.
- */
- int
- jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
- {
- jack_shm_id_t id;
-
- /* The underlying type of `id' differs for SYSV and POSIX */
- memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
-
- jack_release_shm (si);
- jack_destroy_shm (si);
-
- if (jack_shmalloc ((char *) id, size, si)) {
- return -1;
- }
-
- return jack_attach_shm (si);
- }
-
- int
- jack_attach_lib_shm (jack_shm_info_t* si)
- {
- int res = jack_attach_shm(si);
- if (res == 0)
- si->size = jack_shm_registry[si->index].size; // Keep size in si struct
- return res;
- }
-
- int
- jack_attach_lib_shm_read (jack_shm_info_t* si)
- {
- int res = jack_attach_shm_read(si);
- if (res == 0)
- si->size = jack_shm_registry[si->index].size; // Keep size in si struct
- return res;
- }
-
- #ifdef USE_POSIX_SHM
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * POSIX interface-dependent functions
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
- /* gain addressability to existing SHM registry segment
- *
- * sets up global registry pointers, if successful
- *
- * returns: 0 if existing registry accessed successfully
- * ENOENT if registry does not exist
- * EINVAL if registry exists, but has the wrong size
- */
- static int
- jack_access_registry (jack_shm_info_t *ri)
- {
- /* registry must be locked */
- int shm_fd;
-
- /* try to open an existing segment */
- if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
- int rc = errno;
- if (errno != ENOENT) {
- jack_error ("Cannot open existing shm registry segment"
- " (%s)", strerror (errno));
- }
- close (shm_fd);
- return rc;
- }
-
- if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
- PROT_READ|PROT_WRITE,
- MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
- jack_error ("Cannot mmap shm registry segment (%s)",
- strerror (errno));
- close (shm_fd);
- return EINVAL;
- }
-
- /* set up global pointers */
- ri->index = JACK_SHM_REGISTRY_INDEX;
- jack_shm_header = ri->ptr.attached_at;
- jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
-
- close (shm_fd);
- return 0;
- }
-
- /* create a new SHM registry segment
- *
- * sets up global registry pointers, if successful
- *
- * returns: 0 if registry created successfully
- * nonzero error code if unable to allocate a new registry
- */
- static int
- jack_create_registry (jack_shm_info_t *ri)
- {
- /* registry must be locked */
- int shm_fd;
-
- if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
- int rc = errno;
- jack_error ("Cannot create shm registry segment (%s)",
- strerror (errno));
- return rc;
- }
-
- /* Previous shm_open result depends of the actual value of umask, force correct file permission here */
- if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
- jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
- }
-
- /* Set the desired segment size. NOTE: the non-conformant Mac
- * OS X POSIX shm only allows ftruncate() on segment creation.
- */
- if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
- int rc = errno;
- jack_error ("Cannot set registry size (%s)", strerror (errno));
- jack_remove_shm (registry_id);
- close (shm_fd);
- return rc;
- }
-
- if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
- PROT_READ|PROT_WRITE,
- MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
- jack_error ("Cannot mmap shm registry segment (%s)",
- strerror (errno));
- jack_remove_shm (registry_id);
- close (shm_fd);
- return EINVAL;
- }
-
- /* set up global pointers */
- ri->index = JACK_SHM_REGISTRY_INDEX;
- jack_shm_header = ri->ptr.attached_at;
- jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
-
- /* initialize registry contents */
- jack_shm_init_registry ();
- close (shm_fd);
- return 0;
- }
-
- static void
- jack_remove_shm (const jack_shm_id_t id)
- {
- /* registry may or may not be locked */
- shm_unlink (id);
- }
-
- void
- jack_release_shm (jack_shm_info_t* si)
- {
- /* registry may or may not be locked */
- if (si->ptr.attached_at != MAP_FAILED) {
- munmap (si->ptr.attached_at, jack_shm_registry[si->index].size);
- }
- }
-
- void
- jack_release_lib_shm (jack_shm_info_t* si)
- {
- /* registry may or may not be locked */
- if (si->ptr.attached_at != MAP_FAILED) {
- munmap (si->ptr.attached_at, si->size);
- }
- }
-
- /* allocate a POSIX shared memory segment */
- int
- jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
- {
- jack_shm_registry_t* registry;
- int shm_fd;
- int rc = -1;
- char name[SHM_NAME_MAX+1];
- const char* promiscuous;
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- if ((registry = jack_get_free_shm_info ()) == NULL) {
- jack_error ("shm registry full");
- goto unlock;
- }
-
- /* On Mac OS X, the maximum length of a shared memory segment
- * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
- * defined by the standard). Unfortunately, Apple sets this
- * value so small (about 31 bytes) that it is useless for
- * actual names. So, we construct a short name from the
- * registry index for uniqueness and ignore the shm_name
- * parameter. Bah!
- */
- snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index);
-
- if (strlen (name) >= sizeof (registry->id)) {
- jack_error ("shm segment name too long %s", name);
- goto unlock;
- }
-
- if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
- jack_error ("Cannot create shm segment %s (%s)",
- name, strerror (errno));
- goto unlock;
- }
-
- if (ftruncate (shm_fd, size) < 0) {
- jack_error ("Cannot set size of engine shm "
- "registry 0 (%s)",
- strerror (errno));
- close (shm_fd);
- goto unlock;
- }
-
- promiscuous = getenv("JACK_PROMISCUOUS_SERVER");
- if ((promiscuous != NULL) && (jack_promiscuous_perms(shm_fd, name, jack_group2gid(promiscuous)) < 0))
- goto unlock;
-
- close (shm_fd);
- registry->size = size;
- strncpy (registry->id, name, sizeof (registry->id));
- registry->allocator = GetPID();
- si->index = registry->index;
- si->ptr.attached_at = MAP_FAILED; /* not attached */
- rc = 0; /* success */
-
- unlock:
- jack_shm_unlock_registry ();
- return rc;
- }
-
- int
- jack_attach_shm (jack_shm_info_t* si)
- {
- int shm_fd;
- jack_shm_registry_t *registry = &jack_shm_registry[si->index];
-
- if ((shm_fd = shm_open (registry->id,
- O_RDWR, 0666)) < 0) {
- jack_error ("Cannot open shm segment %s (%s)", registry->id,
- strerror (errno));
- return -1;
- }
-
- if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
- MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
- jack_error ("Cannot mmap shm segment %s (%s)",
- registry->id,
- strerror (errno));
- close (shm_fd);
- return -1;
- }
-
- close (shm_fd);
- return 0;
- }
-
- int
- jack_attach_shm_read (jack_shm_info_t* si)
- {
- int shm_fd;
- jack_shm_registry_t *registry = &jack_shm_registry[si->index];
-
- if ((shm_fd = shm_open (registry->id,
- O_RDONLY, 0666)) < 0) {
- jack_error ("Cannot open shm segment %s (%s)", registry->id,
- strerror (errno));
- return -1;
- }
-
- if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ,
- MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
- jack_error ("Cannot mmap shm segment %s (%s)",
- registry->id,
- strerror (errno));
- close (shm_fd);
- return -1;
- }
-
- close (shm_fd);
- return 0;
- }
-
- #elif WIN32
-
- static int
- jack_access_registry (jack_shm_info_t *ri)
- {
- /* registry must be locked */
- HANDLE shm_fd;
-
- /* try to open an existing segment */
-
- if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
- int rc = GetLastError();
- if (rc != ERROR_FILE_NOT_FOUND) {
- jack_error ("Cannot open existing shm registry segment (%ld)", rc);
- }
- return rc;
- }
-
- if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
- jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
- jack_remove_shm (registry_id);
- CloseHandle (shm_fd);
- return EINVAL;
- }
-
- /* set up global pointers */
- ri->index = JACK_SHM_REGISTRY_INDEX;
- jack_shm_header = ri->ptr.attached_at;
- jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
-
- //CloseHandle(shm_fd); // TO CHECK
- return 0;
- }
-
- static int
- jack_create_registry (jack_shm_info_t *ri)
- {
- /* registry must be locked */
- HANDLE shm_fd;
-
- if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
- 0, PAGE_READWRITE,
- 0, JACK_SHM_REGISTRY_SIZE,
- registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
- int rc = GetLastError();
- jack_error ("Cannot create shm registry segment (%ld)", rc);
- return rc;
- }
-
- if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
- jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
- jack_remove_shm (registry_id);
- CloseHandle (shm_fd);
- return EINVAL;
- }
-
- /* set up global pointers */
- ri->index = JACK_SHM_REGISTRY_INDEX;
- jack_shm_header = ri->ptr.attached_at;
- jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
-
- /* initialize registry contents */
- jack_shm_init_registry ();
-
- //CloseHandle(shm_fd); // TO CHECK
- return 0;
- }
-
- static void
- jack_remove_shm (const jack_shm_id_t id)
- {
- /* nothing to do */
- }
-
- void
- jack_release_shm (jack_shm_info_t* si)
- {
- /* registry may or may not be locked */
- if (si->ptr.attached_at != NULL) {
- UnmapViewOfFile (si->ptr.attached_at);
- }
- }
-
- void
- jack_release_lib_shm (jack_shm_info_t* si)
- {
- jack_release_shm(si);
- }
-
- int
- jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
- {
- jack_shm_registry_t* registry;
- HANDLE shm_fd;
- int rc = -1;
- char name[SHM_NAME_MAX+1];
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- if ((registry = jack_get_free_shm_info ()) == NULL) {
- jack_error ("shm registry full");
- goto unlock;
- }
-
- snprintf (name, sizeof (name), "jack-%d-%d", GetUID(), registry->index);
-
- if (strlen (name) >= sizeof (registry->id)) {
- jack_error ("shm segment name too long %s", name);
- goto unlock;
- }
-
- if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
- 0, PAGE_READWRITE,
- 0, size,
- name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
- int rc = GetLastError();
- jack_error ("Cannot create shm segment (%ld)",rc);
- goto unlock;
- }
-
- //CloseHandle (shm_fd); // TO CHECK
-
- registry->size = size;
- strncpy (registry->id, name, sizeof (registry->id));
- registry->allocator = _getpid();
- si->index = registry->index;
- si->ptr.attached_at = NULL; /* not attached */
- rc = 0; /* success */
-
- unlock:
- jack_shm_unlock_registry ();
- return rc;
- }
-
- int
- jack_attach_shm (jack_shm_info_t* si)
- {
- HANDLE shm_fd;
- jack_shm_registry_t *registry = &jack_shm_registry[si->index];
-
- if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
- int rc = GetLastError();
- jack_error ("Cannot open shm segment (%ld)",rc);
- return -1;
- }
-
- if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
- jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
- jack_remove_shm (registry_id);
- CloseHandle (shm_fd);
- return -1;
- }
-
- //CloseHandle (shm_fd); // TO CHECK
- return 0;
- }
-
- int
- jack_attach_shm_read (jack_shm_info_t* si)
- {
- HANDLE shm_fd;
- jack_shm_registry_t *registry = &jack_shm_registry[si->index];
-
- if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
- int rc = GetLastError();
- jack_error ("Cannot open shm segment (%ld)",rc);
- return -1;
- }
-
- if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
- jack_error("Cannot mmap shm segment (%ld)", GetLastError());
- jack_remove_shm(registry_id);
- CloseHandle(shm_fd);
- return -1;
- }
-
- //CloseHandle (shm_fd); // TO CHECK
- return 0;
- }
-
- #else
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * System V interface-dependent functions
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
- /* gain addressability to existing SHM registry segment
- *
- * sets up global registry pointers, if successful
- *
- * returns: 0 if existing registry accessed successfully
- * ENOENT if registry does not exist
- * EINVAL if registry exists, but has the wrong size
- * other nonzero error code if unable to access registry
- */
- static int
- jack_access_registry (jack_shm_info_t *ri)
- {
- /* registry must be locked */
-
- /* try without IPC_CREAT to get existing segment */
- if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
- JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
-
- switch (errno) {
-
- case ENOENT: /* segment does not exist */
- return ENOENT;
-
- case EINVAL: /* segment exists, but too small */
- /* attempt minimum size access */
- registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
- return EINVAL;
-
- default: /* or other error */
- jack_error ("unable to access shm registry (%s)",
- strerror (errno));
- return errno;
- }
- }
-
- if ((ri->ptr.attached_at = shmat (registry_id, 0, 0)) < 0) {
- jack_error ("Cannot attach shm registry segment (%s)",
- strerror (errno));
- return EINVAL;
- }
-
- /* set up global pointers */
- ri->index = JACK_SHM_REGISTRY_INDEX;
- jack_shm_header = ri->ptr.attached_at;
- jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
- return 0;
- }
-
- /* create a new SHM registry segment
- *
- * sets up global registry pointers, if successful
- *
- * returns: 0 if registry created successfully
- * nonzero error code if unable to allocate a new registry
- */
- static int
- jack_create_registry (jack_shm_info_t *ri)
- {
- /* registry must be locked */
- if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
- JACK_SHM_REGISTRY_SIZE,
- 0666|IPC_CREAT)) < 0) {
- jack_error ("Cannot create shm registry segment (%s)",
- strerror (errno));
- return errno;
- }
-
- if ((ri->ptr.attached_at = shmat (registry_id, 0, 0)) < 0) {
- jack_error ("Cannot attach shm registry segment (%s)",
- strerror (errno));
- return EINVAL;
- }
-
- /* set up global pointers */
- ri->index = JACK_SHM_REGISTRY_INDEX;
- jack_shm_header = ri->ptr.attached_at;
- jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
-
- /* initialize registry contents */
- jack_shm_init_registry ();
- return 0;
- }
-
- static void
- jack_remove_shm (jack_shm_id_t id)
- {
- /* registry may or may not be locked */
- shmctl (id, IPC_RMID, NULL);
- }
-
- void
- jack_release_shm (jack_shm_info_t* si)
- {
- /* registry may or may not be locked */
- if (si->ptr.attached_at != MAP_FAILED) {
- shmdt (si->ptr.attached_at);
- }
- }
-
- void
- jack_release_lib_shm (jack_shm_info_t* si)
- {
- jack_release_shm(si);
- }
-
- int
- jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
- jack_shm_info_t* si)
- {
- int shmflags;
- int shmid;
- int rc = -1;
- jack_shm_registry_t* registry;
-
- if (jack_shm_lock_registry () < 0) {
- jack_error ("jack_shm_lock_registry fails...");
- return -1;
- }
-
- if ((registry = jack_get_free_shm_info ())) {
-
- shmflags = 0666 | IPC_CREAT | IPC_EXCL;
-
- if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
-
- registry->size = size;
- registry->id = shmid;
- registry->allocator = getpid();
- si->index = registry->index;
- si->ptr.attached_at = MAP_FAILED; /* not attached */
- rc = 0;
-
- } else {
- jack_error ("Cannot create shm segment %s (%s)",
- name_not_used, strerror (errno));
- }
- }
-
- jack_shm_unlock_registry ();
- return rc;
- }
-
- int
- jack_attach_shm (jack_shm_info_t* si)
- {
- if ((si->ptr.attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
- jack_error ("Cannot attach shm segment (%s)",
- strerror (errno));
- jack_release_shm_info (si->index);
- return -1;
- }
- return 0;
- }
-
- int
- jack_attach_shm_read (jack_shm_info_t* si)
- {
- if ((si->ptr.attached_at = shmat (jack_shm_registry[si->index].id, 0, SHM_RDONLY)) < 0) {
- jack_error ("Cannot attach shm segment (%s)",
- strerror (errno));
- jack_release_shm_info (si->index);
- return -1;
- }
- return 0;
- }
-
- #endif /* !USE_POSIX_SHM */
|