summaryrefslogtreecommitdiff
path: root/libjack/shm.c
diff options
context:
space:
mode:
authorjoq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224>2003-09-30 01:12:16 +0000
committerjoq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224>2003-09-30 01:12:16 +0000
commit1c3df32369bd1f437b4c3eddb107df0d508fd79d (patch)
tree014785edf8ceaa364aee63007c96b57d5ba9cc6d /libjack/shm.c
parent50c12df7e2632fe0abdbe48821036ca9be67b7a3 (diff)
downloadjack1-1c3df32369bd1f437b4c3eddb107df0d508fd79d.tar.gz
[0.83.3] resize with SysV shm
git-svn-id: svn+ssh://jackaudio.org/trunk/jack@514 0c269be4-1314-0410-8aa9-9f06e86f4224
Diffstat (limited to 'libjack/shm.c')
-rw-r--r--libjack/shm.c107
1 files changed, 63 insertions, 44 deletions
diff --git a/libjack/shm.c b/libjack/shm.c
index 4a8541a..499caba 100644
--- a/libjack/shm.c
+++ b/libjack/shm.c
@@ -37,11 +37,8 @@
typedef struct {
shm_name_t name;
-#ifdef USE_POSIX_SHM
char *address;
-#else
- int shmid;
-#endif
+ int shmid; /* only needed for SysV shm */
} jack_shm_registry_entry_t;
static jack_shm_registry_entry_t *jack_shm_registry;
@@ -51,16 +48,29 @@ void
jack_register_shm (char *shm_name, char *addr, int id)
{
if (jack_shm_id_cnt < MAX_SHM_ID) {
- snprintf (jack_shm_registry[jack_shm_id_cnt++].name,
- sizeof (shm_name_t), "%s", shm_name);
-#ifdef USE_POSIX_SHM
- jack_shm_registry[jack_shm_id_cnt].address = addr;
-#else
- jack_shm_registry[jack_shm_id_cnt].shmid = id;
-#endif
+ int entry = jack_shm_id_cnt++;
+ strncpy (jack_shm_registry[entry].name, shm_name,
+ sizeof (shm_name_t));
+ jack_shm_registry[entry].address = addr;
+ jack_shm_registry[entry].shmid = id;
}
}
+static inline int
+jack_lookup_shm (const char *shm_name)
+{
+ /***** NOT THREAD SAFE *****/
+
+ int i;
+
+ for (i = 0; i < jack_shm_id_cnt; ++i) {
+ if (strcmp (jack_shm_registry[i].name, shm_name) == 0) {
+ return i;
+ }
+ }
+ return -1; /* not found */
+}
+
int
jack_initialize_shm ()
{
@@ -209,26 +219,17 @@ char *
jack_resize_shm (const char *shm_name, size_t size, int perm, int mode,
int prot)
{
- int i;
+ int entry;
int shm_fd;
char *addr;
struct stat statbuf;
- for (i = 0; i < jack_shm_id_cnt; ++i) {
- if (strcmp (jack_shm_registry[i].name, shm_name) == 0) {
- break;
- }
- }
-
- if (i == jack_shm_id_cnt) {
+ if ((entry = jack_lookup_shm (shm_name)) < 0) {
jack_error ("attempt to resize unknown shm segment \"%s\"",
shm_name);
return MAP_FAILED;
}
- // JOQ: this does not work reliably for me. After a few
- // resize operations, the open starts failing. Maybe my
- // system is running out of some tmpfs resource?
if ((shm_fd = shm_open (shm_name, perm, mode)) < 0) {
jack_error ("cannot create shm segment %s (%s)", shm_name,
strerror (errno));
@@ -237,7 +238,7 @@ jack_resize_shm (const char *shm_name, size_t size, int perm, int mode,
fstat (shm_fd, &statbuf);
- munmap (jack_shm_registry[i].address, statbuf.st_size);
+ munmap (jack_shm_registry[entry].address, statbuf.st_size);
if (perm & O_CREAT) {
if (ftruncate (shm_fd, size) < 0) {
@@ -262,29 +263,30 @@ jack_resize_shm (const char *shm_name, size_t size, int perm, int mode,
#else /* USE_POSIX_SHM */
-int
-jack_get_shmid (const char *name)
+char
+jack_hash_shm (jack_shmsize_t size)
{
- int i;
+ char log2size = 0; /* log2 of size */
- /* **** NOT THREAD SAFE *****/
+ if (size == 0)
+ return log2size; /* don't loop forever */
- for (i = 0; i < jack_shm_id_cnt; ++i) {
- if (strcmp (jack_shm_registry[i].name, name) == 0) {
- return jack_shm_registry[i].shmid;
- }
+ /* remove low-order zeroes, counting them */
+ while ((size & 1) == 0) {
+ ++log2size;
+ size >>= 1;
}
- return -1;
+
+ return (char) ((size + log2size) & 0x7f);
}
void
jack_destroy_shm (const char *shm_name)
{
- int shmid = jack_get_shmid (shm_name);
+ int i = jack_lookup_shm (shm_name);
- if (shmid >= 0) {
- shmctl (IPC_RMID, shmid, NULL);
- }
+ if (i >= 0)
+ shmctl (IPC_RMID, jack_shm_registry[i].shmid, NULL);
}
void
@@ -305,10 +307,7 @@ jack_get_shm (const char *shm_name, size_t size, int perm, int mode,
int status;
/* note: no trailing '/' on basic path because we expect shm_name to
- begin with one (as per POSIX shm API).
- */
-
-
+ begin with one (as per POSIX shm API). */
snprintf (path, sizeof(path), "%s/jack", jack_server_dir);
if (mkdir (path, 0775)) {
if (errno != EEXIST) {
@@ -340,7 +339,11 @@ jack_get_shm (const char *shm_name, size_t size, int perm, int mode,
close (fd);
}
- if ((key = ftok (path, 'j')) < 0) {
+ /* Hash the shm size to distinguish differently-sized segments
+ * with the same path name. This allows jack_resize_shm() to
+ * allocate a new segment when the size changes with the same
+ * name but a different shmid. */
+ if ((key = ftok (path, jack_hash_shm(size))) < 0) {
jack_error ("cannot generate IPC key for shm segment %s (%s)",
path, strerror (errno));
unlink (path);
@@ -397,9 +400,25 @@ char *
jack_resize_shm (const char *shm_name, size_t size, int perm, int mode,
int prot)
{
- jack_error ("jack_resize_shm() is not implemented for the System V "
- "shared memory API");
- return 0;
+ int entry = jack_lookup_shm (shm_name);
+
+ if (entry < 0) {
+ jack_error ("attempt to resize unknown shm segment \"%s\"",
+ shm_name);
+ return MAP_FAILED;
+ }
+
+ /* There is no way to resize a System V shm segment. So, we
+ * delete it and allocate a new one. This is tricky, because
+ * the old segment will not disappear until all the clients
+ * have released it. */
+ jack_destroy_shm (shm_name);
+ jack_release_shm (jack_shm_registry[entry].address, size);
+ jack_shm_registry[entry].address =
+ jack_get_shm (shm_name, size, perm, mode, prot,
+ &jack_shm_registry[entry].shmid);
+
+ return jack_shm_registry[entry].address;
}
#endif /* USE_POSIX_SHM */