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.

406 lines
8.8KB

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