Browse Source

[0.99.31] SHM registry locking

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@839 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
joq 21 years ago
parent
commit
4ad5ffd031
3 changed files with 164 additions and 81 deletions
  1. +1
    -3
      configure.ac
  2. +0
    -4
      jack/version.h.in
  3. +163
    -74
      libjack/shm.c

+ 1
- 3
configure.ac View File

@@ -15,7 +15,7 @@ dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=99
JACK_MICRO_VERSION=30
JACK_MICRO_VERSION=31

dnl ---
dnl HOWTO: updating the jack protocol version
@@ -151,8 +151,6 @@ then
USE_POSIX_SHM="true"
else
AC_MSG_RESULT([System V shmget().])
JACK_SHM_REGISTRY_KEY=0x00282929
AC_SUBST(JACK_SHM_REGISTRY_KEY)
USE_POSIX_SHM="false"
fi
AM_CONDITIONAL(USE_POSIX_SHM, $USE_POSIX_SHM)


+ 0
- 4
jack/version.h.in View File

@@ -18,7 +18,3 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define jack_protocol_version @JACK_PROTOCOL_VERSION@

#ifndef USE_POSIX_SHM
#define JACK_SHM_REGISTRY_KEY @JACK_SHM_REGISTRY_KEY@
#endif

+ 163
- 74
libjack/shm.c View File

@@ -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 (&registry_info);
jack_remove_shm (&registry_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


Loading…
Cancel
Save