jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
7.1KB

  1. /*
  2. Copyright (C) 2003 Paul Davis
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. $Id$
  15. */
  16. #include <unistd.h>
  17. #include <fcntl.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <limits.h>
  21. #include <errno.h>
  22. #include <sys/stat.h>
  23. #include <sys/mman.h>
  24. #include <sys/types.h>
  25. #include <sys/ipc.h>
  26. #include <sys/shm.h>
  27. #include <jack/shm.h>
  28. #include <jack/internal.h>
  29. typedef struct {
  30. shm_name_t name;
  31. #ifdef USE_POSIX_SHM
  32. char *address;
  33. #else
  34. int shmid;
  35. #endif
  36. } jack_shm_registry_entry_t;
  37. static jack_shm_registry_entry_t *jack_shm_registry;
  38. static int jack_shm_id_cnt;
  39. void
  40. jack_register_shm (char *shm_name, char *addr, int id)
  41. {
  42. if (jack_shm_id_cnt < MAX_SHM_ID) {
  43. snprintf (jack_shm_registry[jack_shm_id_cnt++].name, sizeof (shm_name_t), "%s", shm_name);
  44. #ifdef USE_POSIX_SHM
  45. jack_shm_registry[jack_shm_id_cnt].address = addr;
  46. #else
  47. jack_shm_registry[jack_shm_id_cnt].shmid = id;
  48. #endif
  49. }
  50. }
  51. int
  52. jack_initialize_shm ()
  53. {
  54. void *addr;
  55. int id;
  56. #ifdef USE_POSIX_SHM
  57. fprintf (stderr, "JACK compiled with POSIX SHM support\n");
  58. #else
  59. fprintf (stderr, "JACK compiled with System V SHM support\n");
  60. #endif
  61. if (jack_shm_registry != NULL) {
  62. return 0;
  63. }
  64. /* grab a chunk of memory to store shm ids in. this is
  65. to allow our parent to clean up all such ids when
  66. if we exit. otherwise, they can get lost in crash
  67. or debugger driven exits.
  68. */
  69. if ((addr = jack_get_shm ("/jack-shm-registry", sizeof (jack_shm_registry_entry_t) * MAX_SHM_ID,
  70. O_RDWR|O_CREAT|O_TRUNC, 0600, PROT_READ|PROT_WRITE, &id)) == MAP_FAILED) {
  71. return -1;
  72. }
  73. jack_shm_registry = (jack_shm_registry_entry_t *) addr;
  74. jack_shm_id_cnt = 0;
  75. jack_register_shm ("/jack-shm-registry", addr, id);
  76. return 0;
  77. }
  78. void
  79. jack_cleanup_shm ()
  80. {
  81. int i;
  82. for (i = 0; i < jack_shm_id_cnt; i++) {
  83. jack_destroy_shm (jack_shm_registry[i].name);
  84. }
  85. }
  86. #if USE_POSIX_SHM
  87. void
  88. jack_destroy_shm (const char *shm_name)
  89. {
  90. shm_unlink (shm_name);
  91. }
  92. void
  93. jack_release_shm (char *addr, size_t size)
  94. {
  95. munmap (addr, size);
  96. }
  97. char *
  98. jack_get_shm (const char *shm_name, size_t size, int perm, int mode, int prot, int *not_really_used)
  99. {
  100. int shm_fd;
  101. char *addr;
  102. if ((shm_fd = shm_open (shm_name, perm, mode)) < 0) {
  103. jack_error ("cannot create shm segment %s (%s)", shm_name, strerror (errno));
  104. return MAP_FAILED;
  105. }
  106. if (perm & O_CREAT) {
  107. if (ftruncate (shm_fd, size) < 0) {
  108. jack_error ("cannot set size of engine shm registry (%s)", strerror (errno));
  109. return MAP_FAILED;
  110. }
  111. }
  112. if ((addr = mmap (0, size, prot, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  113. jack_error ("cannot mmap shm segment %s (%s)", shm_name, strerror (errno));
  114. shm_unlink (shm_name);
  115. close (shm_fd);
  116. return MAP_FAILED;
  117. }
  118. close (shm_fd);
  119. *not_really_used = 0;
  120. return addr;
  121. }
  122. char *
  123. jack_resize_shm (const char *shm_name, size_t size, int perm, int mode, int prot)
  124. {
  125. int i;
  126. int shm_fd;
  127. char *addr;
  128. struct stat statbuf;
  129. for (i = 0; i < jack_shm_id_cnt; ++i) {
  130. if (strcmp (jack_shm_registry[i].name, shm_name) == 0) {
  131. break;
  132. }
  133. }
  134. if (i == jack_shm_id_cnt) {
  135. jack_error ("attempt to resize unknown shm segment \"%s\"", shm_name);
  136. return MAP_FAILED;
  137. }
  138. if ((shm_fd = shm_open (shm_name, perm, mode)) < 0) {
  139. jack_error ("cannot create shm segment %s (%s)", shm_name, strerror (errno));
  140. return MAP_FAILED;
  141. }
  142. fstat (shm_fd, &statbuf);
  143. munmap (jack_shm_registry[i].address, statbuf.st_size);
  144. if (perm & O_CREAT) {
  145. if (ftruncate (shm_fd, size) < 0) {
  146. jack_error ("cannot set size of engine shm registry (%s)", strerror (errno));
  147. return MAP_FAILED;
  148. }
  149. }
  150. if ((addr = mmap (0, size, prot, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  151. jack_error ("cannot mmap shm segment %s (%s)", shm_name, strerror (errno));
  152. shm_unlink (shm_name);
  153. close (shm_fd);
  154. return MAP_FAILED;
  155. }
  156. close (shm_fd);
  157. return addr;
  158. }
  159. #else /* USE_POSIX_SHM */
  160. int
  161. jack_get_shmid (const char *name)
  162. {
  163. int i;
  164. /* **** NOT THREAD SAFE *****/
  165. for (i = 0; i < jack_shm_id_cnt; ++i) {
  166. if (strcmp (jack_shm_registry[i].name, name) == 0) {
  167. return jack_shm_registry[i].shmid;
  168. }
  169. }
  170. return -1;
  171. }
  172. void
  173. jack_destroy_shm (const char *shm_name)
  174. {
  175. int shmid = jack_get_shmid (shm_name);
  176. if (shmid >= 0) {
  177. shmctl (IPC_RMID, shmid, NULL);
  178. }
  179. }
  180. void
  181. jack_release_shm (char *addr, size_t size)
  182. {
  183. shmdt (addr);
  184. }
  185. char *
  186. jack_get_shm (const char *shm_name, size_t size, int perm, int mode, int prot, int* shmid)
  187. {
  188. char *addr;
  189. key_t key;
  190. int shmflags;
  191. char path[PATH_MAX+1];
  192. struct stat statbuf;
  193. int status;
  194. /* note: no trailing '/' on basic path because we expect shm_name to
  195. begin with one (as per POSIX shm API).
  196. */
  197. if (mkdir ("/tmp/jack", 0775)) {
  198. if (errno != EEXIST) {
  199. jack_error ("cannot create JACK directory (%s)", strerror (errno));
  200. return MAP_FAILED;
  201. }
  202. }
  203. if (mkdir ("/tmp/jack/shm", 0775)) {
  204. if (errno != EEXIST) {
  205. jack_error ("cannot create JACK shm directory (%s)", strerror (errno));
  206. return MAP_FAILED;
  207. }
  208. }
  209. snprintf (path, sizeof(path), "/tmp/jack/shm%s", shm_name);
  210. if ((status = stat (path, &statbuf)) < 0) {
  211. int fd;
  212. if ((fd = open (path, O_RDWR|O_CREAT, 0775)) < 0) {
  213. jack_error ("cannot create shm file node for %s (%s)", path, strerror (errno));
  214. return MAP_FAILED;
  215. }
  216. close (fd);
  217. }
  218. if ((key = ftok (path, 'j')) < 0) {
  219. jack_error ("cannot generate IPC key for shm segment %s (%s)", path, strerror (errno));
  220. unlink (path);
  221. return MAP_FAILED;
  222. }
  223. /* XXX need to figure out how to do this without causing the inode reallocation
  224. the next time this function is called resulting in ftok() returning non-unique
  225. keys.
  226. */
  227. /* unlink (path); */
  228. shmflags = mode;
  229. if (perm & O_CREAT) {
  230. shmflags |= IPC_CREAT;
  231. }
  232. if (perm & O_TRUNC) {
  233. shmflags |= IPC_EXCL;
  234. }
  235. if ((*shmid = shmget (key, size, shmflags)) < 0) {
  236. if (errno == EEXIST && (shmflags & IPC_EXCL)) {
  237. shmflags &= ~IPC_EXCL;
  238. if ((*shmid = shmget (key, size, shmflags)) < 0) {
  239. jack_error ("cannot get existing shm segment for %s (%s)",
  240. shm_name, strerror (errno));
  241. return MAP_FAILED;
  242. }
  243. } else {
  244. jack_error ("cannot create shm segment %s (%s)", shm_name, strerror (errno));
  245. return MAP_FAILED;
  246. }
  247. }
  248. if ((addr = shmat (*shmid, 0, 0)) < 0) {
  249. jack_error ("cannot attach shm segment %s (%s)", shm_name, strerror (errno));
  250. return MAP_FAILED;
  251. }
  252. return addr;
  253. }
  254. char *
  255. jack_resize_shm (const char *shm_name, size_t size, int perm, int mode, int prot)
  256. {
  257. jack_error ("jack_resize_shm() is not implemented for the System V shared memory API");
  258. return 0;
  259. }
  260. #endif /* USE_POSIX_SHM */