OSDN Git Service

Merge "Update samples to use new getMotionRanges() API." into honeycomb-mr1
[android-x86/development.git] / simulator / app / Shmem.cpp
1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 // Shared memory interface.
5 //
6 #include "Shmem.h"
7 #include "utils/Log.h"
8
9 #if defined(HAVE_MACOSX_IPC) || defined(HAVE_ANDROID_IPC)
10 #  include <sys/mman.h>
11 #  include <fcntl.h>
12 #  include <unistd.h>
13 #elif defined(HAVE_SYSV_IPC)
14 # include <sys/types.h>
15 # include <sys/ipc.h>
16 # include <sys/shm.h>
17 #elif defined(HAVE_WIN32_IPC)
18 # include <windows.h>
19 #else
20 # error "unknown shm config"
21 #endif
22
23 #include <errno.h>
24 #include <assert.h>
25
26 using namespace android;
27
28
29 #if defined(HAVE_MACOSX_IPC) || defined(HAVE_ANDROID_IPC)
30
31 /*
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().
35  */
36
37 #define kInvalidHandle  ((unsigned long)-1)
38
39 static const char* kShmemFile = "/tmp/android-";
40
41 /*
42  * Constructor.  Just set up the fields.
43  */
44 Shmem::Shmem(void)
45     : mHandle(kInvalidHandle), mAddr(MAP_FAILED), mLength(-1), mCreator(false),
46       mKey(-1)
47 {
48 }
49
50 /*
51  * Destructor.  Detach and, if we created it, mark the segment for
52  * destruction.
53  */
54 Shmem::~Shmem(void)
55 {
56     if (mAddr != MAP_FAILED)
57         munmap(mAddr, mLength);
58     if ((long)mHandle >= 0) {
59         close(mHandle);
60
61         if (mCreator) {
62             char nameBuf[64];
63             int cc;
64
65             snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, mKey);
66             cc = unlink(nameBuf);
67             if (cc != 0) {
68                 LOG(LOG_WARN, "shmem", "Couldn't clean up '%s'\n", nameBuf);
69                 /* oh well */
70             }
71         }
72     }
73 }
74
75 /*
76  * Create the segment and attach ourselves to it.
77  */
78 bool Shmem::create(int key, long size, bool deleteExisting)
79 {
80     char nameBuf[64];
81     int fd, cc;
82
83     snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, key);
84
85     if (deleteExisting) {
86         cc = unlink(nameBuf);
87         if (cc != 0 && errno != ENOENT) {
88             LOG(LOG_ERROR, "shmem", "Failed to remove old map file '%s'\n",
89                 nameBuf);
90             return false;
91         }
92     }
93
94     fd = open(nameBuf, O_CREAT|O_EXCL|O_RDWR, 0600);
95     if (fd < 0) {
96         LOG(LOG_ERROR, "shmem", "Unable to create map file '%s' (errno=%d)\n",
97             nameBuf, errno);
98         return false;
99     }
100
101     /*
102      * Set the file size by seeking and writing.
103      */
104     if (ftruncate(fd, size) == -1) {
105         LOG(LOG_ERROR, "shmem", "Unable to set file size in '%s' (errno=%d)\n",
106             nameBuf, errno);
107         close(fd);
108         return false;
109     }
110
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);
114         close(fd);
115         return false;
116     }
117
118     mHandle = fd;
119     mLength = size;
120     mCreator = true;
121     mKey = key;
122
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);
127         return false;
128     }
129
130     return true;
131 }
132
133 /*
134  * Attach ourselves to an existing segment.
135  */
136 bool Shmem::attach(int key)
137 {
138     char nameBuf[64];
139     int fd;
140
141     snprintf(nameBuf, sizeof(nameBuf), "%s%d", kShmemFile, key);
142     fd = open(nameBuf, O_RDWR, 0600);
143     if (fd < 0) {
144         LOG(LOG_ERROR, "shmem", "Unable to open map file '%s' (errno=%d)\n",
145             nameBuf, errno);
146         return false;
147     }
148
149     off_t len;
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",
154             nameBuf, errno);
155         close(fd);
156         return false;
157     }
158
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);
162         close(fd);
163         return false;
164     }
165
166     mHandle = fd;
167     mLength = len;
168     assert(mCreator == false);
169     mKey = key;
170
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);
175         return false;
176     }
177
178     return true;
179 }
180
181 /*
182  * Get address.
183  */
184 void* Shmem::getAddr(void)
185 {
186     assert(mAddr != MAP_FAILED);
187     return mAddr;
188 }
189
190 /*
191  * Return the length of the segment.
192  *
193  * Returns -1 on failure.
194  */
195 long Shmem::getLength(void)
196 {
197     if (mLength >= 0)
198         return mLength;
199
200     // we should always have it by now
201     assert(false);
202     return -1;
203 }
204
205
206 #elif defined(HAVE_SYSV_IPC) // ----------------------------------------------
207
208 /*
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.
211  */
212
213 #define kInvalidHandle  ((unsigned long)-1)
214
215 /*
216  * Constructor.  Just set up the fields.
217  */
218 Shmem::Shmem(void)
219     : mHandle(kInvalidHandle), mAddr(NULL), mLength(-1), mCreator(false),
220       mKey(-1)
221 {
222 }
223
224 /*
225  * Destructor.  Detach and, if we created it, mark the segment for
226  * destruction.
227  */
228 Shmem::~Shmem(void)
229 {
230     int cc;
231
232     //LOG(LOG_DEBUG, "shmem", "~Shmem(handle=%ld creator=%d)",
233     //    mHandle, mCreator);
234
235     if (mAddr != NULL)
236         cc = shmdt(mAddr);
237
238     if (mCreator && mHandle != kInvalidHandle) {
239         cc = shmctl((int) mHandle, IPC_RMID, NULL);
240         if (cc != 0) {
241             LOG(LOG_WARN, "shmem",
242                 "Destructor failed to remove shmid=%ld (errno=%d)\n",
243                 mHandle, errno);
244         }
245     }
246 }
247
248 /*
249  * Create the segment and attach ourselves to it.
250  */
251 bool Shmem::create(int key, long size, bool deleteExisting)
252 {
253     int shmid, cc;
254
255     if (deleteExisting) {
256         shmid = shmget(key, size, 0);
257         if (shmid != -1) {
258             LOG(LOG_DEBUG, "shmem",
259                 "Key %d exists (shmid=%d), marking for destroy", key, shmid);
260             cc = shmctl(shmid, IPC_RMID, NULL);
261             if (cc != 0) {
262                 LOG(LOG_ERROR, "shmem",
263                     "Failed to remove key=%d shmid=%d (errno=%d)\n",
264                     key, shmid, errno);
265                 return false;   // IPC_CREAT | IPC_EXCL will fail, so bail now
266             } else {
267                 LOG(LOG_DEBUG, "shmem",
268                     "Removed previous segment with key=%d\n", key);
269             }
270         }
271     }
272
273     shmid = shmget(key, size, 0600 | IPC_CREAT | IPC_EXCL);
274     if (shmid == -1) {
275         LOG(LOG_ERROR, "shmem", "Failed to create key=%d (errno=%d)\n",
276             key, errno);
277         return false;
278     }
279
280     mHandle = shmid;
281     mCreator = true;
282     mKey = key;
283
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",
288             key, shmid, errno);
289         return false;
290     }
291
292     mAddr = addr;
293     mLength = size;
294
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);
299         return false;
300     }
301
302     return true;
303 }
304
305 /*
306  * Attach ourselves to an existing segment.
307  */
308 bool Shmem::attach(int key)
309 {
310     int shmid;
311
312     shmid = shmget(key, 0, 0);
313     if (shmid == -1) {
314         LOG(LOG_ERROR, "shmem", "Failed to find key=%d\n", key);
315         return false;
316     }
317
318     mHandle = shmid;
319     assert(mCreator == false);
320     mKey = key;
321
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",
325             key, shmid);
326         return false;
327     }
328
329     mAddr = addr;
330
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);
335         return false;
336     }
337
338     return true;
339 }
340
341 /*
342  * Get address.
343  */
344 void* Shmem::getAddr(void)
345 {
346     assert(mAddr != NULL);
347     return mAddr;
348 }
349
350 /*
351  * Return the length of the segment.
352  *
353  * Returns -1 on failure.
354  */
355 long Shmem::getLength(void)
356 {
357     if (mLength >= 0)
358         return mLength;
359
360     assert(mHandle != kInvalidHandle);
361
362     struct shmid_ds shmids;
363     int cc;
364
365     cc = shmctl((int) mHandle, IPC_STAT, &shmids);
366     if (cc != 0) {
367         LOG(LOG_ERROR, "shmem", "Could not IPC_STAT shmid=%ld\n", mHandle);
368         return -1;
369     }
370     mLength = shmids.shm_segsz;     // save a copy to avoid future lookups
371
372     return mLength;
373 }
374
375
376 #elif defined(HAVE_WIN32_IPC) // ---------------------------------------------
377
378 /*
379  * Win32 shared memory implementation.
380  *
381  * Shared memory is implemented as an "anonymous" file mapping, using the
382  * memory-mapped I/O interfaces.
383  */
384
385 static const char* kShmemStr = "android-shmem-";
386
387 /*
388  * Constructor.  Just set up the fields.
389  */
390 Shmem::Shmem(void)
391     : mHandle((unsigned long) INVALID_HANDLE_VALUE),
392       mAddr(NULL), mLength(-1), mCreator(false), mKey(-1)
393 {
394 }
395
396 /*
397  * Destructor.  The Win32 API doesn't require a distinction between
398  * the "creator" and other mappers.
399  */
400 Shmem::~Shmem(void)
401 {
402     LOG(LOG_DEBUG, "shmem", "~Shmem(handle=%ld creator=%d)",
403         mHandle, mCreator);
404
405     if (mAddr != NULL)
406         UnmapViewOfFile(mAddr);
407     if (mHandle != (unsigned long) INVALID_HANDLE_VALUE)
408         CloseHandle((HANDLE) mHandle);
409 }
410
411 /*
412  * Create the segment and map it.
413  */
414 bool Shmem::create(int key, long size, bool deleteExisting)
415 {
416     char keyBuf[64];
417     HANDLE hMapFile;
418
419     snprintf(keyBuf, sizeof(keyBuf), "%s%d", kShmemStr, key);
420
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
426                 size,                       // min size
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());
432         return false;
433     }
434
435     mHandle = (unsigned long) hMapFile;
436     mCreator = true;
437     mKey = key;
438
439     mAddr = MapViewOfFile(
440                 hMapFile,                   // handle to map object
441                 FILE_MAP_ALL_ACCESS,        // read/write
442                 0,                          // offset (hi)
443                 0,                          // offset (lo)
444                 size);                      // #of bytes to map
445     if (mAddr == NULL) {
446         LOG(LOG_ERROR, "shmem", "Could not map shared area (err=%ld)\n",
447             GetLastError());
448         return false;
449     }
450     mLength = size;
451
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);
456         return false;
457     }
458
459     return true;
460 }
461
462 /*
463  * Attach ourselves to an existing segment.
464  */
465 bool Shmem::attach(int key)
466 {
467     char keyBuf[64];
468     HANDLE hMapFile;
469
470     snprintf(keyBuf, sizeof(keyBuf), "%s%d", kShmemStr, key);
471
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());
480         return false;
481     }
482
483     mHandle = (unsigned long) hMapFile;
484     assert(mCreator == false);
485     mKey = key;
486
487     mAddr = MapViewOfFile(
488                 hMapFile,                   // handle to map object
489                 FILE_MAP_ALL_ACCESS,        // read/write
490                 0,                          // offset (hi)
491                 0,                          // offset (lo)
492                 0);                        // #of bytes to map
493     if (mAddr == NULL) {
494         LOG(LOG_ERROR, "shmem", "Could not map shared area (err=%ld)\n",
495             GetLastError());
496         return false;
497     }
498
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);
503         return false;
504     }
505
506     return true;
507 }
508
509 /*
510  * Get address.
511  */
512 void* Shmem::getAddr(void)
513 {
514     assert(mAddr != NULL);
515     return mAddr;
516 }
517
518 /*
519  * Get the length of the segment.
520  */
521 long Shmem::getLength(void)
522 {
523     SIZE_T size;
524     MEMORY_BASIC_INFORMATION mbInfo;
525
526     if (mLength >= 0)
527         return mLength;
528
529     assert(mAddr != NULL);
530
531     size = VirtualQuery(mAddr, &mbInfo, sizeof(mbInfo));
532     if (size == 0) {
533         LOG(LOG_WARN, "shmem", "VirtualQuery returned no data\n");
534         return -1;
535     }
536
537     mLength = mbInfo.RegionSize;
538     return mLength;
539 }
540
541 #endif // --------------------------------------------------------------------
542
543 /*
544  * Semaphore operations.
545  */
546 void Shmem::lock(void)
547 {
548     mSem.acquire();
549 }
550 void Shmem::unlock(void)
551 {
552     mSem.release();
553 }
554 bool Shmem::tryLock(void)
555 {
556     return mSem.tryAcquire();
557 }
558