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.

1214 lines
30KB

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