diff options
author | joq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224> | 2004-12-11 23:31:27 +0000 |
---|---|---|
committer | joq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224> | 2004-12-11 23:31:27 +0000 |
commit | 4ad5ffd031cf9177af7ca559e760314f1c7e327e (patch) | |
tree | 730af5dddfb77a90de90dc4f2c624cb0566aab1b /libjack/shm.c | |
parent | 4e1c06db7aa2a9717adffe84152d7bddc2d1fd71 (diff) | |
download | jack1-4ad5ffd031cf9177af7ca559e760314f1c7e327e.tar.gz |
[0.99.31] SHM registry locking
git-svn-id: svn+ssh://jackaudio.org/trunk/jack@839 0c269be4-1314-0410-8aa9-9f06e86f4224
Diffstat (limited to 'libjack/shm.c')
-rw-r--r-- | libjack/shm.c | 237 |
1 files changed, 163 insertions, 74 deletions
diff --git a/libjack/shm.c b/libjack/shm.c index ad9a419..aa1d98d 100644 --- a/libjack/shm.c +++ b/libjack/shm.c @@ -1,23 +1,35 @@ +/* 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 + * + * The implementation used is determined by whether USE_POSIX_SHM was + * set in the ./configure step. + */ + /* - Copyright (C) 2003 Paul Davis - Copyright (C) 2004 Jack O'Quin - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id$ -*/ + * Copyright (C) 2003 Paul Davis + * Copyright (C) 2004 Jack O'Quin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ #include <config.h> #include <unistd.h> @@ -30,7 +42,10 @@ #include <dirent.h> #include <sys/mman.h> #include <sys/types.h> +#include <sys/stat.h> +#include <sysdeps/ipc.h> #include <sys/shm.h> +#include <sys/sem.h> #include <sysdeps/ipc.h> #include <jack/shm.h> @@ -49,14 +64,6 @@ static char *shmtype_name = "System V"; static int jack_access_registry (jack_shm_info_t *ri); static void jack_remove_shm (jack_shm_id_t *id); -/* This module supports both System V and POSIX shared memory - * interfaces. The code is divided into three sections: - * - * - common (interface-independent) code - * - POSIX implementation - * - System V implementation - */ - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * common interface-independent section * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -72,18 +79,96 @@ jack_shm_info_t registry_info = { /* SHM info for the registry */ 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 segements 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; + +/* all semaphore errors are fatal -- issue message, but do not return */ +static void +semaphore_error (char *msg) +{ + jack_error ("Fatal JACK semaphore error: %s (%s)", + msg, strerror (errno)); + abort (); +} + +static void +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"); + } + + } else if (errno == EEXIST) { + if ((semid = semget(semkey, 0, 0)) == -1) { + semaphore_error ("semget"); + } + + } else { + semaphore_error ("semget creation"); + } + } +} + +static inline void +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"); + } +} + static void jack_shm_lock_registry (void) { - /* XXX magic with semaphores here */ - //JOQ: this is really needed now with multiple servers + if (semid == -1) + semaphore_init (); + + semaphore_add (-1); } static void jack_shm_unlock_registry (void) { - /* XXX magic with semaphores here */ - //JOQ: this is really needed now with multiple servers + semaphore_add (1); } static void @@ -124,7 +209,7 @@ jack_shm_validate_registry () jack_error ("incompatible shm registry (%s)", strerror (errno)); /* Apparently, this registry was created by an older JACK - * version. Delete it and try again. */ + * version. Delete it so we can try again. */ jack_release_shm (®istry_info); jack_remove_shm (®istry_id); @@ -194,11 +279,10 @@ jack_destroy_shm (jack_shm_info_t* si) jack_shm_registry_t * jack_get_free_shm_info () { + /* registry must be locked */ jack_shm_registry_t* si = NULL; int i; - jack_shm_lock_registry (); - for (i = 0; i < MAX_SHM_ID; ++i) { if (jack_shm_registry[i].size == 0) { break; @@ -208,8 +292,6 @@ jack_get_free_shm_info () if (i < MAX_SHM_ID) { si = &jack_shm_registry[i]; } - - jack_shm_unlock_registry (); return si; } @@ -466,37 +548,39 @@ jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) { jack_shm_registry_t* registry; int shm_fd; - int perm = O_RDWR|O_CREAT; + int rc = -1; - if ((registry = jack_get_free_shm_info ()) == NULL) { - return -1; - } + jack_shm_lock_registry (); - if ((shm_fd = shm_open (shm_name, O_RDWR|O_CREAT, 0666)) < 0) { - jack_error ("cannot create shm segment %s (%s)", shm_name, - strerror (errno)); - return -1; - } - - if (perm & O_CREAT) { - if (ftruncate (shm_fd, size) < 0) { + if ((registry = jack_get_free_shm_info ())) { + + if ((shm_fd = shm_open (shm_name, O_RDWR|O_CREAT, 0666)) >= 0) { + + if (ftruncate (shm_fd, size) >= 0) { + + close (shm_fd); + registry->size = size; + snprintf (registry->id, sizeof (registry->id), + "%s", shm_name); + registry->allocator = getpid(); + si->index = registry->index; + si->attached_at = MAP_FAILED; /* not attached */ + rc = 0; /* success */ + + } else { jack_error ("cannot set size of engine shm " "registry 0 (%s)", strerror (errno)); - return -1; + } + + } else { + jack_error ("cannot create shm segment %s (%s)", + shm_name, strerror (errno)); } } - close (shm_fd); - - registry->size = size; - snprintf (registry->id, sizeof (registry->id), "%s", shm_name); - registry->allocator = getpid(); - - si->index = registry->index; - si->attached_at = MAP_FAILED; /* segment not attached */ - - return 0; + jack_shm_unlock_registry (); + return rc; } int @@ -652,28 +736,33 @@ jack_shmalloc (const char* name_not_used, jack_shmsize_t size, { int shmflags; int shmid; + int rc = -1; jack_shm_registry_t* registry; - if ((registry = jack_get_free_shm_info ()) == NULL) { - return -1; - } + jack_shm_lock_registry (); - shmflags = 0666 | IPC_CREAT | IPC_EXCL; + if ((registry = jack_get_free_shm_info ())) { - if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) < 0) { - jack_error ("cannot create shm segment %s (%s)", - name_not_used, strerror (errno)); - return -1; - } + shmflags = 0666 | IPC_CREAT | IPC_EXCL; - registry->size = size; - registry->id = shmid; - registry->allocator = getpid(); + if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) { - si->index = registry->index; - si->attached_at = MAP_FAILED; /* segment not attached */ + registry->size = size; + registry->id = shmid; + registry->allocator = getpid(); + si->index = registry->index; + si->attached_at = MAP_FAILED; /* not attached */ + rc = 0; - return 0; + } else { + jack_error ("cannot create shm segment %s (%s)", + name_not_used, strerror (errno)); + } + } + + jack_shm_unlock_registry (); + + return rc; } int |