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.

1215 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 int
  129. semaphore_init () {return 0;}
  130. static int
  131. semaphore_add (int value) {return 0;}
  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. int
  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. return 0;
  453. }
  454. /* called for server startup and termination */
  455. int
  456. jack_cleanup_shm ()
  457. {
  458. int i;
  459. int destroy;
  460. jack_shm_info_t copy;
  461. if (jack_shm_lock_registry () < 0) {
  462. jack_error ("jack_shm_lock_registry fails...");
  463. return -1;
  464. }
  465. for (i = 0; i < MAX_SHM_ID; i++) {
  466. jack_shm_registry_t* r;
  467. r = &jack_shm_registry[i];
  468. memcpy (&copy, r, sizeof (jack_shm_info_t));
  469. destroy = FALSE;
  470. /* ignore unused entries */
  471. if (r->allocator == 0)
  472. continue;
  473. /* is this my shm segment? */
  474. if (r->allocator == GetPID()) {
  475. /* allocated by this process, so unattach
  476. and destroy. */
  477. jack_release_shm (&copy);
  478. destroy = TRUE;
  479. } else {
  480. /* see if allocator still exists */
  481. #ifdef WIN32 // steph
  482. jack_info("TODO: kill API not available !!");
  483. #else
  484. if (kill (r->allocator, 0)) {
  485. if (errno == ESRCH) {
  486. /* allocator no longer exists,
  487. * so destroy */
  488. destroy = TRUE;
  489. }
  490. }
  491. #endif
  492. }
  493. if (destroy) {
  494. int index = copy.index;
  495. if ((index >= 0) && (index < MAX_SHM_ID)) {
  496. jack_remove_shm (&jack_shm_registry[index].id);
  497. jack_release_shm_entry (index);
  498. }
  499. r->size = 0;
  500. r->allocator = 0;
  501. }
  502. }
  503. jack_shm_unlock_registry ();
  504. return TRUE;
  505. }
  506. /* resize a shared memory segment
  507. *
  508. * There is no way to resize a System V shm segment. Resizing is
  509. * possible with POSIX shm, but not with the non-conformant Mac OS X
  510. * implementation. Since POSIX shm is mainly used on that platform,
  511. * it's simpler to treat them both the same.
  512. *
  513. * So, we always resize by deleting and reallocating. This is
  514. * tricky, because the old segment will not disappear until
  515. * all the clients have released it. We only do what we can
  516. * from here.
  517. *
  518. * This is not done under a single lock. I don't even want to think
  519. * about all the things that could possibly go wrong if multple
  520. * processes tried to resize the same segment concurrently. That
  521. * probably doesn't happen.
  522. */
  523. int
  524. jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size)
  525. {
  526. jack_shm_id_t id;
  527. /* The underlying type of `id' differs for SYSV and POSIX */
  528. memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id));
  529. jack_release_shm (si);
  530. jack_destroy_shm (si);
  531. if (jack_shmalloc ((char *) id, size, si)) {
  532. return -1;
  533. }
  534. return jack_attach_shm (si);
  535. }
  536. #ifdef USE_POSIX_SHM
  537. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  538. * POSIX interface-dependent functions
  539. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  540. /* gain addressability to existing SHM registry segment
  541. *
  542. * sets up global registry pointers, if successful
  543. *
  544. * returns: 0 if existing registry accessed successfully
  545. * ENOENT if registry does not exist
  546. * EINVAL if registry exists, but has the wrong size
  547. */
  548. static int
  549. jack_access_registry (jack_shm_info_t *ri)
  550. {
  551. /* registry must be locked */
  552. int shm_fd;
  553. strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
  554. /* try to open an existing segment */
  555. if ((shm_fd = shm_open (registry_id, O_RDWR, 0666)) < 0) {
  556. int rc = errno;
  557. if (errno != ENOENT) {
  558. jack_error ("Cannot open existing shm registry segment"
  559. " (%s)", strerror (errno));
  560. }
  561. close (shm_fd);
  562. return rc;
  563. }
  564. if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
  565. PROT_READ|PROT_WRITE,
  566. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  567. jack_error ("Cannot mmap shm registry segment (%s)",
  568. strerror (errno));
  569. close (shm_fd);
  570. return EINVAL;
  571. }
  572. /* set up global pointers */
  573. ri->index = JACK_SHM_REGISTRY_INDEX;
  574. jack_shm_header = ri->ptr.attached_at;
  575. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  576. close (shm_fd); // steph
  577. return 0;
  578. }
  579. /* create a new SHM registry segment
  580. *
  581. * sets up global registry pointers, if successful
  582. *
  583. * returns: 0 if registry created successfully
  584. * nonzero error code if unable to allocate a new registry
  585. */
  586. static int
  587. jack_create_registry (jack_shm_info_t *ri)
  588. {
  589. /* registry must be locked */
  590. int shm_fd;
  591. strncpy (registry_id, "/jack-shm-registry", sizeof (registry_id));
  592. if ((shm_fd = shm_open (registry_id, O_RDWR|O_CREAT, 0666)) < 0) {
  593. int rc = errno;
  594. jack_error ("Cannot create shm registry segment (%s)",
  595. strerror (errno));
  596. return rc;
  597. }
  598. /* Previous shm_open result depends of the actual value of umask, force correct file permisssion here */
  599. if (fchmod(shm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0) {
  600. jack_log("Cannot chmod jack-shm-registry (%s) %d %d", strerror (errno));
  601. }
  602. /* Set the desired segment size. NOTE: the non-conformant Mac
  603. * OS X POSIX shm only allows ftruncate() on segment creation.
  604. */
  605. if (ftruncate (shm_fd, JACK_SHM_REGISTRY_SIZE) < 0) {
  606. int rc = errno;
  607. jack_error ("Cannot set registry size (%s)", strerror (errno));
  608. jack_remove_shm (&registry_id);
  609. close (shm_fd);
  610. return rc;
  611. }
  612. if ((ri->ptr.attached_at = mmap (0, JACK_SHM_REGISTRY_SIZE,
  613. PROT_READ|PROT_WRITE,
  614. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  615. jack_error ("Cannot mmap shm registry segment (%s)",
  616. strerror (errno));
  617. jack_remove_shm (&registry_id);
  618. close (shm_fd);
  619. return EINVAL;
  620. }
  621. /* set up global pointers */
  622. ri->index = JACK_SHM_REGISTRY_INDEX;
  623. jack_shm_header = ri->ptr.attached_at;
  624. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  625. /* initialize registry contents */
  626. jack_shm_init_registry ();
  627. close (shm_fd); // steph
  628. return 0;
  629. }
  630. static void
  631. jack_remove_shm (jack_shm_id_t *id)
  632. {
  633. /* registry may or may not be locked */
  634. shm_unlink ((char *) id);
  635. }
  636. void
  637. jack_release_shm (jack_shm_info_t* si)
  638. {
  639. /* registry may or may not be locked */
  640. if (si->ptr.attached_at != MAP_FAILED) {
  641. munmap (si->ptr.attached_at, jack_shm_registry[si->index].size);
  642. }
  643. }
  644. /* allocate a POSIX shared memory segment */
  645. int
  646. jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
  647. {
  648. jack_shm_registry_t* registry;
  649. int shm_fd;
  650. int rc = -1;
  651. char name[SHM_NAME_MAX+1];
  652. if (jack_shm_lock_registry () < 0) {
  653. jack_error ("jack_shm_lock_registry fails...");
  654. return -1;
  655. }
  656. if ((registry = jack_get_free_shm_info ()) == NULL) {
  657. jack_error ("shm registry full");
  658. goto unlock;
  659. }
  660. /* On Mac OS X, the maximum length of a shared memory segment
  661. * name is SHM_NAME_MAX (instead of NAME_MAX or PATH_MAX as
  662. * defined by the standard). Unfortunately, Apple sets this
  663. * value so small (about 31 bytes) that it is useless for
  664. * actual names. So, we construct a short name from the
  665. * registry index for uniqueness and ignore the shm_name
  666. * parameter. Bah!
  667. */
  668. snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index);
  669. if (strlen (name) >= sizeof (registry->id)) {
  670. jack_error ("shm segment name too long %s", name);
  671. goto unlock;
  672. }
  673. if ((shm_fd = shm_open (name, O_RDWR|O_CREAT, 0666)) < 0) {
  674. jack_error ("Cannot create shm segment %s (%s)",
  675. name, strerror (errno));
  676. goto unlock;
  677. }
  678. if (ftruncate (shm_fd, size) < 0) {
  679. jack_error ("Cannot set size of engine shm "
  680. "registry 0 (%s)",
  681. strerror (errno));
  682. close (shm_fd);
  683. goto unlock;
  684. }
  685. close (shm_fd);
  686. registry->size = size;
  687. strncpy (registry->id, name, sizeof (registry->id));
  688. registry->allocator = GetPID();
  689. si->index = registry->index;
  690. si->ptr.attached_at = MAP_FAILED; /* not attached */
  691. rc = 0; /* success */
  692. unlock:
  693. jack_shm_unlock_registry ();
  694. return rc;
  695. }
  696. int
  697. jack_attach_shm (jack_shm_info_t* si)
  698. {
  699. int shm_fd;
  700. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  701. if ((shm_fd = shm_open (registry->id,
  702. O_RDWR, 0666)) < 0) {
  703. jack_error ("Cannot open shm segment %s (%s)", registry->id,
  704. strerror (errno));
  705. return -1;
  706. }
  707. if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE,
  708. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  709. jack_error ("Cannot mmap shm segment %s (%s)",
  710. registry->id,
  711. strerror (errno));
  712. close (shm_fd);
  713. return -1;
  714. }
  715. close (shm_fd);
  716. return 0;
  717. }
  718. int
  719. jack_attach_shm_read (jack_shm_info_t* si)
  720. {
  721. int shm_fd;
  722. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  723. if ((shm_fd = shm_open (registry->id,
  724. O_RDONLY, 0666)) < 0) {
  725. jack_error ("Cannot open shm segment %s (%s)", registry->id,
  726. strerror (errno));
  727. return -1;
  728. }
  729. if ((si->ptr.attached_at = mmap (0, registry->size, PROT_READ,
  730. MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
  731. jack_error ("Cannot mmap shm segment %s (%s)",
  732. registry->id,
  733. strerror (errno));
  734. close (shm_fd);
  735. return -1;
  736. }
  737. close (shm_fd);
  738. return 0;
  739. }
  740. #elif WIN32
  741. static int
  742. jack_access_registry (jack_shm_info_t *ri)
  743. {
  744. /* registry must be locked */
  745. HANDLE shm_fd;
  746. strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
  747. /* try to open an existing segment */
  748. if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry_id)) == NULL) {
  749. int rc = GetLastError();
  750. if (rc != ERROR_FILE_NOT_FOUND) {
  751. jack_error ("Cannot open existing shm registry segment (%ld)", rc);
  752. }
  753. return rc;
  754. }
  755. if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
  756. jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
  757. jack_remove_shm (&registry_id);
  758. CloseHandle (shm_fd);
  759. return EINVAL;
  760. }
  761. /* set up global pointers */
  762. ri->index = JACK_SHM_REGISTRY_INDEX;
  763. jack_shm_header = ri->ptr.attached_at;
  764. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  765. //CloseHandle(shm_fd); // TO CHECK
  766. return 0;
  767. }
  768. static int
  769. jack_create_registry (jack_shm_info_t *ri)
  770. {
  771. /* registry must be locked */
  772. HANDLE shm_fd;
  773. strncpy (registry_id, "jack-shm-registry", sizeof (registry_id));
  774. if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
  775. 0, PAGE_READWRITE,
  776. 0, JACK_SHM_REGISTRY_SIZE,
  777. registry_id)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
  778. int rc = GetLastError();
  779. jack_error ("Cannot create shm registry segment (%ld)", rc);
  780. return rc;
  781. }
  782. if ((ri->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, JACK_SHM_REGISTRY_SIZE)) == NULL) {
  783. jack_error ("Cannot mmap shm registry segment (%ld)", GetLastError());
  784. jack_remove_shm (&registry_id);
  785. CloseHandle (shm_fd);
  786. return EINVAL;
  787. }
  788. /* set up global pointers */
  789. ri->index = JACK_SHM_REGISTRY_INDEX;
  790. jack_shm_header = ri->ptr.attached_at;
  791. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  792. /* initialize registry contents */
  793. jack_shm_init_registry ();
  794. //CloseHandle(shm_fd); // TO CHECK
  795. return 0;
  796. }
  797. static void
  798. jack_remove_shm (jack_shm_id_t *id)
  799. {
  800. /* nothing to do */
  801. }
  802. void
  803. jack_release_shm (jack_shm_info_t* si)
  804. {
  805. /* registry may or may not be locked */
  806. if (si->ptr.attached_at != NULL) {
  807. UnmapViewOfFile (si->ptr.attached_at);
  808. }
  809. }
  810. int
  811. jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si)
  812. {
  813. jack_shm_registry_t* registry;
  814. HANDLE shm_fd;
  815. int rc = -1;
  816. char name[SHM_NAME_MAX+1];
  817. if (jack_shm_lock_registry () < 0) {
  818. jack_error ("jack_shm_lock_registry fails...");
  819. return -1;
  820. }
  821. if ((registry = jack_get_free_shm_info ()) == NULL) {
  822. jack_error ("shm registry full");
  823. goto unlock;
  824. }
  825. snprintf (name, sizeof (name), "jack-%d-%d", GetUID(), registry->index);
  826. if (strlen (name) >= sizeof (registry->id)) {
  827. jack_error ("shm segment name too long %s", name);
  828. goto unlock;
  829. }
  830. if ((shm_fd = CreateFileMapping(INVALID_HANDLE_VALUE,
  831. 0, PAGE_READWRITE,
  832. 0, size,
  833. name)) == NULL || (shm_fd == INVALID_HANDLE_VALUE)) {
  834. int rc = GetLastError();
  835. jack_error ("Cannot create shm segment (%ld)",rc);
  836. goto unlock;
  837. }
  838. //CloseHandle (shm_fd); // TO CHECK
  839. registry->size = size;
  840. strncpy (registry->id, name, sizeof (registry->id));
  841. registry->allocator = _getpid();
  842. si->index = registry->index;
  843. si->ptr.attached_at = NULL; /* not attached */
  844. rc = 0; /* success */
  845. unlock:
  846. jack_shm_unlock_registry ();
  847. return rc;
  848. }
  849. int
  850. jack_attach_shm (jack_shm_info_t* si)
  851. {
  852. HANDLE shm_fd;
  853. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  854. if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
  855. int rc = GetLastError();
  856. jack_error ("Cannot open shm segment (%ld)",rc);
  857. return -1;
  858. }
  859. if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_ALL_ACCESS, 0, 0, registry->size)) == NULL) {
  860. jack_error ("Cannot mmap shm segment (%ld)", GetLastError());
  861. jack_remove_shm (&registry_id);
  862. CloseHandle (shm_fd);
  863. return -1;
  864. }
  865. //CloseHandle (shm_fd); // TO CHECK
  866. return 0;
  867. }
  868. int
  869. jack_attach_shm_read (jack_shm_info_t* si)
  870. {
  871. HANDLE shm_fd;
  872. jack_shm_registry_t *registry = &jack_shm_registry[si->index];
  873. if ((shm_fd = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, registry->id)) == NULL) {
  874. int rc = GetLastError();
  875. jack_error ("Cannot open shm segment (%ld)",rc);
  876. return -1;
  877. }
  878. if ((si->ptr.attached_at = MapViewOfFile (shm_fd, FILE_MAP_READ, 0, 0, registry->size)) == NULL) {
  879. jack_error("Cannot mmap shm segment (%ld)", GetLastError());
  880. jack_remove_shm(&registry_id);
  881. CloseHandle(shm_fd);
  882. return -1;
  883. }
  884. //CloseHandle (shm_fd); // TO CHECK
  885. return 0;
  886. }
  887. #else
  888. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  889. * System V interface-dependent functions
  890. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  891. /* gain addressability to existing SHM registry segment
  892. *
  893. * sets up global registry pointers, if successful
  894. *
  895. * returns: 0 if existing registry accessed successfully
  896. * ENOENT if registry does not exist
  897. * EINVAL if registry exists, but has the wrong size
  898. * other nonzero error code if unable to access registry
  899. */
  900. static int
  901. jack_access_registry (jack_shm_info_t *ri)
  902. {
  903. /* registry must be locked */
  904. /* try without IPC_CREAT to get existing segment */
  905. if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
  906. JACK_SHM_REGISTRY_SIZE, 0666)) < 0) {
  907. switch (errno) {
  908. case ENOENT: /* segment does not exist */
  909. return ENOENT;
  910. case EINVAL: /* segment exists, but too small */
  911. /* attempt minimum size access */
  912. registry_id = shmget (JACK_SHM_REGISTRY_KEY, 1, 0666);
  913. return EINVAL;
  914. default: /* or other error */
  915. jack_error ("unable to access shm registry (%s)",
  916. strerror (errno));
  917. return errno;
  918. }
  919. }
  920. if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
  921. jack_error ("Cannot attach shm registry segment (%s)",
  922. strerror (errno));
  923. return EINVAL;
  924. }
  925. /* set up global pointers */
  926. ri->index = JACK_SHM_REGISTRY_INDEX;
  927. jack_shm_header = ri->attached_at;
  928. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  929. return 0;
  930. }
  931. /* create a new SHM registry segment
  932. *
  933. * sets up global registry pointers, if successful
  934. *
  935. * returns: 0 if registry created successfully
  936. * nonzero error code if unable to allocate a new registry
  937. */
  938. static int
  939. jack_create_registry (jack_shm_info_t *ri)
  940. {
  941. /* registry must be locked */
  942. if ((registry_id = shmget (JACK_SHM_REGISTRY_KEY,
  943. JACK_SHM_REGISTRY_SIZE,
  944. 0666|IPC_CREAT)) < 0) {
  945. jack_error ("Cannot create shm registry segment (%s)",
  946. strerror (errno));
  947. return errno;
  948. }
  949. if ((ri->attached_at = shmat (registry_id, 0, 0)) < 0) {
  950. jack_error ("Cannot attach shm registry segment (%s)",
  951. strerror (errno));
  952. return EINVAL;
  953. }
  954. /* set up global pointers */
  955. ri->index = JACK_SHM_REGISTRY_INDEX;
  956. jack_shm_header = ri->attached_at;
  957. jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1);
  958. /* initialize registry contents */
  959. jack_shm_init_registry ();
  960. return 0;
  961. }
  962. static void
  963. jack_remove_shm (jack_shm_id_t *id)
  964. {
  965. /* registry may or may not be locked */
  966. shmctl (*id, IPC_RMID, NULL);
  967. }
  968. void
  969. jack_release_shm (jack_shm_info_t* si)
  970. {
  971. /* registry may or may not be locked */
  972. if (si->attached_at != MAP_FAILED) {
  973. shmdt (si->attached_at);
  974. }
  975. }
  976. int
  977. jack_shmalloc (const char* name_not_used, jack_shmsize_t size,
  978. jack_shm_info_t* si)
  979. {
  980. int shmflags;
  981. int shmid;
  982. int rc = -1;
  983. jack_shm_registry_t* registry;
  984. if (jack_shm_lock_registry () < 0) {
  985. jack_error ("jack_shm_lock_registry fails...");
  986. return -1;
  987. }
  988. if ((registry = jack_get_free_shm_info ())) {
  989. shmflags = 0666 | IPC_CREAT | IPC_EXCL;
  990. if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) >= 0) {
  991. registry->size = size;
  992. registry->id = shmid;
  993. registry->allocator = getpid();
  994. si->index = registry->index;
  995. si->attached_at = MAP_FAILED; /* not attached */
  996. rc = 0;
  997. } else {
  998. jack_error ("Cannot create shm segment %s (%s)",
  999. name_not_used, strerror (errno));
  1000. }
  1001. }
  1002. jack_shm_unlock_registry ();
  1003. return rc;
  1004. }
  1005. int
  1006. jack_attach_shm (jack_shm_info_t* si)
  1007. {
  1008. if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) {
  1009. jack_error ("Cannot attach shm segment (%s)",
  1010. strerror (errno));
  1011. jack_release_shm_info (si->index);
  1012. return -1;
  1013. }
  1014. return 0;
  1015. }
  1016. #endif /* !USE_POSIX_SHM */