2 // Copyright 2005 The Android Open Source Project
4 // Shared memory interface.
9 #if defined(HAVE_MACOSX_IPC) || defined(HAVE_ANDROID_IPC)
10 # include <sys/mman.h>
13 #elif defined(HAVE_SYSV_IPC)
14 # include <sys/types.h>
17 #elif defined(HAVE_WIN32_IPC)
20 # error "unknown shm config"
26 using namespace android;
29 #if defined(HAVE_MACOSX_IPC) || defined(HAVE_ANDROID_IPC)
32 * SysV IPC under Mac OS X seems to have problems. It works fine on
33 * some machines but totally fails on others. We're working around it
34 * here by using mmap().
37 #define kInvalidHandle ((unsigned long)-1)
39 static const char* kShmemFile = "/tmp/android-";
42 * Constructor. Just set up the fields.
45 : mHandle(kInvalidHandle), mAddr(MAP_FAILED), mLength(-1), mCreator(false),
51 * Destructor. Detach and, if we created it, mark the segment for
56 if (mAddr != MAP_FAILED)
57 munmap(mAddr, mLength);
58 if ((long)mHandle >= 0) {
65 snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, mKey);
68 LOG(LOG_WARN, "shmem", "Couldn't clean up '%s'\n", nameBuf);
76 * Create the segment and attach ourselves to it.
78 bool Shmem::create(int key, long size, bool deleteExisting)
83 snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, key);
87 if (cc != 0 && errno != ENOENT) {
88 LOG(LOG_ERROR, "shmem", "Failed to remove old map file '%s'\n",
94 fd = open(nameBuf, O_CREAT|O_EXCL|O_RDWR, 0600);
96 LOG(LOG_ERROR, "shmem", "Unable to create map file '%s' (errno=%d)\n",
102 * Set the file size by seeking and writing.
104 if (ftruncate(fd, size) == -1) {
105 LOG(LOG_ERROR, "shmem", "Unable to set file size in '%s' (errno=%d)\n",
111 mAddr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
112 if (mAddr == MAP_FAILED) {
113 LOG(LOG_ERROR, "shmem", "mmap failed (errno=%d)\n", errno);
123 /* done with shmem, create the associated semaphore */
124 if (!mSem.create(key, 1, true)) {
125 LOG(LOG_ERROR, "shmem",
126 "Failed creating semaphore for Shmem (key=%d)\n", key);
134 * Attach ourselves to an existing segment.
136 bool Shmem::attach(int key)
141 snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, key);
142 fd = open(nameBuf, O_RDWR, 0600);
144 LOG(LOG_ERROR, "shmem", "Unable to open map file '%s' (errno=%d)\n",
150 len = lseek(fd, 0, SEEK_END);
151 if (len == (off_t) -1) {
152 LOG(LOG_ERROR, "shmem",
153 "Could not determine file size of '%s' (errno=%d)\n",
159 mAddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
160 if (mAddr == MAP_FAILED) {
161 LOG(LOG_ERROR, "shmem", "mmap failed (errno=%d)\n", errno);
168 assert(mCreator == false);
171 /* done with shmem, attach to associated semaphore */
172 if (!mSem.attach(key)) {
173 LOG(LOG_ERROR, "shmem",
174 "Failed to attach to semaphore for Shmem (key=%d)\n", key);
184 void* Shmem::getAddr(void)
186 assert(mAddr != MAP_FAILED);
191 * Return the length of the segment.
193 * Returns -1 on failure.
195 long Shmem::getLength(void)
200 // we should always have it by now
206 #elif defined(HAVE_SYSV_IPC) // ----------------------------------------------
209 * SysV-style IPC. The SysV shared memory API is fairly annoying to
210 * deal with, but it's present on many UNIX-like systems.
213 #define kInvalidHandle ((unsigned long)-1)
216 * Constructor. Just set up the fields.
219 : mHandle(kInvalidHandle), mAddr(NULL), mLength(-1), mCreator(false),
225 * Destructor. Detach and, if we created it, mark the segment for
232 //LOG(LOG_DEBUG, "shmem", "~Shmem(handle=%ld creator=%d)",
233 // mHandle, mCreator);
238 if (mCreator && mHandle != kInvalidHandle) {
239 cc = shmctl((int) mHandle, IPC_RMID, NULL);
241 LOG(LOG_WARN, "shmem",
242 "Destructor failed to remove shmid=%ld (errno=%d)\n",
249 * Create the segment and attach ourselves to it.
251 bool Shmem::create(int key, long size, bool deleteExisting)
255 if (deleteExisting) {
256 shmid = shmget(key, size, 0);
258 LOG(LOG_DEBUG, "shmem",
259 "Key %d exists (shmid=%d), marking for destroy", key, shmid);
260 cc = shmctl(shmid, IPC_RMID, NULL);
262 LOG(LOG_ERROR, "shmem",
263 "Failed to remove key=%d shmid=%d (errno=%d)\n",
265 return false; // IPC_CREAT | IPC_EXCL will fail, so bail now
267 LOG(LOG_DEBUG, "shmem",
268 "Removed previous segment with key=%d\n", key);
273 shmid = shmget(key, size, 0600 | IPC_CREAT | IPC_EXCL);
275 LOG(LOG_ERROR, "shmem", "Failed to create key=%d (errno=%d)\n",
284 void* addr = shmat(shmid, NULL, 0);
285 if (addr == (void*) -1) {
286 LOG(LOG_ERROR, "shmem",
287 "Could not attach to key=%d shmid=%d (errno=%d)\n",
295 /* done with shmem, create the associated semaphore */
296 if (!mSem.create(key, 1, true)) {
297 LOG(LOG_ERROR, "shmem",
298 "Failed creating semaphore for Shmem (key=%d)\n", key);
306 * Attach ourselves to an existing segment.
308 bool Shmem::attach(int key)
312 shmid = shmget(key, 0, 0);
314 LOG(LOG_ERROR, "shmem", "Failed to find key=%d\n", key);
319 assert(mCreator == false);
322 void* addr = shmat(shmid, NULL, 0);
323 if (addr == (void*) -1) {
324 LOG(LOG_ERROR, "shmem", "Could not attach to key=%d shmid=%d\n",
331 /* done with shmem, attach to associated semaphore */
332 if (!mSem.attach(key)) {
333 LOG(LOG_ERROR, "shmem",
334 "Failed to attach to semaphore for Shmem (key=%d)\n", key);
344 void* Shmem::getAddr(void)
346 assert(mAddr != NULL);
351 * Return the length of the segment.
353 * Returns -1 on failure.
355 long Shmem::getLength(void)
360 assert(mHandle != kInvalidHandle);
362 struct shmid_ds shmids;
365 cc = shmctl((int) mHandle, IPC_STAT, &shmids);
367 LOG(LOG_ERROR, "shmem", "Could not IPC_STAT shmid=%ld\n", mHandle);
370 mLength = shmids.shm_segsz; // save a copy to avoid future lookups
376 #elif defined(HAVE_WIN32_IPC) // ---------------------------------------------
379 * Win32 shared memory implementation.
381 * Shared memory is implemented as an "anonymous" file mapping, using the
382 * memory-mapped I/O interfaces.
385 static const char* kShmemStr = "android-shmem-";
388 * Constructor. Just set up the fields.
391 : mHandle((unsigned long) INVALID_HANDLE_VALUE),
392 mAddr(NULL), mLength(-1), mCreator(false), mKey(-1)
397 * Destructor. The Win32 API doesn't require a distinction between
398 * the "creator" and other mappers.
402 LOG(LOG_DEBUG, "shmem", "~Shmem(handle=%ld creator=%d)",
406 UnmapViewOfFile(mAddr);
407 if (mHandle != (unsigned long) INVALID_HANDLE_VALUE)
408 CloseHandle((HANDLE) mHandle);
412 * Create the segment and map it.
414 bool Shmem::create(int key, long size, bool deleteExisting)
419 snprintf(keyBuf, sizeof(keyBuf), "%s%d", kShmemStr, key);
421 hMapFile = CreateFileMapping(
422 INVALID_HANDLE_VALUE, // use paging file, not actual file
423 NULL, // default security
424 PAGE_READWRITE, // read/write access
425 0, // max size; no need to cap
427 keyBuf); // mapping name
428 if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE) {
429 LOG(LOG_ERROR, "shmem",
430 "Could not create mapping object '%s' (err=%ld)\n",
431 keyBuf, GetLastError());
435 mHandle = (unsigned long) hMapFile;
439 mAddr = MapViewOfFile(
440 hMapFile, // handle to map object
441 FILE_MAP_ALL_ACCESS, // read/write
444 size); // #of bytes to map
446 LOG(LOG_ERROR, "shmem", "Could not map shared area (err=%ld)\n",
452 /* done with shmem, create the associated semaphore */
453 if (!mSem.create(key, 1, true)) {
454 LOG(LOG_ERROR, "shmem",
455 "Failed creating semaphore for Shmem (key=%d)\n", key);
463 * Attach ourselves to an existing segment.
465 bool Shmem::attach(int key)
470 snprintf(keyBuf, sizeof(keyBuf), "%s%d", kShmemStr, key);
472 hMapFile = OpenFileMapping(
473 FILE_MAP_ALL_ACCESS, // read/write
474 FALSE, // don't let kids inherit handle
475 keyBuf); // mapping name
476 if (hMapFile == NULL) {
477 LOG(LOG_ERROR, "shmem",
478 "Could not open mapping object '%s' (err=%ld)\n",
479 keyBuf, GetLastError());
483 mHandle = (unsigned long) hMapFile;
484 assert(mCreator == false);
487 mAddr = MapViewOfFile(
488 hMapFile, // handle to map object
489 FILE_MAP_ALL_ACCESS, // read/write
492 0); // #of bytes to map
494 LOG(LOG_ERROR, "shmem", "Could not map shared area (err=%ld)\n",
499 /* done with shmem, attach to associated semaphore */
500 if (!mSem.attach(key)) {
501 LOG(LOG_ERROR, "shmem",
502 "Failed to attach to semaphore for Shmem (key=%d)\n", key);
512 void* Shmem::getAddr(void)
514 assert(mAddr != NULL);
519 * Get the length of the segment.
521 long Shmem::getLength(void)
524 MEMORY_BASIC_INFORMATION mbInfo;
529 assert(mAddr != NULL);
531 size = VirtualQuery(mAddr, &mbInfo, sizeof(mbInfo));
533 LOG(LOG_WARN, "shmem", "VirtualQuery returned no data\n");
537 mLength = mbInfo.RegionSize;
541 #endif // --------------------------------------------------------------------
544 * Semaphore operations.
546 void Shmem::lock(void)
550 void Shmem::unlock(void)
554 bool Shmem::tryLock(void)
556 return mSem.tryAcquire();