jack2 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.

1190 lines
29KB

  1. /* This module provides a set of abstract shared memory interfaces
  2. * with support using both System V and POSIX shared memory
  3. * implementations. The code is divided into three sections:
  4. *
  5. * - common (interface-independent) code
  6. * - POSIX implementation
  7. * - System V implementation
  8. *
  9. * The implementation used is determined by whether USE_POSIX_SHM was
  10. * set in the ./configure step.
  11. */
  12. /*
  13. * Copyright (C) 2003 Paul Davis
  14. * Copyright (C) 2004 Jack O'Quin
  15. * Copyright (C) 2006-2007 Grame
  16. *
  17. * This program is free software; you can redistribute it and/or modify
  18. * it under the terms of the GNU General Public License as published by
  19. * the Free Software Foundation; either version 2 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  30. *
  31. */
  32. #include "JackConstants.h"
  33. #ifdef WIN32
  34. #include <process.h>
  35. #else
  36. #include <unistd.h>
  37. #include <fcntl.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <signal.h>
  41. #include <limits.h>
  42. #include <errno.h>
  43. #include <dirent.h>
  44. #include <sys/mman.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #include <sys/shm.h>
  48. #include <sys/sem.h>
  49. #include <stdlib.h>
  50. #endif
  51. #include "shm.h"
  52. #include "JackError.h"
  53. #ifdef USE_POSIX_SHM
  54. static jack_shmtype_t jack_shmtype = shm_POSIX;
  55. #elif WIN32
  56. static jack_shmtype_t jack_shmtype = shm_WIN32;
  57. #else
  58. static jack_shmtype_t jack_shmtype = shm_SYSV;
  59. #endif
  60. /* interface-dependent forward declarations */
  61. static int jack_access_registry (jack_shm_info_t *ri);
  62. static int jack_create_registry (jack_shm_info_t *ri);
  63. static void jack_remove_shm (jack_shm_id_t *id);
  64. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  65. * common interface-independent section
  66. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  67. /* The JACK SHM registry is a chunk of memory for keeping track of the
  68. * shared memory used by each active JACK server. This allows the
  69. * server to clean up shared memory when it exits. To avoid memory
  70. * leakage due to kill -9, crashes or debugger-driven exits, this
  71. * cleanup is also done when a new instance of that server starts.
  72. */
  73. /* per-process global data for the SHM interfaces */
  74. static jack_shm_id_t registry_id; /* SHM id for the registry */
  75. #ifdef WIN32
  76. static jack_shm_info_t registry_info = {/* SHM info for the registry */
  77. JACK_SHM_NULL_INDEX,
  78. NULL
  79. };
  80. #else
  81. static jack_shm_info_t registry_info = { /* SHM info for the registry */
  82. .index = JACK_SHM_NULL_INDEX,
  83. .attached_at = MAP_FAILED
  84. };
  85. #endif
  86. /* pointers to registry header and array */
  87. static jack_shm_header_t *jack_shm_header = NULL;
  88. static jack_shm_registry_t *jack_shm_registry = NULL;
  89. static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
  90. /* jack_shm_lock_registry() serializes updates to the shared memory
  91. * segment JACK uses to keep track of the SHM segments allocated to
  92. * all its processes, including multiple servers.
  93. *
  94. * This is not a high-contention lock, but it does need to work across
  95. * multiple processes. High transaction rates and realtime safety are
  96. * not required. Any solution needs to at least be portable to POSIX
  97. * and POSIX-like systems.
  98. *
  99. * We must be particularly careful to ensure that the lock be released
  100. * if the owning process terminates abnormally. Otherwise, a segfault
  101. * or kill -9 at the wrong moment could prevent JACK from ever running
  102. * again on that machine until after a reboot.
  103. */
  104. #define JACK_SEMAPHORE_KEY 0x282929
  105. #ifndef USE_POSIX_SHM
  106. #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
  107. #endif
  108. static int semid = -1;
  109. #ifdef WIN32
  110. // steph TODO
  111. static void
  112. semaphore_init () {}
  113. static void
  114. semaphore_add (int value) {}
  115. #else
  116. /* all semaphore errors are fatal -- issue message, but do not return */
  117. static void
  118. semaphore_error (char *msg)
  119. {
  120. jack_error ("Fatal JACK semaphore error: %s (%s)",
  121. msg, strerror (errno));
  122. abort ();
  123. }
  124. static void
  125. semaphore_init ()
  126. {
  127. key_t semkey = JACK_SEMAPHORE_KEY;
  128. struct sembuf sbuf;
  129. int create_flags = IPC_CREAT | IPC_EXCL
  130. | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
  131. /* Get semaphore ID associated with this key. */
  132. if ((semid = semget(semkey, 0, 0)) == -1) {
  133. /* Semaphore does not exist - Create. */
  134. if ((semid = semget(semkey, 1, create_flags)) != -1) {
  135. /* Initialize the semaphore, allow one owner. */
  136. sbuf.sem_num = 0;
  137. sbuf.sem_op = 1;
  138. sbuf.sem_flg = 0;
  139. if (semop(semid, &sbuf, 1) == -1) {
  140. semaphore_error ("semop");
  141. }
  142. } else if (errno == EEXIST) {
  143. if ((semid = semget(semkey, 0, 0)) == -1) {
  144. semaphore_error ("semget");
  145. }
  146. } else {
  147. semaphore_error ("semget creation");
  148. }
  149. }
  150. }
  151. static inline void
  152. semaphore_add (int value)
  153. {
  154. struct sembuf sbuf;
  155. sbuf.sem_num = 0;
  156. sbuf.sem_op = value;
  157. sbuf.sem_flg = SEM_UNDO;
  158. if (semop(semid, &sbuf, 1) == -1) {
  159. semaphore_error ("semop");
  160. }
  161. }
  162. #endif
  163. static void
  164. jack_shm_lock_registry (void)
  165. {
  166. if (semid == -1)
  167. semaphore_init ();
  168. semaphore_add (-1);
  169. }
  170. static void
  171. jack_shm_unlock_registry (void)
  172. {
  173. semaphore_add (1);
  174. }
  175. static void
  176. jack_shm_init_registry ()
  177. {
  178. /* registry must be locked */
  179. int i;
  180. memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
  181. jack_shm_header->magic = JACK_SHM_MAGIC;
  182. //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
  183. jack_shm_header->type = jack_shmtype;
  184. jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
  185. jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
  186. jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
  187. for (i = 0; i < MAX_SHM_ID; ++i) {
  188. jack_shm_registry[i].index = i;
  189. }
  190. }
  191. static int
  192. jack_shm_validate_registry ()
  193. {
  194. /* registry must be locked */
  195. if ((jack_shm_header->magic == JACK_SHM_MAGIC)
  196. //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
  197. && (jack_shm_header->type == jack_shmtype)
  198. && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
  199. && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
  200. && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
  201. return 0; /* registry OK */
  202. }
  203. return -1;
  204. }
  205. /* set a unique per-user, per-server shm prefix string
  206. *
  207. * According to the POSIX standard:
  208. *
  209. * "The name argument conforms to the construction rules for a
  210. * pathname. If name begins with the slash character, then processes
  211. * calling shm_open() with the same value of name refer to the same
  212. * shared memory object, as long as that name has not been
  213. * removed. If name does not begin with the slash character, the
  214. * effect is implementation-defined. The interpretation of slash
  215. * characters other than the leading slash character in name is
  216. * implementation-defined."
  217. *
  218. * Since the Linux implementation does not allow slashes *within* the
  219. * name, in the interest of portability we use colons instead.
  220. */
  221. static void
  222. jack_set_server_prefix (const char *server_name)
  223. {
  224. #ifdef WIN32
  225. snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
  226. "jack-%d:%s:", _getpid (), server_name); // steph TO CHECK
  227. #else
  228. snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
  229. "/jack-%d:%s:", getuid (), server_name);
  230. #endif
  231. }
  232. /* gain server addressability to shared memory registration segment
  233. *
  234. * returns: 0 if successful
  235. */
  236. static int
  237. jack_server_initialize_shm (int new_registry)
  238. {
  239. int rc;
  240. if (jack_shm_header)
  241. return 0; /* already initialized */
  242. jack_shm_lock_registry ();
  243. rc = jack_access_registry (&registry_info);
  244. if (new_registry) {
  245. jack_remove_shm (&registry_id);
  246. rc = ENOENT;
  247. }
  248. switch (rc) {
  249. case ENOENT: /* registry does not exist */
  250. rc = jack_create_registry (&registry_info);
  251. break;
  252. case 0: /* existing registry */
  253. if (jack_shm_validate_registry () == 0)
  254. break;
  255. /* else it was invalid, so fall through */
  256. case EINVAL: /* bad registry */
  257. /* Apparently, this registry was created by an older
  258. * JACK version. Delete it so we can try again. */
  259. jack_release_shm (&registry_info);
  260. jack_remove_shm (&registry_id);
  261. if ((rc = jack_create_registry (&registry_info)) != 0) {
  262. jack_error ("incompatible shm registry (%s)",
  263. strerror (errno));
  264. #ifndef USE_POSIX_SHM
  265. jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
  266. JACK_SHM_REGISTRY_KEY);
  267. #endif
  268. }
  269. break;
  270. default: /* failure return code */
  271. break;
  272. }
  273. jack_shm_unlock_registry ();
  274. return rc;
  275. }
  276. /* gain client addressability to shared memory registration segment
  277. *
  278. * NOTE: this function is no longer used for server initialization,
  279. * instead it calls jack_register_server().
  280. *
  281. * returns: 0 if successful
  282. */
  283. int
  284. jack_initialize_shm (const char *server_name)
  285. {
  286. int rc;
  287. if (jack_shm_header)
  288. return 0; /* already initialized */
  289. jack_set_server_prefix (server_name);
  290. jack_shm_lock_registry ();
  291. if ((rc = jack_access_registry (&registry_info)) == 0) {
  292. if ((rc = jack_shm_validate_registry ()) != 0) {
  293. jack_error ("Incompatible shm registry, "
  294. "are jackd and libjack in sync?");
  295. }
  296. }
  297. jack_shm_unlock_registry ();
  298. return rc;
  299. }
  300. char* jack_shm_addr (jack_shm_info_t* si)
  301. {
  302. return (char*)si->attached_at;
  303. }
  304. void
  305. jack_destroy_shm (jack_shm_info_t* si)
  306. {
  307. /* must NOT have the registry locked */
  308. if (si->index == JACK_SHM_NULL_INDEX)
  309. return; /* segment not allocated */
  310. jack_remove_shm (&jack_shm_registry[si->index].id);
  311. jack_release_shm_info (si->index);
  312. }
  313. jack_shm_registry_t *
  314. jack_get_free_shm_info ()
  315. {
  316. /* registry must be locked */
  317. jack_shm_registry_t* si = NULL;
  318. int i;
  319. for (i = 0; i < MAX_SHM_ID; ++i) {
  320. if (jack_shm_registry[i].size == 0) {
  321. break;
  322. }
  323. }
  324. if (i < MAX_SHM_ID) {
  325. si = &jack_shm_registry[i];
  326. }
  327. return si;
  328. }
  329. static void
  330. jack_release_shm_entry (jack_shm_registry_index_t index)
  331. {
  332. /* the registry must be locked */
  333. jack_shm_registry[index].size = 0;
  334. jack_shm_registry[index].allocator = 0;
  335. memset (&jack_shm_registry[index].id, 0,
  336. sizeof (jack_shm_registry[index].id));
  337. }
  338. void
  339. jack_release_shm_info (jack_shm_registry_index_t index)
  340. {
  341. #ifdef WIN32
  342. int my_pid = _getpid();
  343. #else
  344. pid_t my_pid = getpid();
  345. #endif
  346. /* must NOT have the registry locked */
  347. if (jack_shm_registry[index].allocator == my_pid) {
  348. jack_shm_lock_registry ();
  349. jack_release_shm_entry (index);
  350. jack_shm_unlock_registry ();
  351. }
  352. }
  353. /* Claim server_name for this process.
  354. *
  355. * returns 0 if successful
  356. * EEXIST if server_name was already active for this user
  357. * ENOSPC if server registration limit reached
  358. * ENOMEM if unable to access shared memory registry
  359. */
  360. int
  361. jack_register_server (const char *server_name, int new_registry)
  362. {
  363. int i, res = 0;
  364. #ifdef WIN32
  365. int my_pid = _getpid();
  366. #else
  367. pid_t my_pid = getpid();
  368. #endif
  369. jack_set_server_prefix (server_name);
  370. if (jack_server_initialize_shm (new_registry))
  371. return ENOMEM;
  372. jack_shm_lock_registry ();
  373. /* See if server_name already registered. Since server names
  374. * are per-user, we register the unique server prefix string.
  375. */
  376. for (i = 0; i < MAX_SERVERS; i++) {
  377. if (strncmp (jack_shm_header->server[i].name,
  378. jack_shm_server_prefix,
  379. JACK_SERVER_NAME_SIZE) != 0)
  380. continue; /* no match */
  381. if (jack_shm_header->server[i].pid == my_pid){
  382. res = 0; /* it's me */
  383. goto unlock;
  384. }
  385. /* see if server still exists */
  386. #ifndef WIN32 // steph TO CHECK
  387. if (kill (jack_shm_header->server[i].pid, 0) == 0) {
  388. res = EEXIST; /* other server running */
  389. goto unlock;
  390. }
  391. #endif
  392. /* it's gone, reclaim this entry */
  393. memset (&jack_shm_header->server[i], 0,
  394. sizeof (jack_shm_server_t));
  395. }
  396. /* find a free entry */
  397. for (i = 0; i < MAX_SERVERS; i++) {
  398. if (jack_shm_header->server[i].pid == 0)
  399. break;
  400. }
  401. if (i >= MAX_SERVERS){
  402. res = ENOSPC; /* out of space */
  403. goto unlock;
  404. }
  405. /* claim it */
  406. jack_shm_header->server[i].pid = my_pid;
  407. strncpy (jack_shm_header->server[i].name,
  408. jack_shm_server_prefix,
  409. JACK_SERVER_NAME_SIZE);
  410. unlock:
  411. jack_shm_unlock_registry ();
  412. return 0;
  413. }
  414. /* release server_name registration */
  415. void
  416. jack_unregister_server (const char *server_name /* unused */)
  417. {
  418. int i;
  419. #ifdef WIN32
  420. int my_pid = _getpid();
  421. #else
  422. pid_t my_pid = getpid();
  423. #endif
  424. jack_shm_lock_registry ();
  425. for (i = 0; i < MAX_SERVERS; i++) {
  426. if (jack_shm_header->server[i].pid == my_pid) {
  427. memset (&jack_shm_header->server[i], 0,
  428. sizeof (jack_shm_server_t));
  429. }
  430. }
  431. jack_shm_unlock_registry ();
  432. }
  433. /* called for server startup and termination */
  434. int
  435. jack_cleanup_shm ()
  436. {
  437. int i;
  438. int destroy;
  439. jack_shm_info_t copy;
  440. #ifdef WIN32
  441. int my_pid = _getpid();
  442. #else
  443. pid_t my_pid = getpid();
  444. #endif
  445. jack_shm_lock_registry ();
  446. for (i = 0; i < MAX_SHM_ID; i++) {
  447. jack_shm_registry_t* r;
  448. r = &jack_shm_registry[i];
  449. memcpy (&copy, r, sizeof (jack_shm_info_t));
  450. destroy = FALSE;
  451. /* ignore unused entries */
  452. if (r->allocator == 0)
  453. continue;
  454. /* is this my shm segment? */
  455. if (r->allocator == my_pid) {
  456. /* allocated by this process, so unattach
  457. and destroy. */
  458. jack_release_shm (&copy);
  459. destroy = TRUE;
  460. } else {
  461. /* see if allocator still exists */
  462. #ifdef WIN32 // steph
  463. jack_info("TODO: kill API not available !!");
  464. #else
  465. if (kill (r->allocator, 0)) {
  466. if (errno == ESRCH) {
  467. /* allocator no longer exists,
  468. * so destroy */
  469. destroy = TRUE;
  470. }
  471. }
  472. #endif
  473. }
  474. if (destroy) {
  475. int index = copy.index;
  476. if ((index >= 0) && (index < MAX_SHM_ID)) {
  477. jack_remove_shm (&jack_shm_registry[index].id);
  478. jack_release_shm_entry (index);
  479. }
  480. r->size = 0;
  481. r->allocator = 0;
  482. }
  483. }
  484. jack_shm_unlock_registry ();
  485. return TRUE;
  486. }
  487. /* resize a shared memory segment
  488. *
  489. * There is no way to resize a System V shm segment. Resizing is
  490. * possible with POSIX shm, but not with the non-conformant Mac OS X
  491. * implementation. Since POSIX shm is mainly used on that platform,
  492. * it's simpler to treat them both the same.
  493. *
  494. * So, we always resize by deleting and reallocating. This is
  495. * tricky, because the old segment will not disappear until
  496. * all the clients have released it. We only do what we can
  497. * from here.
  498. *
  499. * This is not done under a single lock. I don't even want to think
  500. * about all the things that could possibly go wrong if multple
  501. * processes tried to resize the same segment concurrently. That
  502. * probably doesn't happen.
  503. */
  504. int
  505. jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
  506. {
  507. jack_shm_id_t id;
  508. /* The underlying type of `id' differs for SYSV and POSIX */
  509. memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
  510. jack_release_shm (si);
  511. jack_destroy_shm (si);
  512. if (jack_shmalloc ((char *) id, size, si)) {
  513. return -1;
  514. }
  515. return jack_attach_shm (si);
  516. }
  517. #ifdef USE_POSIX_SHM
  518. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  519. * POSIX interface-dependent functions
  520. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  521. /* gain addressability to existing SHM registry segment
  522. *
  523. * sets up global registry pointers, if successful
  524. *
  525. * returns: 0 if existing registry accessed successfully
  526. * ENOENT if registry does not exist
  527. * EINVAL if registry exists, but has the wrong size
  528. */
  529. static int
  530. jack_access_registry (jack_shm_info_t *ri)
  531. {
  532. /* registry must be locked */
  533. int shm_fd;
  534. strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
  535. /* try to open an existing segment */
  536. if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
  537. int rc = errno;
  538. if (errno != ENOENT) {
  539. jack_error ("Cannot open existing shm registry segment"
  540. " (%s)", strerror (errno));
  541. }
  542. close (shm_fd);
  543. return rc;
  544. }
  545. if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
  546. PROT_READ|PROT_WRITE,
  547. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  548. jack_error ("Cannot mmap shm registry segment (%s)",
  549. strerror (errno));
  550. close (shm_fd);
  551. return EINVAL;
  552. }
  553. /* set up global pointers */
  554. ri->index = JACK_SHM_REGISTRY_INDEX;
  555. jack_shm_header = ri->attached_at;
  556. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  557. close (shm_fd); // steph
  558. return 0;
  559. }
  560. /* create a new SHM registry segment
  561. *
  562. * sets up global registry pointers, if successful
  563. *
  564. * returns: 0 if registry created successfully
  565. * nonzero error code if unable to allocate a new registry
  566. */
  567. static int
  568. jack_create_registry (jack_shm_info_t *ri)
  569. {
  570. /* registry must be locked */
  571. int shm_fd;
  572. strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
  573. if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
  574. int rc = errno;
  575. jack_error ("Cannot create shm registry segment (%s)",
  576. strerror (errno));
  577. return rc;
  578. }
  579. /* Previous shm_open result depends of the actual value of umask, force correct file permisssion here */
  580. if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
  581. jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
  582. }
  583. /* Set the desired segment size. NOTE: the non-conformant Mac
  584. * OS X POSIX shm only allows ftruncate() on segment creation.
  585. */
  586. if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
  587. int rc = errno;
  588. jack_error ("Cannot set registry size (%s)", strerror (errno));
  589. jack_remove_shm (&registry_id);
  590. close (shm_fd);
  591. return rc;
  592. }
  593. if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
  594. PROT_READ|PROT_WRITE,
  595. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  596. jack_error ("Cannot mmap shm registry segment (%s)",
  597. strerror (errno));
  598. jack_remove_shm (&registry_id);
  599. close (shm_fd);
  600. return EINVAL;
  601. }
  602. /* set up global pointers */
  603. ri->index = JACK_SHM_REGISTRY_INDEX;
  604. jack_shm_header = ri->attached_at;
  605. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  606. /* initialize registry contents */
  607. jack_shm_init_registry ();
  608. close (shm_fd); // steph
  609. return 0;
  610. }
  611. static void
  612. jack_remove_shm (jack_shm_id_t *id)
  613. {
  614. /* registry may or may not be locked */
  615. shm_unlink ((char *) id);
  616. }
  617. void
  618. jack_release_shm (jack_shm_info_t* si)
  619. {
  620. /* registry may or may not be locked */
  621. if (si->attached_at != MAP_FAILED) {
  622. munmap (si->attached_at, jack_shm_registry[si->index].size);
  623. }
  624. }
  625. /* allocate a POSIX shared memory segment */
  626. int
  627. jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
  628. {
  629. jack_shm_registry_t* registry;
  630. int shm_fd;
  631. int rc = -1;
  632. char name[SHM_NAME_MAX+1];
  633. jack_shm_lock_registry ();
  634. if ((registry = jack_get_free_shm_info ()) == NULL) {
  635. jack_error ("shm registry full");
  636. goto unlock;
  637. }
  638. /* On Mac OS X, the maximum length of a shared memory segment
  639. * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
  640. * defined by the standard). Unfortunately, Apple sets this
  641. * value so small (about 31 bytes) that it is useless for
  642. * actual names. So, we construct a short name from the
  643. * registry index for uniqueness and ignore the shm_name
  644. * parameter. Bah!
  645. */
  646. snprintf (name, sizeof (name), "/jackmp-%d", registry->index);
  647. if (strlen (name) >= sizeof (registry->id)) {
  648. jack_error ("shm segment name too long %s", name);
  649. goto unlock;
  650. }
  651. if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
  652. jack_error ("Cannot create shm segment %s (%s)",
  653. name, strerror (errno));
  654. goto unlock;
  655. }
  656. if (ftruncate (shm_fd, size) < 0) {
  657. jack_error ("Cannot set size of engine shm "
  658. "registry 0 (%s)",
  659. strerror (errno));
  660. close (shm_fd);
  661. goto unlock;
  662. }
  663. close (shm_fd);
  664. registry->size = size;
  665. strncpy (registry->id, name, sizeof (registry->id));
  666. registry->allocator = getpid();
  667. si->index = registry->index;
  668. si->attached_at = MAP_FAILED; /* not attached */
  669. rc = 0; /* success */
  670. unlock:
  671. jack_shm_unlock_registry ();
  672. return rc;
  673. }
  674. int
  675. jack_attach_shm (jack_shm_info_t* si)
  676. {
  677. int shm_fd;
  678. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  679. if ((shm_fd = shm_open (registry->id,
  680. O_RDWR, 0666)) < 0) {
  681. jack_error ("Cannot open shm segment %s (%s)", registry->id,
  682. strerror (errno));
  683. return -1;
  684. }
  685. if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
  686. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  687. jack_error ("Cannot mmap shm segment %s (%s)",
  688. registry->id,
  689. strerror (errno));
  690. close (shm_fd);
  691. return -1;
  692. }
  693. close (shm_fd);
  694. return 0;
  695. }
  696. int
  697. jack_attach_shm_read (jack_shm_info_t* si)
  698. {
  699. int shm_fd;
  700. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  701. if ((shm_fd = shm_open (registry->id,
  702. O_RDONLY, 0666)) < 0) {
  703. jack_error ("Cannot open shm segment %s (%s)", registry->id,
  704. strerror (errno));
  705. return -1;
  706. }
  707. if ((si->attached_at = mmap (0, registry->size, PROT_READ,
  708. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  709. jack_error ("Cannot mmap shm segment %s (%s)",
  710. registry->id,
  711. strerror (errno));
  712. close (shm_fd);
  713. return -1;
  714. }
  715. close (shm_fd);
  716. return 0;
  717. }
  718. #elif WIN32
  719. static int
  720. jack_access_registry (jack_shm_info_t *ri)
  721. {
  722. /* registry must be locked */
  723. HANDLE shm_fd;
  724. LPSECURITY_ATTRIBUTES sec = 0;
  725. strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
  726. /* try to open an existing segment */
  727. if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
  728. int rc = GetLastError();
  729. if (rc != ERROR_FILE_NOT_FOUND) {
  730. jack_error ("Cannot open existing shm registry segment (%ld)", rc);
  731. }
  732. return rc;
  733. }
  734. if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
  735. jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
  736. jack_remove_shm (&registry_id);
  737. CloseHandle (shm_fd);
  738. return EINVAL;
  739. }
  740. /* set up global pointers */
  741. ri->index = JACK_SHM_REGISTRY_INDEX;
  742. jack_shm_header = ri->attached_at;
  743. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  744. //CloseHandle(shm_fd); // TO CHECK
  745. return 0;
  746. }
  747. static int
  748. jack_create_registry (jack_shm_info_t *ri)
  749. {
  750. /* registry must be locked */
  751. HANDLE shm_fd;
  752. strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
  753. if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
  754. 0, PAGE_READWRITE,
  755. 0, JACK_SHM_REGISTRY_SIZE,
  756. registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
  757. int rc = GetLastError();
  758. jack_error ("Cannot create shm registry segment (%ld)", rc);
  759. return rc;
  760. }
  761. if ((ri->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
  762. jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
  763. jack_remove_shm (&registry_id);
  764. CloseHandle (shm_fd);
  765. return EINVAL;
  766. }
  767. /* set up global pointers */
  768. ri->index = JACK_SHM_REGISTRY_INDEX;
  769. jack_shm_header = ri->attached_at;
  770. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  771. /* initialize registry contents */
  772. jack_shm_init_registry ();
  773. //CloseHandle(shm_fd); // TO CHECK
  774. return 0;
  775. }
  776. static void
  777. jack_remove_shm (jack_shm_id_t *id)
  778. {
  779. /* nothing to do */
  780. }
  781. void
  782. jack_release_shm (jack_shm_info_t* si)
  783. {
  784. /* registry may or may not be locked */
  785. if (si->attached_at != NULL) {
  786. UnmapViewOfFile (si->attached_at);
  787. }
  788. }
  789. int
  790. jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
  791. {
  792. jack_shm_registry_t* registry;
  793. HANDLE shm_fd;
  794. int rc = -1;
  795. char name[SHM_NAME_MAX+1];
  796. jack_shm_lock_registry ();
  797. if ((registry = jack_get_free_shm_info ()) == NULL) {
  798. jack_error ("shm registry full");
  799. goto unlock;
  800. }
  801. snprintf (name, sizeof (name), "jack-%d", registry->index);
  802. if (strlen (name) >= sizeof (registry->id)) {
  803. jack_error ("shm segment name too long %s", name);
  804. goto unlock;
  805. }
  806. if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
  807. 0, PAGE_READWRITE,
  808. 0, size,
  809. name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
  810. int rc = GetLastError();
  811. jack_error ("Cannot create shm segment (%ld)",rc);
  812. goto unlock;
  813. }
  814. //CloseHandle (shm_fd); // TO CHECK
  815. registry->size = size;
  816. strncpy (registry->id, name, sizeof (registry->id));
  817. registry->allocator = _getpid();
  818. si->index = registry->index;
  819. si->attached_at = NULL; /* not attached */
  820. rc = 0; /* success */
  821. unlock:
  822. jack_shm_unlock_registry ();
  823. return rc;
  824. }
  825. int
  826. jack_attach_shm (jack_shm_info_t* si)
  827. {
  828. HANDLE shm_fd;
  829. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  830. if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
  831. int rc = GetLastError();
  832. jack_error ("Cannot open shm segment (%ld)",rc);
  833. return -1;
  834. }
  835. if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
  836. jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
  837. jack_remove_shm (&registry_id);
  838. CloseHandle (shm_fd);
  839. return -1;
  840. }
  841. //CloseHandle (shm_fd); // TO CHECK
  842. return 0;
  843. }
  844. int
  845. jack_attach_shm_read (jack_shm_info_t* si)
  846. {
  847. HANDLE shm_fd;
  848. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  849. if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
  850. int rc = GetLastError();
  851. jack_error ("Cannot open shm segment (%ld)",rc);
  852. return -1;
  853. }
  854. if ((si->attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
  855. jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
  856. jack_remove_shm (&registry_id);
  857. CloseHandle (shm_fd);
  858. return -1;
  859. }
  860. //CloseHandle (shm_fd); // TO CHECK
  861. return 0;
  862. }
  863. #else
  864. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  865. * System V interface-dependent functions
  866. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  867. /* gain addressability to existing SHM registry segment
  868. *
  869. * sets up global registry pointers, if successful
  870. *
  871. * returns: 0 if existing registry accessed successfully
  872. * ENOENT if registry does not exist
  873. * EINVAL if registry exists, but has the wrong size
  874. * other nonzero error code if unable to access registry
  875. */
  876. static int
  877. jack_access_registry (jack_shm_info_t *ri)
  878. {
  879. /* registry must be locked */
  880. /* try without IPC_CREAT to get existing segment */
  881. if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
  882. JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
  883. switch (errno) {
  884. case ENOENT: /* segment does not exist */
  885. return ENOENT;
  886. case EINVAL: /* segment exists, but too small */
  887. /* attempt minimum size access */
  888. registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
  889. return EINVAL;
  890. default: /* or other error */
  891. jack_error ("unable to access shm registry (%s)",
  892. strerror (errno));
  893. return errno;
  894. }
  895. }
  896. if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
  897. jack_error ("Cannot attach shm registry segment (%s)",
  898. strerror (errno));
  899. return EINVAL;
  900. }
  901. /* set up global pointers */
  902. ri->index = JACK_SHM_REGISTRY_INDEX;
  903. jack_shm_header = ri->attached_at;
  904. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  905. return 0;
  906. }
  907. /* create a new SHM registry segment
  908. *
  909. * sets up global registry pointers, if successful
  910. *
  911. * returns: 0 if registry created successfully
  912. * nonzero error code if unable to allocate a new registry
  913. */
  914. static int
  915. jack_create_registry (jack_shm_info_t *ri)
  916. {
  917. /* registry must be locked */
  918. if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
  919. JACK_SHM_REGISTRY_SIZE,
  920. 0666|IPC_CREAT)) < 0) {
  921. jack_error ("Cannot create shm registry segment (%s)",
  922. strerror (errno));
  923. return errno;
  924. }
  925. if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
  926. jack_error ("Cannot attach shm registry segment (%s)",
  927. strerror (errno));
  928. return EINVAL;
  929. }
  930. /* set up global pointers */
  931. ri->index = JACK_SHM_REGISTRY_INDEX;
  932. jack_shm_header = ri->attached_at;
  933. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  934. /* initialize registry contents */
  935. jack_shm_init_registry ();
  936. return 0;
  937. }
  938. static void
  939. jack_remove_shm (jack_shm_id_t *id)
  940. {
  941. /* registry may or may not be locked */
  942. shmctl (*id, IPC_RMID, NULL);
  943. }
  944. void
  945. jack_release_shm (jack_shm_info_t* si)
  946. {
  947. /* registry may or may not be locked */
  948. if (si->attached_at != MAP_FAILED) {
  949. shmdt (si->attached_at);
  950. }
  951. }
  952. int
  953. jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
  954. jack_shm_info_t* si)
  955. {
  956. int shmflags;
  957. int shmid;
  958. int rc = -1;
  959. jack_shm_registry_t* registry;
  960. jack_shm_lock_registry ();
  961. if ((registry = jack_get_free_shm_info ())) {
  962. shmflags = 0666 | IPC_CREAT | IPC_EXCL;
  963. if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
  964. registry->size = size;
  965. registry->id = shmid;
  966. registry->allocator = getpid();
  967. si->index = registry->index;
  968. si->attached_at = MAP_FAILED; /* not attached */
  969. rc = 0;
  970. } else {
  971. jack_error ("Cannot create shm segment %s (%s)",
  972. name_not_used, strerror (errno));
  973. }
  974. }
  975. jack_shm_unlock_registry ();
  976. return rc;
  977. }
  978. int
  979. jack_attach_shm (jack_shm_info_t* si)
  980. {
  981. if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
  982. jack_error ("Cannot attach shm segment (%s)",
  983. strerror (errno));
  984. jack_release_shm_info (si->index);
  985. return -1;
  986. }
  987. return 0;
  988. }
  989. #endif /* !USE_POSIX_SHM */