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.

372 lines
8.4KB

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