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.

337 lines
7.5KB

  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 <config.h>
  28. #include <jack/shm.h>
  29. #include <jack/internal.h>
  30. typedef struct {
  31. shm_name_t name;
  32. #ifdef USE_POSIX_SHM
  33. char *address;
  34. #else
  35. int shmid;
  36. #endif
  37. } jack_shm_registry_entry_t;
  38. static jack_shm_registry_entry_t *jack_shm_registry;
  39. static int jack_shm_id_cnt;
  40. void
  41. jack_register_shm (char *shm_name, char *addr, int id)
  42. {
  43. if (jack_shm_id_cnt < MAX_SHM_ID) {
  44. snprintf (jack_shm_registry[jack_shm_id_cnt++].name, sizeof (shm_name_t), "%s", shm_name);
  45. #ifdef USE_POSIX_SHM
  46. jack_shm_registry[jack_shm_id_cnt].address = addr;
  47. #else
  48. jack_shm_registry[jack_shm_id_cnt].shmid = id;
  49. #endif
  50. }
  51. }
  52. int
  53. jack_initialize_shm ()
  54. {
  55. void *addr;
  56. int id;
  57. int perm;
  58. #ifdef USE_POSIX_SHM
  59. fprintf (stderr, "JACK compiled with POSIX SHM support\n");
  60. #else
  61. fprintf (stderr, "JACK compiled with System V SHM support\n");
  62. #endif
  63. if (jack_shm_registry != NULL) {
  64. return 0;
  65. }
  66. /* grab a chunk of memory to store shm ids in. this is
  67. to allow our parent to clean up all such ids when
  68. if we exit. otherwise, they can get lost in crash
  69. or debugger driven exits.
  70. */
  71. #if defined(linux)
  72. perm = O_RDWR|O_CREAT|O_TRUNC;
  73. #elif defined(__APPLE__) && defined(__POWERPC__)
  74. /* using O_TRUNC option does not work on Darwin */
  75. perm = O_RDWR|O_CREAT;
  76. #endif
  77. if ((addr = jack_get_shm ("/jack-shm-registry", sizeof (jack_shm_registry_entry_t) * MAX_SHM_ID,
  78. perm, 0600, PROT_READ|PROT_WRITE, &id)) == MAP_FAILED) {
  79. return -1;
  80. }
  81. jack_shm_registry = (jack_shm_registry_entry_t *) addr;
  82. jack_shm_id_cnt = 0;
  83. jack_register_shm ("/jack-shm-registry", addr, id);
  84. return 0;
  85. }
  86. void
  87. jack_cleanup_shm ()
  88. {
  89. int i;
  90. for (i = 0; i < jack_shm_id_cnt; i++) {
  91. jack_destroy_shm (jack_shm_registry[i].name);
  92. }
  93. }
  94. #if USE_POSIX_SHM
  95. void
  96. jack_destroy_shm (const char *shm_name)
  97. {
  98. shm_unlink (shm_name);
  99. }
  100. void
  101. jack_release_shm (char *addr, size_t size)
  102. {
  103. munmap (addr, size);
  104. }
  105. char *
  106. jack_get_shm (const char *shm_name, size_t size, int perm, int mode, int prot, int *not_really_used)
  107. {
  108. int shm_fd;
  109. char *addr;
  110. if ((shm_fd = shm_open (shm_name, perm, mode)) < 0) {
  111. jack_error ("cannot create shm segment %s (%s)", shm_name, strerror (errno));
  112. return MAP_FAILED;
  113. }
  114. if (perm & O_CREAT) {
  115. if (ftruncate (shm_fd, size) < 0) {
  116. jack_error ("cannot set size of engine shm registry (%s)", strerror (errno));
  117. return MAP_FAILED;
  118. }
  119. }
  120. if ((addr = mmap (0, size, prot, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  121. jack_error ("cannot mmap shm segment %s (%s)", shm_name, strerror (errno));
  122. shm_unlink (shm_name);
  123. close (shm_fd);
  124. return MAP_FAILED;
  125. }
  126. close (shm_fd);
  127. *not_really_used = 0;
  128. return addr;
  129. }
  130. char *
  131. jack_resize_shm (const char *shm_name, size_t size, int perm, int mode, int prot)
  132. {
  133. int i;
  134. int shm_fd;
  135. char *addr;
  136. struct stat statbuf;
  137. for (i = 0; i < jack_shm_id_cnt; ++i) {
  138. if (strcmp (jack_shm_registry[i].name, shm_name) == 0) {
  139. break;
  140. }
  141. }
  142. if (i == jack_shm_id_cnt) {
  143. jack_error ("attempt to resize unknown shm segment \"%s\"", shm_name);
  144. return MAP_FAILED;
  145. }
  146. if ((shm_fd = shm_open (shm_name, perm, mode)) < 0) {
  147. jack_error ("cannot create shm segment %s (%s)", shm_name, strerror (errno));
  148. return MAP_FAILED;
  149. }
  150. fstat (shm_fd, &statbuf);
  151. munmap (jack_shm_registry[i].address, statbuf.st_size);
  152. if (perm & O_CREAT) {
  153. if (ftruncate (shm_fd, size) < 0) {
  154. jack_error ("cannot set size of engine shm registry (%s)", strerror (errno));
  155. return MAP_FAILED;
  156. }
  157. }
  158. if ((addr = mmap (0, size, prot, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  159. jack_error ("cannot mmap shm segment %s (%s)", shm_name, strerror (errno));
  160. shm_unlink (shm_name);
  161. close (shm_fd);
  162. return MAP_FAILED;
  163. }
  164. close (shm_fd);
  165. return addr;
  166. }
  167. #else /* USE_POSIX_SHM */
  168. int
  169. jack_get_shmid (const char *name)
  170. {
  171. int i;
  172. /* **** NOT THREAD SAFE *****/
  173. for (i = 0; i < jack_shm_id_cnt; ++i) {
  174. if (strcmp (jack_shm_registry[i].name, name) == 0) {
  175. return jack_shm_registry[i].shmid;
  176. }
  177. }
  178. return -1;
  179. }
  180. void
  181. jack_destroy_shm (const char *shm_name)
  182. {
  183. int shmid = jack_get_shmid (shm_name);
  184. if (shmid >= 0) {
  185. shmctl (IPC_RMID, shmid, NULL);
  186. }
  187. }
  188. void
  189. jack_release_shm (char *addr, size_t size)
  190. {
  191. shmdt (addr);
  192. }
  193. char *
  194. jack_get_shm (const char *shm_name, size_t size, int perm, int mode, int prot, int* shmid)
  195. {
  196. char *addr;
  197. key_t key;
  198. int shmflags;
  199. char path[PATH_MAX+1];
  200. struct stat statbuf;
  201. int status;
  202. /* note: no trailing '/' on basic path because we expect shm_name to
  203. begin with one (as per POSIX shm API).
  204. */
  205. snprintf (path, sizeof(path), "%s/jack", jack_server_dir);
  206. if (mkdir (path, 0775)) {
  207. if (errno != EEXIST) {
  208. jack_error ("cannot create JACK directory (%s)", strerror (errno));
  209. return MAP_FAILED;
  210. }
  211. }
  212. snprintf (path, sizeof(path), "%s/jack/shm", jack_server_dir);
  213. if (mkdir (path, 0775)) {
  214. if (errno != EEXIST) {
  215. jack_error ("cannot create JACK shm directory (%s)", strerror (errno));
  216. return MAP_FAILED;
  217. }
  218. }
  219. snprintf (path, sizeof(path), "%s/jack/shm%s", jack_server_dir, shm_name);
  220. if ((status = stat (path, &statbuf)) < 0) {
  221. int fd;
  222. if ((fd = open (path, O_RDWR|O_CREAT, 0775)) < 0) {
  223. jack_error ("cannot create shm file node for %s (%s)", path, strerror (errno));
  224. return MAP_FAILED;
  225. }
  226. close (fd);
  227. }
  228. if ((key = ftok (path, 'j')) < 0) {
  229. jack_error ("cannot generate IPC key for shm segment %s (%s)", path, strerror (errno));
  230. unlink (path);
  231. return MAP_FAILED;
  232. }
  233. /* XXX need to figure out how to do this without causing the inode reallocation
  234. the next time this function is called resulting in ftok() returning non-unique
  235. keys.
  236. */
  237. /* unlink (path); */
  238. shmflags = mode;
  239. if (perm & O_CREAT) {
  240. shmflags |= IPC_CREAT;
  241. }
  242. if (perm & O_TRUNC) {
  243. shmflags |= IPC_EXCL;
  244. }
  245. if ((*shmid = shmget (key, size, shmflags)) < 0) {
  246. if (errno == EEXIST && (shmflags & IPC_EXCL)) {
  247. shmflags &= ~IPC_EXCL;
  248. if ((*shmid = shmget (key, size, shmflags)) < 0) {
  249. jack_error ("cannot get existing shm segment for %s (%s)",
  250. shm_name, strerror (errno));
  251. return MAP_FAILED;
  252. }
  253. } else {
  254. jack_error ("cannot create shm segment %s (%s)", shm_name, strerror (errno));
  255. return MAP_FAILED;
  256. }
  257. }
  258. if ((addr = shmat (*shmid, 0, 0)) < 0) {
  259. jack_error ("cannot attach shm segment %s (%s)", shm_name, strerror (errno));
  260. return MAP_FAILED;
  261. }
  262. return addr;
  263. }
  264. char *
  265. jack_resize_shm (const char *shm_name, size_t size, int perm, int mode, int prot)
  266. {
  267. jack_error ("jack_resize_shm() is not implemented for the System V shared memory API");
  268. return 0;
  269. }
  270. #endif /* USE_POSIX_SHM */