diff options
author | joq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224> | 2003-09-30 01:12:16 +0000 |
---|---|---|
committer | joq <joq@0c269be4-1314-0410-8aa9-9f06e86f4224> | 2003-09-30 01:12:16 +0000 |
commit | 1c3df32369bd1f437b4c3eddb107df0d508fd79d (patch) | |
tree | 014785edf8ceaa364aee63007c96b57d5ba9cc6d /libjack/shm.c | |
parent | 50c12df7e2632fe0abdbe48821036ca9be67b7a3 (diff) | |
download | jack1-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.c | 107 |
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 */ |