OSDN Git Service

am af242824: Revert "Fix a type error in the allocation of non-moving arrays." per...
[android-x86/dalvik.git] / vm / Misc.c
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  * Miscellaneous utility functions.
18  */
19 #include "Dalvik.h"
20
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <ctype.h>
26 #include <time.h>
27 #include <sys/time.h>
28 #include <fcntl.h>
29 #include <cutils/ashmem.h>
30 #include <sys/mman.h>
31
32 #define ALIGN_UP_TO_PAGE_SIZE(p) \
33     (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
34
35 /*
36  * Print a hex dump in this format:
37  *
38 01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff  0123456789abcdef\n
39  *
40  * If "mode" is kHexDumpLocal, we start at offset zero, and show a full
41  * 16 bytes on the first line.  If it's kHexDumpMem, we make this look
42  * like a memory dump, using the actual address, outputting a partial line
43  * if "vaddr" isn't aligned on a 16-byte boundary.
44  *
45  * "priority" and "tag" determine the values passed to the log calls.
46  *
47  * Does not use printf() or other string-formatting calls.
48  */
49 void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
50     size_t length, HexDumpMode mode)
51 {
52     static const char gHexDigit[] = "0123456789abcdef";
53     const unsigned char* addr = vaddr;
54     char out[77];           /* exact fit */
55     unsigned int offset;    /* offset to show while printing */
56     char* hex;
57     char* asc;
58     int gap;
59     //int trickle = 0;
60
61     if (mode == kHexDumpLocal)
62         offset = 0;
63     else
64         offset = (int) addr;
65
66     memset(out, ' ', sizeof(out)-1);
67     out[8] = ':';
68     out[sizeof(out)-2] = '\n';
69     out[sizeof(out)-1] = '\0';
70
71     gap = (int) offset & 0x0f;
72     while (length) {
73         unsigned int lineOffset = offset & ~0x0f;
74         int i, count;
75
76         hex = out;
77         asc = out + 59;
78
79         for (i = 0; i < 8; i++) {
80             *hex++ = gHexDigit[lineOffset >> 28];
81             lineOffset <<= 4;
82         }
83         hex++;
84         hex++;
85
86         count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */
87         assert(count != 0);
88         assert(count+gap <= 16);
89
90         if (gap) {
91             /* only on first line */
92             hex += gap * 3;
93             asc += gap;
94         }
95
96         for (i = gap ; i < count+gap; i++) {
97             *hex++ = gHexDigit[*addr >> 4];
98             *hex++ = gHexDigit[*addr & 0x0f];
99             hex++;
100             if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/)
101                 *asc++ = *addr;
102             else
103                 *asc++ = '.';
104             addr++;
105         }
106         for ( ; i < 16; i++) {
107             /* erase extra stuff; only happens on last line */
108             *hex++ = ' ';
109             *hex++ = ' ';
110             hex++;
111             *asc++ = ' ';
112         }
113
114         LOG_PRI(priority, tag, "%s", out);
115 #if 0 //def HAVE_ANDROID_OS
116         /*
117          * We can overrun logcat easily by writing at full speed.  On the
118          * other hand, we can make Eclipse time out if we're showing
119          * packet dumps while debugging JDWP.
120          */
121         {
122             if (trickle++ == 8) {
123                 trickle = 0;
124                 usleep(20000);
125             }
126         }
127 #endif
128
129         gap = 0;
130         length -= count;
131         offset += count;
132     }
133 }
134
135
136 /*
137  * Fill out a DebugOutputTarget, suitable for printing to the log.
138  */
139 void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
140     const char* tag)
141 {
142     assert(target != NULL);
143     assert(tag != NULL);
144
145     target->which = kDebugTargetLog;
146     target->data.log.priority = priority;
147     target->data.log.tag = tag;
148 }
149
150 /*
151  * Fill out a DebugOutputTarget suitable for printing to a file pointer.
152  */
153 void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp)
154 {
155     assert(target != NULL);
156     assert(fp != NULL);
157
158     target->which = kDebugTargetFile;
159     target->data.file.fp = fp;
160 }
161
162 /*
163  * Free "target" and any associated data.
164  */
165 void dvmFreeOutputTarget(DebugOutputTarget* target)
166 {
167     free(target);
168 }
169
170 /*
171  * Print a debug message, to either a file or the log.
172  */
173 void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
174     ...)
175 {
176     va_list args;
177
178     va_start(args, format);
179
180     switch (target->which) {
181     case kDebugTargetLog:
182         LOG_PRI_VA(target->data.log.priority, target->data.log.tag,
183             format, args);
184         break;
185     case kDebugTargetFile:
186         vfprintf(target->data.file.fp, format, args);
187         break;
188     default:
189         LOGE("unexpected 'which' %d\n", target->which);
190         break;
191     }
192
193     va_end(args);
194 }
195
196
197 /*
198  * Allocate a bit vector with enough space to hold at least the specified
199  * number of bits.
200  */
201 BitVector* dvmAllocBitVector(int startBits, bool expandable)
202 {
203     BitVector* bv;
204     int count;
205
206     assert(sizeof(bv->storage[0]) == 4);        /* assuming 32-bit units */
207     assert(startBits >= 0);
208
209     bv = (BitVector*) malloc(sizeof(BitVector));
210
211     count = (startBits + 31) >> 5;
212
213     bv->storageSize = count;
214     bv->expandable = expandable;
215     bv->storage = (u4*) malloc(count * sizeof(u4));
216     memset(bv->storage, 0x00, count * sizeof(u4));
217     return bv;
218 }
219
220 /*
221  * Free a BitVector.
222  */
223 void dvmFreeBitVector(BitVector* pBits)
224 {
225     if (pBits == NULL)
226         return;
227
228     free(pBits->storage);
229     free(pBits);
230 }
231
232 /*
233  * "Allocate" the first-available bit in the bitmap.
234  *
235  * This is not synchronized.  The caller is expected to hold some sort of
236  * lock that prevents multiple threads from executing simultaneously in
237  * dvmAllocBit/dvmFreeBit.
238  */
239 int dvmAllocBit(BitVector* pBits)
240 {
241     int word, bit;
242
243 retry:
244     for (word = 0; word < pBits->storageSize; word++) {
245         if (pBits->storage[word] != 0xffffffff) {
246             /*
247              * There are unallocated bits in this word.  Return the first.
248              */
249             bit = ffs(~(pBits->storage[word])) -1;
250             assert(bit >= 0 && bit < 32);
251             pBits->storage[word] |= 1 << bit;
252             return (word << 5) | bit;
253         }
254     }
255
256     /*
257      * Ran out of space, allocate more if we're allowed to.
258      */
259     if (!pBits->expandable)
260         return -1;
261
262     pBits->storage = realloc(pBits->storage,
263                     (pBits->storageSize + kBitVectorGrowth) * sizeof(u4));
264     memset(&pBits->storage[pBits->storageSize], 0x00,
265         kBitVectorGrowth * sizeof(u4));
266     pBits->storageSize += kBitVectorGrowth;
267     goto retry;
268 }
269
270 /*
271  * Mark the specified bit as "set".
272  *
273  * Returns "false" if the bit is outside the range of the vector and we're
274  * not allowed to expand.
275  */
276 bool dvmSetBit(BitVector* pBits, int num)
277 {
278     assert(num >= 0);
279     if (num >= pBits->storageSize * (int)sizeof(u4) * 8) {
280         if (!pBits->expandable)
281             return false;
282
283         /* Round up to word boundaries for "num+1" bits */
284         int newSize = (num + 1 + 31) >> 5;
285         assert(newSize > pBits->storageSize);
286         pBits->storage = realloc(pBits->storage, newSize * sizeof(u4));
287         memset(&pBits->storage[pBits->storageSize], 0x00,
288             (newSize - pBits->storageSize) * sizeof(u4));
289         pBits->storageSize = newSize;
290     }
291
292     pBits->storage[num >> 5] |= 1 << (num & 0x1f);
293     return true;
294 }
295
296 /*
297  * Mark the specified bit as "clear".
298  */
299 void dvmClearBit(BitVector* pBits, int num)
300 {
301     assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
302
303     pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
304 }
305
306 /*
307  * Mark all bits bit as "clear".
308  */
309 void dvmClearAllBits(BitVector* pBits)
310 {
311     int count = pBits->storageSize;
312     memset(pBits->storage, 0, count * sizeof(u4));
313 }
314
315 /*
316  * Determine whether or not the specified bit is set.
317  */
318 bool dvmIsBitSet(const BitVector* pBits, int num)
319 {
320     assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
321
322     int val = pBits->storage[num >> 5] & (1 << (num & 0x1f));
323     return (val != 0);
324 }
325
326 /*
327  * Count the number of bits that are set.
328  */
329 int dvmCountSetBits(const BitVector* pBits)
330 {
331     int word;
332     int count = 0;
333
334     for (word = 0; word < pBits->storageSize; word++) {
335         u4 val = pBits->storage[word];
336
337         if (val != 0) {
338             if (val == 0xffffffff) {
339                 count += 32;
340             } else {
341                 /* count the number of '1' bits */
342                 while (val != 0) {
343                     val &= val - 1;
344                     count++;
345                 }
346             }
347         }
348     }
349
350     return count;
351 }
352
353 /*
354  * Copy a whole vector to the other. Only do that when the both vectors have
355  * the same size and attribute.
356  */
357 bool dvmCopyBitVector(BitVector *dest, const BitVector *src)
358 {
359     if (dest->storageSize != src->storageSize ||
360         dest->expandable != src->expandable)
361         return false;
362     memcpy(dest->storage, src->storage, sizeof(u4) * dest->storageSize);
363     return true;
364 }
365
366 /*
367  * Intersect two bit vectores and merge the result on top of the pre-existing
368  * value in the dest vector.
369  */
370 bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1,
371                             const BitVector *src2)
372 {
373     if (dest->storageSize != src1->storageSize ||
374         dest->storageSize != src2->storageSize ||
375         dest->expandable != src1->expandable ||
376         dest->expandable != src2->expandable)
377         return false;
378
379     int i;
380     for (i = 0; i < dest->storageSize; i++) {
381         dest->storage[i] |= src1->storage[i] & src2->storage[i];
382     }
383     return true;
384 }
385
386 /*
387  * Return a newly-allocated string in which all occurrences of '.' have
388  * been changed to '/'.  If we find a '/' in the original string, NULL
389  * is returned to avoid ambiguity.
390  */
391 char* dvmDotToSlash(const char* str)
392 {
393     char* newStr = strdup(str);
394     char* cp = newStr;
395
396     if (newStr == NULL)
397         return NULL;
398
399     while (*cp != '\0') {
400         if (*cp == '/') {
401             assert(false);
402             return NULL;
403         }
404         if (*cp == '.')
405             *cp = '/';
406         cp++;
407     }
408
409     return newStr;
410 }
411
412 char* dvmHumanReadableDescriptor(const char* descriptor)
413 {
414     // Count the number of '['s to get the dimensionality.
415     const char* c = descriptor;
416     size_t dim = 0;
417     while (*c == '[') {
418         dim++;
419         c++;
420     }
421
422     // Work out how large the result will be.
423     size_t resultLength;
424     if (*c == 'L') {
425         // "[[La/b/C;" -> "a.b.C[][]".
426         resultLength = strlen(c) - 2 + 2*dim;
427         c++; // Skip the 'L'.
428     } else {
429         // "[[B" -> "byte[][]".
430         // To make life easier, we make primitives look like unqualified
431         // reference types.
432         switch (*c) {
433         case 'B': c = "byte;"; break;
434         case 'C': c = "char;"; break;
435         case 'D': c = "double;"; break;
436         case 'F': c = "float;"; break;
437         case 'I': c = "int;"; break;
438         case 'J': c = "long;"; break;
439         case 'S': c = "short;"; break;
440         case 'Z': c = "boolean;"; break;
441         default: return strdup(descriptor);
442         }
443         resultLength = strlen(c) - 1 + 2*dim;
444     }
445
446     // Allocate enough space.
447     char* result = malloc(resultLength + 1);
448     if (result == NULL) {
449         return NULL;
450     }
451
452     // At this point, 'c' is a string of the form "fully/qualified/Type;"
453     // or "primitive;". Rewrite the type with '.' instead of '/':
454     const char* p = c;
455     char* q = result;
456     while (*p != ';') {
457         char ch = *p++;
458         if (ch == '/') {
459           ch = '.';
460         }
461         *q++ = ch;
462     }
463     // ...and replace the semicolon with 'dim' "[]" pairs:
464     while (dim--) {
465         *q++ = '[';
466         *q++ = ']';
467     }
468     *q = '\0';
469     return result;
470 }
471
472 /*
473  * Return a newly-allocated string for the "dot version" of the class
474  * name for the given type descriptor. That is, The initial "L" and
475  * final ";" (if any) have been removed and all occurrences of '/'
476  * have been changed to '.'.
477  *
478  * "Dot version" names are used in the class loading machinery.
479  * See also dvmHumanReadableDescriptor.
480  */
481 char* dvmDescriptorToDot(const char* str)
482 {
483     size_t at = strlen(str);
484     char* newStr;
485
486     if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
487         at -= 2; /* Two fewer chars to copy. */
488         str++; /* Skip the 'L'. */
489     }
490
491     newStr = malloc(at + 1); /* Add one for the '\0'. */
492     if (newStr == NULL)
493         return NULL;
494
495     newStr[at] = '\0';
496
497     while (at > 0) {
498         at--;
499         newStr[at] = (str[at] == '/') ? '.' : str[at];
500     }
501
502     return newStr;
503 }
504
505 /*
506  * Return a newly-allocated string for the type descriptor
507  * corresponding to the "dot version" of the given class name. That
508  * is, non-array names are surrounded by "L" and ";", and all
509  * occurrences of '.' have been changed to '/'.
510  *
511  * "Dot version" names are used in the class loading machinery.
512  */
513 char* dvmDotToDescriptor(const char* str)
514 {
515     size_t length = strlen(str);
516     int wrapElSemi = 0;
517     char* newStr;
518     char* at;
519
520     if (str[0] != '[') {
521         length += 2; /* for "L" and ";" */
522         wrapElSemi = 1;
523     }
524
525     newStr = at = malloc(length + 1); /* + 1 for the '\0' */
526
527     if (newStr == NULL) {
528         return NULL;
529     }
530
531     if (wrapElSemi) {
532         *(at++) = 'L';
533     }
534
535     while (*str) {
536         char c = *(str++);
537         if (c == '.') {
538             c = '/';
539         }
540         *(at++) = c;
541     }
542
543     if (wrapElSemi) {
544         *(at++) = ';';
545     }
546
547     *at = '\0';
548     return newStr;
549 }
550
551 /*
552  * Return a newly-allocated string for the internal-form class name for
553  * the given type descriptor. That is, the initial "L" and final ";" (if
554  * any) have been removed.
555  */
556 char* dvmDescriptorToName(const char* str)
557 {
558     if (str[0] == 'L') {
559         size_t length = strlen(str) - 1;
560         char* newStr = malloc(length);
561
562         if (newStr == NULL) {
563             return NULL;
564         }
565
566         strlcpy(newStr, str + 1, length);
567         return newStr;
568     }
569
570     return strdup(str);
571 }
572
573 /*
574  * Return a newly-allocated string for the type descriptor for the given
575  * internal-form class name. That is, a non-array class name will get
576  * surrounded by "L" and ";", while array names are left as-is.
577  */
578 char* dvmNameToDescriptor(const char* str)
579 {
580     if (str[0] != '[') {
581         size_t length = strlen(str);
582         char* descriptor = malloc(length + 3);
583
584         if (descriptor == NULL) {
585             return NULL;
586         }
587
588         descriptor[0] = 'L';
589         strcpy(descriptor + 1, str);
590         descriptor[length + 1] = ';';
591         descriptor[length + 2] = '\0';
592
593         return descriptor;
594     }
595
596     return strdup(str);
597 }
598
599 /*
600  * Get a notion of the current time, in nanoseconds.  This is meant for
601  * computing durations (e.g. "operation X took 52nsec"), so the result
602  * should not be used to get the current date/time.
603  */
604 u8 dvmGetRelativeTimeNsec(void)
605 {
606 #ifdef HAVE_POSIX_CLOCKS
607     struct timespec now;
608     clock_gettime(CLOCK_MONOTONIC, &now);
609     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
610 #else
611     struct timeval now;
612     gettimeofday(&now, NULL);
613     return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
614 #endif
615 }
616
617 /*
618  * Get the per-thread CPU time, in nanoseconds.
619  *
620  * Only useful for time deltas.
621  */
622 u8 dvmGetThreadCpuTimeNsec(void)
623 {
624 #ifdef HAVE_POSIX_CLOCKS
625     struct timespec now;
626     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
627     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
628 #else
629     return (u8) -1;
630 #endif
631 }
632
633 /*
634  * Get the per-thread CPU time, in nanoseconds, for the specified thread.
635  */
636 u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
637 {
638 #if 0 /*def HAVE_POSIX_CLOCKS*/
639     int clockId;
640
641     if (pthread_getcpuclockid(thread, &clockId) != 0)
642         return (u8) -1;
643
644     struct timespec now;
645     clock_gettime(clockId, &now);
646     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
647 #else
648     return (u8) -1;
649 #endif
650 }
651
652
653 /*
654  * Call this repeatedly, with successively higher values for "iteration",
655  * to sleep for a period of time not to exceed "maxTotalSleep".
656  *
657  * For example, when called with iteration==0 we will sleep for a very
658  * brief time.  On the next call we will sleep for a longer time.  When
659  * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
660  *
661  * The initial start time value for "relStartTime" MUST come from the
662  * dvmGetRelativeTimeUsec call.  On the device this must come from the
663  * monotonic clock source, not the wall clock.
664  *
665  * This should be used wherever you might be tempted to call sched_yield()
666  * in a loop.  The problem with sched_yield is that, for a high-priority
667  * thread, the kernel might not actually transfer control elsewhere.
668  *
669  * Returns "false" if we were unable to sleep because our time was up.
670  */
671 bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
672 {
673     const int minSleep = 10000;
674     u8 curTime;
675     int curDelay;
676
677     /*
678      * Get current time, and see if we've already exceeded the limit.
679      */
680     curTime = dvmGetRelativeTimeUsec();
681     if (curTime >= relStartTime + maxTotalSleep) {
682         LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
683             relStartTime, maxTotalSleep, curTime);
684         return false;
685     }
686
687     /*
688      * Compute current delay.  We're bounded by "maxTotalSleep", so no
689      * real risk of overflow assuming "usleep" isn't returning early.
690      * (Besides, 2^30 usec is about 18 minutes by itself.)
691      *
692      * For iteration==0 we just call sched_yield(), so the first sleep
693      * at iteration==1 is actually (minSleep * 2).
694      */
695     curDelay = minSleep;
696     while (iteration-- > 0)
697         curDelay *= 2;
698     assert(curDelay > 0);
699
700     if (curTime + curDelay >= relStartTime + maxTotalSleep) {
701         LOGVV("exsl: reduced delay from %d to %d\n",
702             curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
703         curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
704     }
705
706     if (iteration == 0) {
707         LOGVV("exsl: yield\n");
708         sched_yield();
709     } else {
710         LOGVV("exsl: sleep for %d\n", curDelay);
711         usleep(curDelay);
712     }
713     return true;
714 }
715
716
717 /*
718  * Set the "close on exec" flag so we don't expose our file descriptors
719  * to processes launched by us.
720  */
721 bool dvmSetCloseOnExec(int fd)
722 {
723     int flags;
724
725     /*
726      * There's presently only one flag defined, so getting the previous
727      * value of the fd flags is probably unnecessary.
728      */
729     flags = fcntl(fd, F_GETFD);
730     if (flags < 0) {
731         LOGW("Unable to get fd flags for fd %d\n", fd);
732         return false;
733     }
734     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
735         LOGW("Unable to set close-on-exec for fd %d\n", fd);
736         return false;
737     }
738     return true;
739 }
740
741 #if (!HAVE_STRLCPY)
742 /* Implementation of strlcpy() for platforms that don't already have it. */
743 size_t strlcpy(char *dst, const char *src, size_t size) {
744     size_t srcLength = strlen(src);
745     size_t copyLength = srcLength;
746
747     if (srcLength > (size - 1)) {
748         copyLength = size - 1;
749     }
750
751     if (size != 0) {
752         strncpy(dst, src, copyLength);
753         dst[copyLength] = '\0';
754     }
755
756     return srcLength;
757 }
758 #endif
759
760 /*
761  *  Allocates a memory region using ashmem and mmap, initialized to
762  *  zero.  Actual allocation rounded up to page multiple.  Returns
763  *  NULL on failure.
764  */
765 void *dvmAllocRegion(size_t size, int prot, const char *name) {
766     void *base;
767     int fd, ret;
768
769     size = ALIGN_UP_TO_PAGE_SIZE(size);
770     fd = ashmem_create_region(name, size);
771     if (fd == -1) {
772         return NULL;
773     }
774     base = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0);
775     ret = close(fd);
776     if (base == MAP_FAILED) {
777         return NULL;
778     }
779     if (ret == -1) {
780         return NULL;
781     }
782     return base;
783 }
784
785 /*
786  * Get some per-thread stats.
787  *
788  * This is currently generated by opening the appropriate "stat" file
789  * in /proc and reading the pile of stuff that comes out.
790  */
791 bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
792 {
793     /*
794     int pid;
795     char comm[128];
796     char state;
797     int ppid, pgrp, session, tty_nr, tpgid;
798     unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
799     long cutime, cstime, priority, nice, zero, itrealvalue;
800     unsigned long starttime, vsize;
801     long rss;
802     unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
803     unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
804     int exit_signal, processor;
805     unsigned long rt_priority, policy;
806
807     scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
808           "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
809           "%lu %lu %lu %d %d %lu %lu",
810         &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
811         &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
812         &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
813         &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
814         &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
815         &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
816         &rt_priority, &policy);
817
818         (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
819     */
820
821     char nameBuf[64];
822     int i, fd;
823
824     /*
825      * Open and read the appropriate file.  This is expected to work on
826      * Linux but will fail on other platforms (e.g. Mac sim).
827      */
828     sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
829     fd = open(nameBuf, O_RDONLY);
830     if (fd < 0) {
831         LOGV("Unable to open '%s': %s\n", nameBuf, strerror(errno));
832         return false;
833     }
834
835     char lineBuf[512];      /* > 2x typical */
836     int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
837     if (cc <= 0) {
838         const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
839         LOGI("Unable to read '%s': %s\n", nameBuf, msg);
840         close(fd);
841         return false;
842     }
843     close(fd);
844     lineBuf[cc] = '\0';
845
846     /*
847      * Skip whitespace-separated tokens.  For the most part we can assume
848      * that tokens do not contain spaces, and are separated by exactly one
849      * space character.  The only exception is the second field ("comm")
850      * which may contain spaces but is surrounded by parenthesis.
851      */
852     char* cp = strchr(lineBuf, ')');
853     if (cp == NULL)
854         goto parse_fail;
855     cp++;
856     for (i = 2; i < 13; i++) {
857         cp = strchr(cp+1, ' ');
858         if (cp == NULL)
859             goto parse_fail;
860     }
861
862     /*
863      * Grab utime/stime.
864      */
865     char* endp;
866     pData->utime = strtoul(cp+1, &endp, 10);
867     if (endp == cp+1)
868         LOGI("Warning: strtoul failed on utime ('%.30s...')\n", cp);
869
870     cp = strchr(cp+1, ' ');
871     if (cp == NULL)
872         goto parse_fail;
873
874     pData->stime = strtoul(cp+1, &endp, 10);
875     if (endp == cp+1)
876         LOGI("Warning: strtoul failed on stime ('%.30s...')\n", cp);
877
878     /*
879      * Skip more stuff we don't care about.
880      */
881     for (i = 14; i < 38; i++) {
882         cp = strchr(cp+1, ' ');
883         if (cp == NULL)
884             goto parse_fail;
885     }
886
887     /*
888      * Grab processor number.
889      */
890     pData->processor = strtol(cp+1, &endp, 10);
891     if (endp == cp+1)
892         LOGI("Warning: strtoul failed on processor ('%.30s...')\n", cp);
893
894     return true;
895
896 parse_fail:
897     LOGI("stat parse failed (%s)\n", lineBuf);
898     return false;
899 }
900
901 /* documented in header file */
902 const char* dvmPathToAbsolutePortion(const char* path) {
903     if (path == NULL) {
904         return NULL;
905     }
906
907     if (path[0] == '/') {
908         /* It's a regular absolute path. Return it. */
909         return path;
910     }
911
912     const char* sentinel = strstr(path, "/./");
913
914     if (sentinel != NULL) {
915         /* It's got the sentinel. Return a pointer to the second slash. */
916         return sentinel + 2;
917     }
918
919     return NULL;
920 }