blob: a3bfb737d7a9a53240d7bfcd794a7e77c41a323a [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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>
Carl Shapiro10b0b7a2010-03-16 00:21:41 -070024#include <strings.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080025#include <ctype.h>
26#include <time.h>
27#include <sys/time.h>
28#include <fcntl.h>
Barry Hayes6e5cf602010-06-22 12:32:59 -070029#include <cutils/ashmem.h>
30#include <sys/mman.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080031
Barry Hayes6e5cf602010-06-22 12:32:59 -070032#define ALIGN_UP_TO_PAGE_SIZE(p) \
33 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080034
35/*
36 * Print a hex dump in this format:
37 *
3801234567: 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 */
49void 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 */
139void 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 */
153void 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 */
165void dvmFreeOutputTarget(DebugOutputTarget* target)
166{
167 free(target);
168}
169
170/*
171 * Print a debug message, to either a file or the log.
172 */
173void 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 */
201BitVector* 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 */
223void 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 */
239int dvmAllocBit(BitVector* pBits)
240{
241 int word, bit;
242
243retry:
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 */
276bool 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
Ben Chengabf3ef82010-11-23 11:55:16 -0800283 /* Round up to word boundaries for "num+1" bits */
284 int newSize = (num + 1 + 31) >> 5;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800285 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));
Andy McFadden01651b42009-08-19 10:32:01 -0700289 pBits->storageSize = newSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800290 }
291
292 pBits->storage[num >> 5] |= 1 << (num & 0x1f);
293 return true;
294}
295
296/*
297 * Mark the specified bit as "clear".
298 */
299void 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/*
Ben Chenge9695e52009-06-16 16:11:47 -0700307 * Mark all bits bit as "clear".
308 */
309void dvmClearAllBits(BitVector* pBits)
310{
311 int count = pBits->storageSize;
312 memset(pBits->storage, 0, count * sizeof(u4));
313}
314
315/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800316 * Determine whether or not the specified bit is set.
317 */
318bool 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 */
329int dvmCountSetBits(const BitVector* pBits)
330{
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700331 int word;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800332 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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800353/*
Ben Cheng4238ec22009-08-24 16:32:22 -0700354 * Copy a whole vector to the other. Only do that when the both vectors have
355 * the same size and attribute.
356 */
357bool 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 */
370bool 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/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800387 * 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 */
391char* dvmDotToSlash(const char* str)
392{
393 char* newStr = strdup(str);
394 char* cp = newStr;
395
Andy McFaddenf9058532009-09-03 14:48:10 -0700396 if (newStr == NULL)
397 return NULL;
398
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800399 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/*
413 * Return a newly-allocated string for the "dot version" of the class
414 * name for the given type descriptor. That is, The initial "L" and
415 * final ";" (if any) have been removed and all occurrences of '/'
416 * have been changed to '.'.
417 */
418char* dvmDescriptorToDot(const char* str)
419{
420 size_t at = strlen(str);
421 char* newStr;
422
423 if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
424 at -= 2; /* Two fewer chars to copy. */
425 str++; /* Skip the 'L'. */
426 }
427
428 newStr = malloc(at + 1); /* Add one for the '\0'. */
Andy McFaddenf9058532009-09-03 14:48:10 -0700429 if (newStr == NULL)
430 return NULL;
431
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800432 newStr[at] = '\0';
433
434 while (at > 0) {
435 at--;
436 newStr[at] = (str[at] == '/') ? '.' : str[at];
437 }
438
439 return newStr;
440}
441
442/*
443 * Return a newly-allocated string for the type descriptor
444 * corresponding to the "dot version" of the given class name. That
445 * is, non-array names are surrounded by "L" and ";", and all
446 * occurrences of '.' are changed to '/'.
447 */
448char* dvmDotToDescriptor(const char* str)
449{
450 size_t length = strlen(str);
451 int wrapElSemi = 0;
452 char* newStr;
453 char* at;
454
455 if (str[0] != '[') {
456 length += 2; /* for "L" and ";" */
457 wrapElSemi = 1;
458 }
459
460 newStr = at = malloc(length + 1); /* + 1 for the '\0' */
461
462 if (newStr == NULL) {
463 return NULL;
464 }
465
466 if (wrapElSemi) {
467 *(at++) = 'L';
468 }
469
470 while (*str) {
471 char c = *(str++);
472 if (c == '.') {
473 c = '/';
474 }
475 *(at++) = c;
476 }
477
478 if (wrapElSemi) {
479 *(at++) = ';';
480 }
481
482 *at = '\0';
483 return newStr;
484}
485
486/*
487 * Return a newly-allocated string for the internal-form class name for
488 * the given type descriptor. That is, the initial "L" and final ";" (if
489 * any) have been removed.
490 */
491char* dvmDescriptorToName(const char* str)
492{
493 if (str[0] == 'L') {
494 size_t length = strlen(str) - 1;
495 char* newStr = malloc(length);
496
497 if (newStr == NULL) {
498 return NULL;
499 }
500
501 strlcpy(newStr, str + 1, length);
502 return newStr;
503 }
504
505 return strdup(str);
506}
507
508/*
509 * Return a newly-allocated string for the type descriptor for the given
510 * internal-form class name. That is, a non-array class name will get
511 * surrounded by "L" and ";", while array names are left as-is.
512 */
513char* dvmNameToDescriptor(const char* str)
514{
515 if (str[0] != '[') {
516 size_t length = strlen(str);
517 char* descriptor = malloc(length + 3);
518
519 if (descriptor == NULL) {
520 return NULL;
521 }
522
523 descriptor[0] = 'L';
524 strcpy(descriptor + 1, str);
525 descriptor[length + 1] = ';';
526 descriptor[length + 2] = '\0';
527
528 return descriptor;
529 }
530
531 return strdup(str);
532}
533
534/*
535 * Get a notion of the current time, in nanoseconds. This is meant for
536 * computing durations (e.g. "operation X took 52nsec"), so the result
537 * should not be used to get the current date/time.
538 */
539u8 dvmGetRelativeTimeNsec(void)
540{
541#ifdef HAVE_POSIX_CLOCKS
542 struct timespec now;
543 clock_gettime(CLOCK_MONOTONIC, &now);
544 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
545#else
546 struct timeval now;
547 gettimeofday(&now, NULL);
548 return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
549#endif
550}
551
552/*
553 * Get the per-thread CPU time, in nanoseconds.
554 *
555 * Only useful for time deltas.
556 */
557u8 dvmGetThreadCpuTimeNsec(void)
558{
559#ifdef HAVE_POSIX_CLOCKS
560 struct timespec now;
561 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
562 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
563#else
564 return (u8) -1;
565#endif
566}
567
568/*
569 * Get the per-thread CPU time, in nanoseconds, for the specified thread.
570 */
571u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
572{
573#if 0 /*def HAVE_POSIX_CLOCKS*/
574 int clockId;
575
576 if (pthread_getcpuclockid(thread, &clockId) != 0)
577 return (u8) -1;
578
579 struct timespec now;
580 clock_gettime(clockId, &now);
581 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
582#else
583 return (u8) -1;
584#endif
585}
586
587
588/*
589 * Call this repeatedly, with successively higher values for "iteration",
590 * to sleep for a period of time not to exceed "maxTotalSleep".
591 *
592 * For example, when called with iteration==0 we will sleep for a very
593 * brief time. On the next call we will sleep for a longer time. When
594 * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
595 *
596 * The initial start time value for "relStartTime" MUST come from the
597 * dvmGetRelativeTimeUsec call. On the device this must come from the
598 * monotonic clock source, not the wall clock.
599 *
600 * This should be used wherever you might be tempted to call sched_yield()
601 * in a loop. The problem with sched_yield is that, for a high-priority
602 * thread, the kernel might not actually transfer control elsewhere.
603 *
604 * Returns "false" if we were unable to sleep because our time was up.
605 */
606bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
607{
608 const int minSleep = 10000;
609 u8 curTime;
610 int curDelay;
611
612 /*
613 * Get current time, and see if we've already exceeded the limit.
614 */
615 curTime = dvmGetRelativeTimeUsec();
616 if (curTime >= relStartTime + maxTotalSleep) {
617 LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
618 relStartTime, maxTotalSleep, curTime);
619 return false;
620 }
621
622 /*
623 * Compute current delay. We're bounded by "maxTotalSleep", so no
624 * real risk of overflow assuming "usleep" isn't returning early.
625 * (Besides, 2^30 usec is about 18 minutes by itself.)
626 *
627 * For iteration==0 we just call sched_yield(), so the first sleep
628 * at iteration==1 is actually (minSleep * 2).
629 */
630 curDelay = minSleep;
631 while (iteration-- > 0)
632 curDelay *= 2;
633 assert(curDelay > 0);
634
635 if (curTime + curDelay >= relStartTime + maxTotalSleep) {
636 LOGVV("exsl: reduced delay from %d to %d\n",
637 curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
638 curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
639 }
640
641 if (iteration == 0) {
642 LOGVV("exsl: yield\n");
643 sched_yield();
644 } else {
645 LOGVV("exsl: sleep for %d\n", curDelay);
646 usleep(curDelay);
647 }
648 return true;
649}
650
651
652/*
653 * Set the "close on exec" flag so we don't expose our file descriptors
654 * to processes launched by us.
655 */
656bool dvmSetCloseOnExec(int fd)
657{
658 int flags;
659
660 /*
661 * There's presently only one flag defined, so getting the previous
662 * value of the fd flags is probably unnecessary.
663 */
664 flags = fcntl(fd, F_GETFD);
665 if (flags < 0) {
666 LOGW("Unable to get fd flags for fd %d\n", fd);
667 return false;
668 }
669 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
670 LOGW("Unable to set close-on-exec for fd %d\n", fd);
671 return false;
672 }
673 return true;
674}
675
676#if (!HAVE_STRLCPY)
677/* Implementation of strlcpy() for platforms that don't already have it. */
678size_t strlcpy(char *dst, const char *src, size_t size) {
679 size_t srcLength = strlen(src);
680 size_t copyLength = srcLength;
681
682 if (srcLength > (size - 1)) {
683 copyLength = size - 1;
684 }
685
686 if (size != 0) {
687 strncpy(dst, src, copyLength);
688 dst[copyLength] = '\0';
689 }
690
691 return srcLength;
692}
693#endif
Barry Hayes6e5cf602010-06-22 12:32:59 -0700694
695/*
696 * Allocates a memory region using ashmem and mmap, initialized to
697 * zero. Actual allocation rounded up to page multiple. Returns
698 * NULL on failure.
699 */
700void *dvmAllocRegion(size_t size, int prot, const char *name) {
701 void *base;
702 int fd, ret;
703
704 size = ALIGN_UP_TO_PAGE_SIZE(size);
705 fd = ashmem_create_region(name, size);
706 if (fd == -1) {
707 return NULL;
708 }
709 base = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0);
710 ret = close(fd);
711 if (base == MAP_FAILED) {
712 return NULL;
713 }
714 if (ret == -1) {
715 return NULL;
716 }
717 return base;
718}
Andy McFadden0a3f6982010-08-31 13:50:08 -0700719
Andy McFadden0a3f6982010-08-31 13:50:08 -0700720/*
721 * Get some per-thread stats.
722 *
723 * This is currently generated by opening the appropriate "stat" file
724 * in /proc and reading the pile of stuff that comes out.
725 */
726bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
727{
728 /*
729 int pid;
730 char comm[128];
731 char state;
732 int ppid, pgrp, session, tty_nr, tpgid;
733 unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
734 long cutime, cstime, priority, nice, zero, itrealvalue;
735 unsigned long starttime, vsize;
736 long rss;
737 unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
738 unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
739 int exit_signal, processor;
740 unsigned long rt_priority, policy;
741
742 scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
743 "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
744 "%lu %lu %lu %d %d %lu %lu",
745 &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
746 &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
747 &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
748 &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
749 &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
750 &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
751 &rt_priority, &policy);
752
753 (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
754 */
755
756 char nameBuf[64];
757 int i, fd;
758
759 /*
760 * Open and read the appropriate file. This is expected to work on
761 * Linux but will fail on other platforms (e.g. Mac sim).
762 */
763 sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
764 fd = open(nameBuf, O_RDONLY);
765 if (fd < 0) {
766 LOGV("Unable to open '%s': %s\n", nameBuf, strerror(errno));
767 return false;
768 }
769
770 char lineBuf[512]; /* > 2x typical */
771 int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
772 if (cc <= 0) {
773 const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
774 LOGI("Unable to read '%s': %s\n", nameBuf, msg);
775 close(fd);
776 return false;
777 }
778 close(fd);
779 lineBuf[cc] = '\0';
780
781 /*
782 * Skip whitespace-separated tokens. For the most part we can assume
783 * that tokens do not contain spaces, and are separated by exactly one
784 * space character. The only exception is the second field ("comm")
785 * which may contain spaces but is surrounded by parenthesis.
786 */
787 char* cp = strchr(lineBuf, ')');
788 if (cp == NULL)
789 goto parse_fail;
790 cp++;
791 for (i = 2; i < 13; i++) {
792 cp = strchr(cp+1, ' ');
793 if (cp == NULL)
794 goto parse_fail;
795 }
796
797 /*
798 * Grab utime/stime.
799 */
800 char* endp;
801 pData->utime = strtoul(cp+1, &endp, 10);
802 if (endp == cp+1)
803 LOGI("Warning: strtoul failed on utime ('%.30s...')\n", cp);
804
805 cp = strchr(cp+1, ' ');
806 if (cp == NULL)
807 goto parse_fail;
808
809 pData->stime = strtoul(cp+1, &endp, 10);
810 if (endp == cp+1)
811 LOGI("Warning: strtoul failed on stime ('%.30s...')\n", cp);
812
813 /*
814 * Skip more stuff we don't care about.
815 */
816 for (i = 14; i < 38; i++) {
817 cp = strchr(cp+1, ' ');
818 if (cp == NULL)
819 goto parse_fail;
820 }
821
822 /*
823 * Grab processor number.
824 */
825 pData->processor = strtol(cp+1, &endp, 10);
826 if (endp == cp+1)
827 LOGI("Warning: strtoul failed on processor ('%.30s...')\n", cp);
828
829 return true;
830
831parse_fail:
832 LOGI("stat parse failed (%s)\n", lineBuf);
833 return false;
834}
Dan Bornsteinbbf9d732010-09-15 13:13:33 -0700835
Dan Bornstein32bc0782010-09-13 17:30:10 -0700836/* documented in header file */
837const char* dvmPathToAbsolutePortion(const char* path) {
838 if (path == NULL) {
839 return NULL;
840 }
841
842 if (path[0] == '/') {
843 /* It's a regular absolute path. Return it. */
844 return path;
845 }
846
847 const char* sentinel = strstr(path, "/./");
848
849 if (sentinel != NULL) {
850 /* It's got the sentinel. Return a pointer to the second slash. */
851 return sentinel + 2;
852 }
853
854 return NULL;
855}