jack1 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.

901 lines
22KB

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