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.

470 lines
9.6KB

  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 <config.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <signal.h>
  22. #include <limits.h>
  23. #include <errno.h>
  24. #include <dirent.h>
  25. #include <sys/mman.h>
  26. #include <sys/types.h>
  27. #include <sys/shm.h>
  28. #include <jack/shm.h>
  29. #include <jack/internal.h>
  30. static jack_shm_registry_t* jack_shm_registry;
  31. static void
  32. jack_shm_lock_registry ()
  33. {
  34. /* XXX magic with semaphores here */
  35. }
  36. static void
  37. jack_shm_unlock_registry ()
  38. {
  39. /* XXX magic with semaphores here */
  40. }
  41. jack_shm_registry_t *
  42. jack_get_free_shm_info ()
  43. {
  44. jack_shm_registry_t* si = NULL;
  45. int i;
  46. jack_shm_lock_registry ();
  47. for (i = 0; i < MAX_SHM_ID; ++i) {
  48. if (jack_shm_registry[i].size == 0) {
  49. break;
  50. }
  51. }
  52. if (i < MAX_SHM_ID) {
  53. si = &jack_shm_registry[i];
  54. }
  55. jack_shm_unlock_registry ();
  56. return si;
  57. }
  58. void
  59. jack_release_shm_info (jack_shm_registry_index_t index)
  60. {
  61. if (jack_shm_registry[index].allocator == getpid()) {
  62. jack_shm_lock_registry ();
  63. jack_shm_registry[index].size = 0;
  64. jack_shm_registry[index].allocator = 0;
  65. jack_shm_unlock_registry ();
  66. }
  67. }
  68. void
  69. jack_cleanup_shm (void)
  70. {
  71. int i;
  72. int destroy;
  73. jack_shm_info_t copy;
  74. jack_initialize_shm ();
  75. jack_shm_lock_registry ();
  76. for (i = 0; i < MAX_SHM_ID; i++) {
  77. jack_shm_registry_t* r;
  78. r = &jack_shm_registry[i];
  79. copy.index = r->index;
  80. destroy = FALSE;
  81. if (r->allocator == getpid()) {
  82. /* allocated by this process, so unattach
  83. and destroy. */
  84. jack_release_shm (&copy);
  85. destroy = TRUE;
  86. } else {
  87. if (kill (r->allocator, 0)) {
  88. if (errno == ESRCH) {
  89. /* allocator no longer exists,
  90. * so destroy */
  91. destroy = TRUE;
  92. }
  93. }
  94. }
  95. if (destroy) {
  96. jack_destroy_shm (&copy);
  97. r->size = 0;
  98. r->allocator = 0;
  99. }
  100. }
  101. jack_shm_unlock_registry ();
  102. }
  103. #ifdef USE_POSIX_SHM
  104. int
  105. jack_initialize_shm (void)
  106. {
  107. int shm_fd;
  108. jack_shmsize_t size;
  109. int new_registry = FALSE;
  110. int ret = -1;
  111. int perm;
  112. if (jack_shm_registry != NULL) {
  113. return 0;
  114. }
  115. /* grab a chunk of memory to store shm ids in. this is
  116. to allow clean up of all segments whenever JACK
  117. starts (or stops). */
  118. size = sizeof (jack_shm_registry_t) * MAX_SHM_ID;
  119. jack_shm_lock_registry ();
  120. perm = O_RDWR;
  121. /* try without O_CREAT to see if it already exists */
  122. if ((shm_fd = shm_open ("/jack-shm-registry", perm, 0666)) < 0) {
  123. if (errno == ENOENT) {
  124. /* it doesn't exist, so create it */
  125. perm = O_RDWR|O_CREAT;
  126. if ((shm_fd =
  127. shm_open ("/jack-shm-registry", perm, 0666)) < 0) {
  128. jack_error ("cannot create shm registry segment"
  129. " (%s)", strerror (errno));
  130. goto out;
  131. }
  132. new_registry = TRUE;
  133. } else {
  134. jack_error ("cannot open existing shm registry segment"
  135. " (%s)", strerror (errno));
  136. goto out;
  137. }
  138. }
  139. if (perm & O_CREAT) {
  140. if (ftruncate (shm_fd, size) < 0) {
  141. jack_error ("cannot set size of engine shm registry 1"
  142. "(%s)", strerror (errno));
  143. goto out;
  144. }
  145. }
  146. if ((jack_shm_registry = mmap (0, size, PROT_READ|PROT_WRITE,
  147. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  148. jack_error ("cannot mmap shm registry segment (%s)",
  149. strerror (errno));
  150. goto out;
  151. }
  152. if (new_registry) {
  153. int i;
  154. memset (jack_shm_registry, 0, size);
  155. for (i = 0; i < MAX_SHM_ID; ++i) {
  156. jack_shm_registry[i].index = i;
  157. }
  158. fprintf (stderr, "JACK compiled with POSIX SHM support\n");
  159. }
  160. ret = 0;
  161. out:
  162. close (shm_fd);
  163. jack_shm_unlock_registry ();
  164. return ret;
  165. }
  166. void
  167. jack_destroy_shm (jack_shm_info_t* si)
  168. {
  169. shm_unlink (jack_shm_registry[si->index].id);
  170. jack_release_shm_info (si->index);
  171. }
  172. void
  173. jack_release_shm (jack_shm_info_t* si)
  174. {
  175. if (si->attached_at != MAP_FAILED) {
  176. munmap (si->attached_at, jack_shm_registry[si->index].size);
  177. }
  178. }
  179. int
  180. jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
  181. {
  182. jack_shm_registry_t* registry;
  183. int shm_fd;
  184. int perm = O_RDWR|O_CREAT;
  185. if ((registry = jack_get_free_shm_info ()) == NULL) {
  186. return -1;
  187. }
  188. if ((shm_fd = shm_open (shm_name, O_RDWR|O_CREAT, 0666)) < 0) {
  189. jack_error ("cannot create shm segment %s (%s)", shm_name,
  190. strerror (errno));
  191. return -1;
  192. }
  193. if (perm & O_CREAT) {
  194. if (ftruncate (shm_fd, size) < 0) {
  195. jack_error ("cannot set size of engine shm "
  196. "registry 0 (%s)", strerror (errno));
  197. return -1;
  198. }
  199. }
  200. close (shm_fd);
  201. registry->size = size;
  202. snprintf (registry->id, sizeof (registry->id), "%s", shm_name);
  203. registry->allocator = getpid();
  204. si->index = registry->index;
  205. si->attached_at = MAP_FAILED; /* segment not attached */
  206. return 0;
  207. }
  208. int
  209. jack_attach_shm (jack_shm_info_t* si)
  210. {
  211. int shm_fd;
  212. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  213. if ((shm_fd = shm_open (registry->id,
  214. O_RDWR, 0666)) < 0) {
  215. jack_error ("cannot open shm segment %s (%s)", registry->id,
  216. strerror (errno));
  217. return -1;
  218. }
  219. if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
  220. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  221. jack_error ("cannot mmap shm segment %s (%s)",
  222. registry->id,
  223. strerror (errno));
  224. close (shm_fd);
  225. return -1;
  226. }
  227. close (shm_fd);
  228. return 0;
  229. }
  230. int
  231. jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
  232. {
  233. int shm_fd;
  234. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  235. if ((shm_fd = shm_open (registry->id, O_RDWR, 0666)) < 0) {
  236. jack_error ("cannot create shm segment %s (%s)", registry->id,
  237. strerror (errno));
  238. return -1;
  239. }
  240. munmap (si->attached_at, registry->size);
  241. if (ftruncate (shm_fd, size) < 0) {
  242. jack_error ("cannot set size of shm segment %s "
  243. "(%s)", registry->id, strerror (errno));
  244. return -1;
  245. }
  246. if ((si->attached_at = mmap (0, size, PROT_READ|PROT_WRITE,
  247. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  248. jack_error ("cannot mmap shm segment %s (%s)", registry->id,
  249. strerror (errno));
  250. close (shm_fd);
  251. return -1;
  252. }
  253. close (shm_fd);
  254. return 0;
  255. }
  256. #else /* USE_POSIX_SHM */
  257. #define JACK_SHM_REGISTRY_KEY 0x282929
  258. int
  259. jack_initialize_shm (void)
  260. {
  261. int shmflags;
  262. int shmid;
  263. key_t key;
  264. jack_shmsize_t size;
  265. int new_registry = FALSE;
  266. int ret = -1;
  267. if (jack_shm_registry != NULL) {
  268. return 0;
  269. }
  270. /* grab a chunk of memory to store shm ids in. this is
  271. to allow our parent to clean up all such ids when
  272. if we exit. otherwise, they can get lost in crash
  273. or debugger driven exits.
  274. */
  275. shmflags = 0666;
  276. key = JACK_SHM_REGISTRY_KEY;
  277. size = sizeof (jack_shm_registry_t) * MAX_SHM_ID;
  278. jack_shm_lock_registry ();
  279. /* try without IPC_CREAT to check if it already exists */
  280. if ((shmid = shmget (key, size, shmflags)) < 0) {
  281. if (errno == ENOENT) {
  282. if ((shmid = shmget (key, size,
  283. shmflags|IPC_CREAT)) < 0) {
  284. jack_error ("cannot create shm registry segment"
  285. " (%s)", strerror (errno));
  286. goto out;
  287. }
  288. new_registry = TRUE;
  289. } else {
  290. jack_error ("cannot use existing shm registry segment"
  291. " (%s)", strerror (errno));
  292. goto out;
  293. }
  294. }
  295. if ((jack_shm_registry = shmat (shmid, 0, 0)) < 0) {
  296. jack_error ("cannot attach shm registry segment (%s)",
  297. strerror (errno));
  298. goto out;
  299. }
  300. if (new_registry) {
  301. int i;
  302. memset (jack_shm_registry, 0, size);
  303. for (i = 0; i < MAX_SHM_ID; ++i) {
  304. jack_shm_registry[i].index = i;
  305. }
  306. fprintf (stderr, "JACK compiled with System V SHM support\n");
  307. }
  308. ret = 0;
  309. out:
  310. jack_shm_unlock_registry ();
  311. return ret;
  312. }
  313. void
  314. jack_destroy_shm (jack_shm_info_t* si)
  315. {
  316. shmctl (jack_shm_registry[si->index].id, IPC_RMID, NULL);
  317. jack_release_shm_info (si->index);
  318. }
  319. void
  320. jack_release_shm (jack_shm_info_t* si)
  321. {
  322. if (si->attached_at != MAP_FAILED) {
  323. shmdt (si->attached_at);
  324. }
  325. }
  326. int
  327. jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
  328. jack_shm_info_t* si)
  329. {
  330. int shmflags;
  331. int shmid;
  332. jack_shm_registry_t* registry;
  333. if ((registry = jack_get_free_shm_info ()) == NULL) {
  334. return -1;
  335. }
  336. shmflags = 0666 | IPC_CREAT | IPC_EXCL;
  337. if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) < 0) {
  338. jack_error ("cannot create shm segment %s (%s)",
  339. name_not_used, strerror (errno));
  340. return -1;
  341. }
  342. registry->size = size;
  343. registry->id = shmid;
  344. registry->allocator = getpid();
  345. si->index = registry->index;
  346. si->attached_at = MAP_FAILED; /* segment not attached */
  347. return 0;
  348. }
  349. int
  350. jack_attach_shm (jack_shm_info_t* si)
  351. {
  352. if ((si->attached_at = shmat (jack_shm_registry[si->index].id,
  353. 0, 0)) < 0) {
  354. jack_error ("cannot attach shm segment (%s)",
  355. strerror (errno));
  356. jack_release_shm_info (si->index);
  357. return -1;
  358. }
  359. return 0;
  360. }
  361. int
  362. jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
  363. {
  364. /* There is no way to resize a System V shm segment. So, we
  365. * delete it and allocate a new one. This is tricky, because
  366. * the old segment will not disappear until all the clients
  367. * have released it. We can only do what we can from here.
  368. */
  369. jack_release_shm (si);
  370. jack_destroy_shm (si);
  371. if (jack_shmalloc ("not used", size, si)) {
  372. return -1;
  373. }
  374. return jack_attach_shm (si);
  375. }
  376. #endif /* !USE_POSIX_SHM */