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.

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