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.

1175 lines
28KB

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