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.

1174 lines
29KB

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