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.

472 lines
9.7KB

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