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. *
  16. * This program is free software; you can redistribute it and/or modify
  17. * it under the terms of the GNU General Public License as published by
  18. * the Free Software Foundation; either version 2 of the License, or
  19. * (at your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. *
  30. * $Id: shm.c,v 1.8.2.16 2006/08/28 10:10:16 letz Exp $
  31. */
  32. #ifdef WIN32
  33. #include <process.h>
  34. #else
  35. #include <unistd.h>
  36. #include <fcntl.h>
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <signal.h>
  40. #include <limits.h>
  41. #include <errno.h>
  42. #include <dirent.h>
  43. #include <sys/mman.h>
  44. #include <sys/types.h>
  45. #include <sys/stat.h>
  46. #include <sys/shm.h>
  47. #include <sys/sem.h>
  48. #include <stdlib.h>
  49. #endif
  50. #include "shm.h"
  51. #include "JackError.h"
  52. #ifdef USE_POSIX_SHM
  53. static jack_shmtype_t jack_shmtype = shm_POSIX;
  54. #elif WIN32
  55. static jack_shmtype_t jack_shmtype = shm_WIN32;
  56. #else
  57. static jack_shmtype_t jack_shmtype = shm_SYSV;
  58. #endif
  59. /* interface-dependent forward declarations */
  60. static int jack_access_registry (jack_shm_info_t *ri);
  61. static int jack_create_registry (jack_shm_info_t *ri);
  62. static void jack_remove_shm (jack_shm_id_t *id);
  63. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  64. * common interface-independent section
  65. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  66. /* The JACK SHM registry is a chunk of memory for keeping track of the
  67. * shared memory used by each active JACK server. This allows the
  68. * server to clean up shared memory when it exits. To avoid memory
  69. * leakage due to kill -9, crashes or debugger-driven exits, this
  70. * cleanup is also done when a new instance of that server starts.
  71. */
  72. /* per-process global data for the SHM interfaces */
  73. static jack_shm_id_t registry_id; /* SHM id for the registry */
  74. #ifdef WIN32
  75. static jack_shm_info_t registry_info = {/* SHM info for the registry */
  76. JACK_SHM_NULL_INDEX,
  77. NULL
  78. };
  79. #else
  80. static jack_shm_info_t registry_info = { /* SHM info for the registry */
  81. .index = JACK_SHM_NULL_INDEX,
  82. .attached_at = MAP_FAILED
  83. };
  84. #endif
  85. /* pointers to registry header and array */
  86. static jack_shm_header_t *jack_shm_header = NULL;
  87. static jack_shm_registry_t *jack_shm_registry = NULL;
  88. static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = "";
  89. /* jack_shm_lock_registry() serializes updates to the shared memory
  90. * segment JACK uses to keep track of the SHM segments allocated to
  91. * all its processes, including multiple servers.
  92. *
  93. * This is not a high-contention lock, but it does need to work across
  94. * multiple processes. High transaction rates and realtime safety are
  95. * not required. Any solution needs to at least be portable to POSIX
  96. * and POSIX-like systems.
  97. *
  98. * We must be particularly careful to ensure that the lock be released
  99. * if the owning process terminates abnormally. Otherwise, a segfault
  100. * or kill -9 at the wrong moment could prevent JACK from ever running
  101. * again on that machine until after a reboot.
  102. */
  103. #define JACK_SEMAPHORE_KEY 0x282929
  104. #ifndef USE_POSIX_SHM
  105. #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
  106. #endif
  107. static int semid = -1;
  108. #ifdef WIN32
  109. // steph TODO
  110. static void
  111. semaphore_init () {}
  112. static void
  113. semaphore_add (int value) {}
  114. #else
  115. /* all semaphore errors are fatal -- issue message, but do not return */
  116. static void
  117. semaphore_error (char *msg)
  118. {
  119. jack_error ("Fatal JACK semaphore error: %s (%s)",
  120. msg, strerror (errno));
  121. abort ();
  122. }
  123. static void
  124. semaphore_init ()
  125. {
  126. key_t semkey = JACK_SEMAPHORE_KEY;
  127. struct sembuf sbuf;
  128. int create_flags = IPC_CREAT | IPC_EXCL
  129. | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
  130. /* Get semaphore ID associated with this key. */
  131. if ((semid = semget(semkey, 0, 0)) == -1) {
  132. /* Semaphore does not exist - Create. */
  133. if ((semid = semget(semkey, 1, create_flags)) != -1) {
  134. /* Initialize the semaphore, allow one owner. */
  135. sbuf.sem_num = 0;
  136. sbuf.sem_op = 1;
  137. sbuf.sem_flg = 0;
  138. if (semop(semid, &sbuf, 1) == -1) {
  139. semaphore_error ("semop");
  140. }
  141. } else if (errno == EEXIST) {
  142. if ((semid = semget(semkey, 0, 0)) == -1) {
  143. semaphore_error ("semget");
  144. }
  145. } else {
  146. semaphore_error ("semget creation");
  147. }
  148. }
  149. }
  150. static inline void
  151. semaphore_add (int value)
  152. {
  153. struct sembuf sbuf;
  154. sbuf.sem_num = 0;
  155. sbuf.sem_op = value;
  156. sbuf.sem_flg = SEM_UNDO;
  157. if (semop(semid, &sbuf, 1) == -1) {
  158. semaphore_error ("semop");
  159. }
  160. }
  161. #endif
  162. static void
  163. jack_shm_lock_registry (void)
  164. {
  165. if (semid == -1)
  166. semaphore_init ();
  167. semaphore_add (-1);
  168. }
  169. static void
  170. jack_shm_unlock_registry (void)
  171. {
  172. semaphore_add (1);
  173. }
  174. static void
  175. jack_shm_init_registry ()
  176. {
  177. /* registry must be locked */
  178. int i;
  179. memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE);
  180. jack_shm_header->magic = JACK_SHM_MAGIC;
  181. //jack_shm_header->protocol = JACK_PROTOCOL_VERSION;
  182. jack_shm_header->type = jack_shmtype;
  183. jack_shm_header->size = JACK_SHM_REGISTRY_SIZE;
  184. jack_shm_header->hdr_len = sizeof (jack_shm_header_t);
  185. jack_shm_header->entry_len = sizeof (jack_shm_registry_t);
  186. for (i = 0; i < MAX_SHM_ID; ++i) {
  187. jack_shm_registry[i].index = i;
  188. }
  189. }
  190. static int
  191. jack_shm_validate_registry ()
  192. {
  193. /* registry must be locked */
  194. if ((jack_shm_header->magic == JACK_SHM_MAGIC)
  195. //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION)
  196. && (jack_shm_header->type == jack_shmtype)
  197. && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE)
  198. && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t))
  199. && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) {
  200. return 0; /* registry OK */
  201. }
  202. return -1;
  203. }
  204. /* set a unique per-user, per-server shm prefix string
  205. *
  206. * According to the POSIX standard:
  207. *
  208. * "The name argument conforms to the construction rules for a
  209. * pathname. If name begins with the slash character, then processes
  210. * calling shm_open() with the same value of name refer to the same
  211. * shared memory object, as long as that name has not been
  212. * removed. If name does not begin with the slash character, the
  213. * effect is implementation-defined. The interpretation of slash
  214. * characters other than the leading slash character in name is
  215. * implementation-defined."
  216. *
  217. * Since the Linux implementation does not allow slashes *within* the
  218. * name, in the interest of portability we use colons instead.
  219. */
  220. static void
  221. jack_set_server_prefix (const char *server_name)
  222. {
  223. #ifdef WIN32
  224. snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
  225. "jack-%d:%s:", _getpid (), server_name); // steph TO CHECK
  226. #else
  227. snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix),
  228. "/jack-%d:%s:", getuid (), server_name);
  229. #endif
  230. }
  231. /* gain server addressability to shared memory registration segment
  232. *
  233. * returns: 0 if successful
  234. */
  235. static int
  236. jack_server_initialize_shm (int new_registry)
  237. {
  238. int rc;
  239. if (jack_shm_header)
  240. return 0; /* already initialized */
  241. jack_shm_lock_registry ();
  242. rc = jack_access_registry (&registry_info);
  243. if (new_registry) {
  244. jack_remove_shm (&registry_id);
  245. rc = ENOENT;
  246. }
  247. switch (rc) {
  248. case ENOENT: /* registry does not exist */
  249. rc = jack_create_registry (&registry_info);
  250. break;
  251. case 0: /* existing registry */
  252. if (jack_shm_validate_registry () == 0)
  253. break;
  254. /* else it was invalid, so fall through */
  255. case EINVAL: /* bad registry */
  256. /* Apparently, this registry was created by an older
  257. * JACK version. Delete it so we can try again. */
  258. jack_release_shm (&registry_info);
  259. jack_remove_shm (&registry_id);
  260. if ((rc = jack_create_registry (&registry_info)) != 0) {
  261. jack_error ("incompatible shm registry (%s)",
  262. strerror (errno));
  263. #ifndef USE_POSIX_SHM
  264. jack_error ("to delete, use `ipcrm -M 0x%0.8x'",
  265. JACK_SHM_REGISTRY_KEY);
  266. #endif
  267. }
  268. break;
  269. default: /* failure return code */
  270. break;
  271. }
  272. jack_shm_unlock_registry ();
  273. return rc;
  274. }
  275. /* gain client addressability to shared memory registration segment
  276. *
  277. * NOTE: this function is no longer used for server initialization,
  278. * instead it calls jack_register_server().
  279. *
  280. * returns: 0 if successful
  281. */
  282. int
  283. jack_initialize_shm (const char *server_name)
  284. {
  285. int rc;
  286. if (jack_shm_header)
  287. return 0; /* already initialized */
  288. jack_set_server_prefix (server_name);
  289. jack_shm_lock_registry ();
  290. if ((rc = jack_access_registry (&registry_info)) == 0) {
  291. if ((rc = jack_shm_validate_registry ()) != 0) {
  292. jack_error ("Incompatible shm registry, "
  293. "are jackd and libjack in sync?");
  294. }
  295. }
  296. jack_shm_unlock_registry ();
  297. return rc;
  298. }
  299. // steph
  300. int jack_initialize_shm_server()
  301. {
  302. return jack_initialize_shm("default");
  303. }
  304. int jack_initialize_shm_client()
  305. {
  306. return jack_initialize_shm("default");
  307. }
  308. char* jack_shm_addr (jack_shm_info_t* si)
  309. {
  310. return (char*)si->attached_at;
  311. }
  312. void
  313. jack_destroy_shm (jack_shm_info_t* si)
  314. {
  315. /* must NOT have the registry locked */
  316. if (si->index == JACK_SHM_NULL_INDEX)
  317. return; /* segment not allocated */
  318. jack_remove_shm (&jack_shm_registry[si->index].id);
  319. jack_release_shm_info (si->index);
  320. }
  321. jack_shm_registry_t *
  322. jack_get_free_shm_info ()
  323. {
  324. /* registry must be locked */
  325. jack_shm_registry_t* si = NULL;
  326. int i;
  327. for (i = 0; i < MAX_SHM_ID; ++i) {
  328. if (jack_shm_registry[i].size == 0) {
  329. break;
  330. }
  331. }
  332. if (i < MAX_SHM_ID) {
  333. si = &jack_shm_registry[i];
  334. }
  335. return si;
  336. }
  337. static void
  338. jack_release_shm_entry (jack_shm_registry_index_t index)
  339. {
  340. /* the registry must be locked */
  341. jack_shm_registry[index].size = 0;
  342. jack_shm_registry[index].allocator = 0;
  343. memset (&jack_shm_registry[index].id, 0,
  344. sizeof (jack_shm_registry[index].id));
  345. }
  346. void
  347. jack_release_shm_info (jack_shm_registry_index_t index)
  348. {
  349. #ifdef WIN32
  350. int my_pid = _getpid();
  351. #else
  352. pid_t my_pid = getpid();
  353. #endif
  354. /* must NOT have the registry locked */
  355. if (jack_shm_registry[index].allocator == my_pid) {
  356. jack_shm_lock_registry ();
  357. jack_release_shm_entry (index);
  358. jack_shm_unlock_registry ();
  359. }
  360. }
  361. /* Claim server_name for this process.
  362. *
  363. * returns 0 if successful
  364. * EEXIST if server_name was already active for this user
  365. * ENOSPC if server registration limit reached
  366. * ENOMEM if unable to access shared memory registry
  367. */
  368. EXPORT int
  369. jack_register_server (const char *server_name, int new_registry)
  370. {
  371. int i, res = 0;
  372. #ifdef WIN32
  373. int my_pid = _getpid();
  374. #else
  375. pid_t my_pid = getpid();
  376. #endif
  377. jack_set_server_prefix (server_name);
  378. if (jack_server_initialize_shm (new_registry))
  379. return ENOMEM;
  380. jack_shm_lock_registry ();
  381. /* See if server_name already registered. Since server names
  382. * are per-user, we register the unique server prefix string.
  383. */
  384. for (i = 0; i < MAX_SERVERS; i++) {
  385. if (strncmp (jack_shm_header->server[i].name,
  386. jack_shm_server_prefix,
  387. JACK_SERVER_NAME_SIZE) != 0)
  388. continue; /* no match */
  389. if (jack_shm_header->server[i].pid == my_pid){
  390. res = 0; /* it's me */
  391. goto unlock;
  392. }
  393. /* see if server still exists */
  394. #ifndef WIN32 // steph TO CHECK
  395. if (kill (jack_shm_header->server[i].pid, 0) == 0) {
  396. res = EEXIST; /* other server running */
  397. goto unlock;
  398. }
  399. #endif
  400. /* it's gone, reclaim this entry */
  401. memset (&jack_shm_header->server[i], 0,
  402. sizeof (jack_shm_server_t));
  403. }
  404. /* find a free entry */
  405. for (i = 0; i < MAX_SERVERS; i++) {
  406. if (jack_shm_header->server[i].pid == 0)
  407. break;
  408. }
  409. if (i >= MAX_SERVERS){
  410. res = ENOSPC; /* out of space */
  411. goto unlock;
  412. }
  413. /* claim it */
  414. jack_shm_header->server[i].pid = my_pid;
  415. strncpy (jack_shm_header->server[i].name,
  416. jack_shm_server_prefix,
  417. JACK_SERVER_NAME_SIZE);
  418. unlock:
  419. jack_shm_unlock_registry ();
  420. return 0;
  421. }
  422. /* release server_name registration */
  423. EXPORT void
  424. jack_unregister_server (const char *server_name /* unused */)
  425. {
  426. int i;
  427. #ifdef WIN32
  428. int my_pid = _getpid();
  429. #else
  430. pid_t my_pid = getpid();
  431. #endif
  432. jack_shm_lock_registry ();
  433. for (i = 0; i < MAX_SERVERS; i++) {
  434. if (jack_shm_header->server[i].pid == my_pid) {
  435. memset (&jack_shm_header->server[i], 0,
  436. sizeof (jack_shm_server_t));
  437. }
  438. }
  439. jack_shm_unlock_registry ();
  440. }
  441. /* called for server startup and termination */
  442. EXPORT int
  443. jack_cleanup_shm ()
  444. {
  445. int i;
  446. int destroy;
  447. jack_shm_info_t copy;
  448. #ifdef WIN32
  449. int my_pid = _getpid();
  450. #else
  451. pid_t my_pid = getpid();
  452. #endif
  453. jack_shm_lock_registry ();
  454. for (i = 0; i < MAX_SHM_ID; i++) {
  455. jack_shm_registry_t* r;
  456. r = &jack_shm_registry[i];
  457. memcpy (&copy, r, sizeof (jack_shm_info_t));
  458. destroy = FALSE;
  459. /* ignore unused entries */
  460. if (r->allocator == 0)
  461. continue;
  462. /* is this my shm segment? */
  463. if (r->allocator == my_pid) {
  464. /* allocated by this process, so unattach
  465. and destroy. */
  466. jack_release_shm (&copy);
  467. destroy = TRUE;
  468. } else {
  469. /* see if allocator still exists */
  470. #ifdef WIN32 // steph
  471. printf("TODO: kill API not available !!\n");
  472. #else
  473. if (kill (r->allocator, 0)) {
  474. if (errno == ESRCH) {
  475. /* allocator no longer exists,
  476. * so destroy */
  477. destroy = TRUE;
  478. }
  479. }
  480. #endif
  481. }
  482. if (destroy) {
  483. int index = copy.index;
  484. if ((index >= 0) && (index < MAX_SHM_ID)) {
  485. jack_remove_shm (&jack_shm_registry[index].id);
  486. jack_release_shm_entry (index);
  487. }
  488. r->size = 0;
  489. r->allocator = 0;
  490. }
  491. }
  492. jack_shm_unlock_registry ();
  493. return TRUE;
  494. }
  495. /* resize a shared memory segment
  496. *
  497. * There is no way to resize a System V shm segment. Resizing is
  498. * possible with POSIX shm, but not with the non-conformant Mac OS X
  499. * implementation. Since POSIX shm is mainly used on that platform,
  500. * it's simpler to treat them both the same.
  501. *
  502. * So, we always resize by deleting and reallocating. This is
  503. * tricky, because the old segment will not disappear until
  504. * all the clients have released it. We only do what we can
  505. * from here.
  506. *
  507. * This is not done under a single lock. I don't even want to think
  508. * about all the things that could possibly go wrong if multple
  509. * processes tried to resize the same segment concurrently. That
  510. * probably doesn't happen.
  511. */
  512. int
  513. jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
  514. {
  515. jack_shm_id_t id;
  516. /* The underlying type of `id' differs for SYSV and POSIX */
  517. memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
  518. jack_release_shm (si);
  519. jack_destroy_shm (si);
  520. if (jack_shmalloc ((char *) id, size, si)) {
  521. return -1;
  522. }
  523. return jack_attach_shm (si);
  524. }
  525. #ifdef USE_POSIX_SHM
  526. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  527. * POSIX interface-dependent functions
  528. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  529. /* gain addressability to existing SHM registry segment
  530. *
  531. * sets up global registry pointers, if successful
  532. *
  533. * returns: 0 if existing registry accessed successfully
  534. * ENOENT if registry does not exist
  535. * EINVAL if registry exists, but has the wrong size
  536. */
  537. static int
  538. jack_access_registry (jack_shm_info_t *ri)
  539. {
  540. /* registry must be locked */
  541. int shm_fd;
  542. strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
  543. /* try to open an existing segment */
  544. if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
  545. int rc = errno;
  546. if (errno != ENOENT) {
  547. jack_error ("Cannot open existing shm registry segment"
  548. " (%s)", strerror (errno));
  549. }
  550. close (shm_fd);
  551. return rc;
  552. }
  553. if ((ri->attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
  554. PROT_READ|PROT_WRITE,
  555. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  556. jack_error ("Cannot mmap shm registry segment (%s)",
  557. strerror (errno));
  558. close (shm_fd);
  559. return EINVAL;
  560. }
  561. /* set up global pointers */
  562. ri->index = JACK_SHM_REGISTRY_INDEX;
  563. jack_shm_header = ri->attached_at;
  564. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  565. close (shm_fd); // steph
  566. return 0;
  567. }
  568. /* create a new SHM registry segment
  569. *
  570. * sets up global registry pointers, if successful
  571. *
  572. * returns: 0 if registry created successfully
  573. * nonzero error code if unable to allocate a new registry
  574. */
  575. static int
  576. jack_create_registry (jack_shm_info_t *ri)
  577. {
  578. /* registry must be locked */
  579. int shm_fd;
  580. strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
  581. if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
  582. int rc = errno;
  583. jack_error ("Cannot create shm registry segment (%s)",
  584. strerror (errno));
  585. return rc;
  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), "/jackmp-%d", 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", 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 */