~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
JACK/libjack/shm.c


** Warning: Cannot open xref database.

1 /* 2 Copyright (C) 2003 Paul Davis 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software 16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 18 $Id: shm.c,v 1.12 2003/11/07 05:45:03 joq Exp $ 19 */ 20 21 #include <unistd.h> 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <signal.h> 26 #include <limits.h> 27 #include <errno.h> 28 #include <sys/mman.h> 29 #include <sys/types.h> 30 #include <dirent.h> 31 #include <sys/ipc.h> 32 #include <sys/shm.h> 33 #include <config.h> 34 35 #include <jack/shm.h> 36 #include <jack/internal.h> 37 38 static jack_shm_registry_t* jack_shm_registry; 39 40 static void 41 jack_shm_lock_registry () 42 { 43 /* XXX magic with semaphores here */ 44 } 45 46 static void 47 jack_shm_unlock_registry () 48 { 49 /* XXX magic with semaphores here */ 50 } 51 52 jack_shm_registry_t * 53 jack_get_free_shm_info () 54 { 55 jack_shm_registry_t* si = NULL; 56 int i; 57 58 jack_shm_lock_registry (); 59 60 for (i = 0; i < MAX_SHM_ID; ++i) { 61 if (jack_shm_registry[i].size == 0) { 62 break; 63 } 64 } 65 66 if (i < MAX_SHM_ID) { 67 si = &jack_shm_registry[i]; 68 } 69 70 jack_shm_unlock_registry (); 71 72 return si; 73 } 74 75 void 76 jack_release_shm_info (jack_shm_registry_index_t index) 77 { 78 if (jack_shm_registry[index].allocator == getpid()) { 79 jack_shm_lock_registry (); 80 jack_shm_registry[index].size = 0; 81 jack_shm_registry[index].allocator = 0; 82 jack_shm_unlock_registry (); 83 } 84 } 85 86 void 87 jack_cleanup_shm () 88 { 89 int i; 90 int destroy; 91 jack_shm_info_t copy; 92 93 jack_initialize_shm (); 94 jack_shm_lock_registry (); 95 96 for (i = 0; i < MAX_SHM_ID; i++) { 97 jack_shm_registry_t* r; 98 99 r = &jack_shm_registry[i]; 100 copy.index = r->index; 101 destroy = FALSE; 102 103 if (r->allocator == getpid()) { 104 105 /* allocated by this process, so unattach 106 and destroy. 107 */ 108 109 jack_release_shm (&copy); 110 destroy = TRUE; 111 112 } else { 113 114 if (kill (r->allocator, 0)) { 115 if (errno == ESRCH) { 116 117 /* allocator no longer exists, so destroy */ 118 119 destroy = TRUE; 120 } 121 } 122 } 123 124 if (destroy) { 125 126 jack_destroy_shm (&copy); 127 128 r->size = 0; 129 r->allocator = 0; 130 } 131 } 132 133 jack_shm_unlock_registry (); 134 } 135 136 #if USE_POSIX_SHM 137 138 int 139 jack_initialize_shm () 140 { 141 int shm_fd; 142 jack_shmsize_t size; 143 int new_registry = FALSE; 144 int ret = -1; 145 146 if (jack_shm_registry != NULL) { 147 return 0; 148 } 149 150 /* grab a chunk of memory to store shm ids in. this is 151 to allow clean up of all segments whenever JACK 152 starts (or stops). 153 */ 154 155 size = sizeof (jack_shm_registry_t) * MAX_SHM_ID; 156 157 jack_shm_lock_registry (); 158 159 /* try without O_CREAT to see if it already exists */ 160 161 if ((shm_fd = shm_open ("/jack-shm-registry", O_RDWR, 0666)) < 0) { 162 163 if (errno == ENOENT) { 164 165 /* it doesn't exist, so create it */ 166 167 if ((shm_fd = shm_open ("/jack-shm-registry", O_RDWR|O_CREAT, 0666)) < 0) { 168 jack_error ("cannot create shm registry segment (%s)", 169 strerror (errno)); 170 goto out; 171 } 172 new_registry = TRUE; 173 174 } else { 175 176 jack_error ("cannot open existing shm registry segment (%s)", 177 strerror (errno)); 178 goto out; 179 } 180 } 181 182 if (ftruncate (shm_fd, size) < 0) { 183 jack_error ("cannot set size of engine shm registry " 184 "(%s)", strerror (errno)); 185 goto out; 186 } 187 188 if ((jack_shm_registry = mmap (0, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { 189 jack_error ("cannot mmap shm registry segment (%s)", 190 strerror (errno)); 191 goto out; 192 } 193 194 if (new_registry) { 195 int i; 196 197 memset (jack_shm_registry, 0, size); 198 for (i = 0; i < MAX_SHM_ID; ++i) { 199 jack_shm_registry[i].index = i; 200 } 201 fprintf (stderr, "JACK compiled with POSIX SHM support\n"); 202 } 203 204 ret = 0; 205 206 out: 207 close (shm_fd); 208 jack_shm_unlock_registry (); 209 return ret; 210 } 211 212 void 213 jack_destroy_shm (jack_shm_info_t* si) 214 { 215 shm_unlink (jack_shm_registry[si->index].id); 216 jack_release_shm_info (si->index); 217 } 218 219 void 220 jack_release_shm (jack_shm_info_t* si) 221 { 222 if (si->attached_at != MAP_FAILED) { 223 munmap (si->attached_at, jack_shm_registry[si->index].size); 224 } 225 } 226 227 int 228 jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) 229 { 230 jack_shm_registry_t* registry; 231 int shm_fd; 232 233 if ((registry = jack_get_free_shm_info ()) == NULL) { 234 return -1; 235 } 236 237 if ((shm_fd = shm_open (shm_name, O_RDWR|O_CREAT, 0666)) < 0) { 238 jack_error ("cannot create shm segment %s (%s)", shm_name, 239 strerror (errno)); 240 return -1; 241 } 242 243 if (ftruncate (shm_fd, size) < 0) { 244 jack_error ("cannot set size of engine shm registry " 245 "(%s)", strerror (errno)); 246 return -1; 247 } 248 249 close (shm_fd); 250 251 registry->size = size; 252 snprintf (registry->id, sizeof (registry->id), "%s", shm_name); 253 registry->allocator = getpid(); 254 255 si->index = registry->index; 256 si->attached_at = MAP_FAILED; /* segment not attached */ 257 258 return 0; 259 } 260 261 int 262 jack_attach_shm (jack_shm_info_t* si) 263 { 264 int shm_fd; 265 jack_shm_registry_t *registry = &jack_shm_registry[si->index]; 266 267 if ((shm_fd = shm_open (registry->id, 268 O_RDWR, 0666)) < 0) { 269 jack_error ("cannot open shm segment %s (%s)", registry->id, 270 strerror (errno)); 271 return -1; 272 } 273 274 if ((si->attached_at = mmap (0, registry->size, PROT_READ|PROT_WRITE, 275 MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { 276 jack_error ("cannot mmap shm segment %s (%s)", 277 registry->id, 278 strerror (errno)); 279 close (shm_fd); 280 return -1; 281 } 282 283 close (shm_fd); 284 285 return 0; 286 } 287 288 int 289 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size) 290 { 291 int shm_fd; 292 jack_shm_registry_t *registry = &jack_shm_registry[si->index]; 293 294 if ((shm_fd = shm_open (registry->id, O_RDWR, 0666)) < 0) { 295 jack_error ("cannot create shm segment %s (%s)", registry->id, 296 strerror (errno)); 297 return -1; 298 } 299 300 munmap (si->attached_at, registry->size); 301 302 if (ftruncate (shm_fd, size) < 0) { 303 jack_error ("cannot set size of shm segment %s " 304 "(%s)", registry->id, strerror (errno)); 305 return -1; 306 } 307 308 if ((si->attached_at = mmap (0, size, PROT_READ|PROT_WRITE, 309 MAP_SHARED, shm_fd, 0)) 310 == MAP_FAILED) { 311 jack_error ("cannot mmap shm segment %s (%s)", registry->id, 312 strerror (errno)); 313 close (shm_fd); 314 return -1; 315 } 316 317 close (shm_fd); 318 return 0; 319 } 320 321 #else /* USE_POSIX_SHM */ 322 323 #define JACK_SHM_REGISTRY_KEY 0x282929 324 325 int 326 jack_initialize_shm () 327 { 328 int shmflags; 329 int shmid; 330 key_t key; 331 jack_shmsize_t size; 332 int new_registry = FALSE; 333 int ret = -1; 334 335 if (jack_shm_registry != NULL) { 336 return 0; 337 } 338 339 /* grab a chunk of memory to store shm ids in. this is 340 to allow our parent to clean up all such ids when 341 if we exit. otherwise, they can get lost in crash 342 or debugger driven exits. 343 */ 344 345 shmflags = 0666; 346 key = JACK_SHM_REGISTRY_KEY; 347 size = sizeof (jack_shm_registry_t) * MAX_SHM_ID; 348 349 jack_shm_lock_registry (); 350 351 /* try without IPC_CREAT to check if it already exists */ 352 353 if ((shmid = shmget (key, size, shmflags)) < 0) { 354 if (errno == ENOENT) { 355 if ((shmid = shmget (key, size, shmflags|IPC_CREAT)) < 0) { 356 jack_error ("cannot create shm registry segment (%s)", 357 strerror (errno)); 358 goto out; 359 } 360 361 new_registry = TRUE; 362 363 } else { 364 365 jack_error ("cannot use existing shm registry segment (%s)", 366 strerror (errno)); 367 goto out; 368 } 369 } 370 371 if ((jack_shm_registry = shmat (shmid, 0, 0)) < 0) { 372 jack_error ("cannot attach shm registry segment (%s)", 373 strerror (errno)); 374 goto out; 375 } 376 377 if (new_registry) { 378 int i; 379 memset (jack_shm_registry, 0, size); 380 for (i = 0; i < MAX_SHM_ID; ++i) { 381 jack_shm_registry[i].index = i; 382 } 383 fprintf (stderr, "JACK compiled with System V SHM support\n"); 384 } 385 386 ret = 0; 387 388 out: 389 jack_shm_unlock_registry (); 390 return ret; 391 } 392 393 void 394 jack_destroy_shm (jack_shm_info_t* si) 395 { 396 shmctl (jack_shm_registry[si->index].id, IPC_RMID, NULL); 397 jack_release_shm_info (si->index); 398 } 399 400 void 401 jack_release_shm (jack_shm_info_t* si) 402 { 403 if (si->attached_at != MAP_FAILED) { 404 shmdt (si->attached_at); 405 } 406 } 407 408 int 409 jack_shmalloc (const char* name_not_used, jack_shmsize_t size, jack_shm_info_t* si) 410 { 411 int shmflags; 412 int shmid; 413 jack_shm_registry_t* registry; 414 415 if ((registry = jack_get_free_shm_info ()) == NULL) { 416 return -1; 417 } 418 419 shmflags = 0666 | IPC_CREAT | IPC_EXCL; 420 421 if ((shmid = shmget (IPC_PRIVATE, size, shmflags)) < 0) { 422 jack_error ("cannot create shm segment %s (%s)", 423 name_not_used, strerror (errno)); 424 return -1; 425 } 426 427 registry->size = size; 428 registry->id = shmid; 429 registry->allocator = getpid(); 430 431 si->index = registry->index; 432 si->attached_at = MAP_FAILED; /* segment not attached */ 433 434 return 0; 435 } 436 437 int 438 jack_attach_shm (jack_shm_info_t* si) 439 { 440 if ((si->attached_at = shmat (jack_shm_registry[si->index].id, 0, 0)) < 0) { 441 jack_error ("cannot attach shm segment (%s)", 442 strerror (errno)); 443 jack_release_shm_info (si->index); 444 return -1; 445 } 446 return 0; 447 } 448 449 int 450 jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size) 451 { 452 /* There is no way to resize a System V shm segment. So, we 453 * delete it and allocate a new one. This is tricky, because 454 * the old segment will not disappear until all the clients 455 * have released it. We can only do what we can from here. 456 */ 457 458 jack_release_shm (si); 459 jack_destroy_shm (si); 460 461 if (jack_shmalloc ("not used", size, si)) { 462 return -1; 463 } 464 465 return jack_attach_shm (si); 466 } 467 468 #endif /* !USE_POSIX_SHM */ 469

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.