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.

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