2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Miscellaneous utility functions.
31 * Print a hex dump in this format:
33 01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef\n
35 * If "mode" is kHexDumpLocal, we start at offset zero, and show a full
36 * 16 bytes on the first line. If it's kHexDumpMem, we make this look
37 * like a memory dump, using the actual address, outputting a partial line
38 * if "vaddr" isn't aligned on a 16-byte boundary.
40 * "priority" and "tag" determine the values passed to the log calls.
42 * Does not use printf() or other string-formatting calls.
44 void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
45 size_t length, HexDumpMode mode)
47 static const char gHexDigit[] = "0123456789abcdef";
48 const unsigned char* addr = vaddr;
49 char out[77]; /* exact fit */
50 unsigned int offset; /* offset to show while printing */
56 if (mode == kHexDumpLocal)
61 memset(out, ' ', sizeof(out)-1);
63 out[sizeof(out)-2] = '\n';
64 out[sizeof(out)-1] = '\0';
66 gap = (int) offset & 0x0f;
68 unsigned int lineOffset = offset & ~0x0f;
74 for (i = 0; i < 8; i++) {
75 *hex++ = gHexDigit[lineOffset >> 28];
81 count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */
83 assert(count+gap <= 16);
86 /* only on first line */
91 for (i = gap ; i < count+gap; i++) {
92 *hex++ = gHexDigit[*addr >> 4];
93 *hex++ = gHexDigit[*addr & 0x0f];
95 if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/)
101 for ( ; i < 16; i++) {
102 /* erase extra stuff; only happens on last line */
109 LOG_PRI(priority, tag, "%s", out);
110 #if 0 //def HAVE_ANDROID_OS
112 * We can overrun logcat easily by writing at full speed. On the
113 * other hand, we can make Eclipse time out if we're showing
114 * packet dumps while debugging JDWP.
117 if (trickle++ == 8) {
132 * Fill out a DebugOutputTarget, suitable for printing to the log.
134 void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
137 assert(target != NULL);
140 target->which = kDebugTargetLog;
141 target->data.log.priority = priority;
142 target->data.log.tag = tag;
146 * Fill out a DebugOutputTarget suitable for printing to a file pointer.
148 void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp)
150 assert(target != NULL);
153 target->which = kDebugTargetFile;
154 target->data.file.fp = fp;
158 * Free "target" and any associated data.
160 void dvmFreeOutputTarget(DebugOutputTarget* target)
166 * Print a debug message, to either a file or the log.
168 void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
173 va_start(args, format);
175 switch (target->which) {
176 case kDebugTargetLog:
177 LOG_PRI_VA(target->data.log.priority, target->data.log.tag,
180 case kDebugTargetFile:
181 vfprintf(target->data.file.fp, format, args);
184 LOGE("unexpected 'which' %d\n", target->which);
193 * Allocate a bit vector with enough space to hold at least the specified
196 BitVector* dvmAllocBitVector(int startBits, bool expandable)
201 assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */
202 assert(startBits >= 0);
204 bv = (BitVector*) malloc(sizeof(BitVector));
206 count = (startBits + 31) >> 5;
208 bv->storageSize = count;
209 bv->expandable = expandable;
210 bv->storage = (u4*) malloc(count * sizeof(u4));
211 memset(bv->storage, 0x00, count * sizeof(u4));
218 void dvmFreeBitVector(BitVector* pBits)
223 free(pBits->storage);
228 * "Allocate" the first-available bit in the bitmap.
230 * This is not synchronized. The caller is expected to hold some sort of
231 * lock that prevents multiple threads from executing simultaneously in
232 * dvmAllocBit/dvmFreeBit.
234 int dvmAllocBit(BitVector* pBits)
239 for (word = 0; word < pBits->storageSize; word++) {
240 if (pBits->storage[word] != 0xffffffff) {
242 * There are unallocated bits in this word. Return the first.
244 bit = ffs(~(pBits->storage[word])) -1;
245 assert(bit >= 0 && bit < 32);
246 pBits->storage[word] |= 1 << bit;
247 return (word << 5) | bit;
252 * Ran out of space, allocate more if we're allowed to.
254 if (!pBits->expandable)
257 pBits->storage = realloc(pBits->storage,
258 (pBits->storageSize + kBitVectorGrowth) * sizeof(u4));
259 memset(&pBits->storage[pBits->storageSize], 0x00,
260 kBitVectorGrowth * sizeof(u4));
261 pBits->storageSize += kBitVectorGrowth;
266 * Mark the specified bit as "set".
268 * Returns "false" if the bit is outside the range of the vector and we're
269 * not allowed to expand.
271 bool dvmSetBit(BitVector* pBits, int num)
274 if (num >= pBits->storageSize * (int)sizeof(u4) * 8) {
275 if (!pBits->expandable)
278 int newSize = (num + 31) >> 5;
279 assert(newSize > pBits->storageSize);
280 pBits->storage = realloc(pBits->storage, newSize * sizeof(u4));
281 memset(&pBits->storage[pBits->storageSize], 0x00,
282 (newSize - pBits->storageSize) * sizeof(u4));
283 pBits->storageSize = newSize;
286 pBits->storage[num >> 5] |= 1 << (num & 0x1f);
291 * Mark the specified bit as "clear".
293 void dvmClearBit(BitVector* pBits, int num)
295 assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
297 pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
301 * Mark all bits bit as "clear".
303 void dvmClearAllBits(BitVector* pBits)
305 int count = pBits->storageSize;
306 memset(pBits->storage, 0, count * sizeof(u4));
310 * Determine whether or not the specified bit is set.
312 bool dvmIsBitSet(const BitVector* pBits, int num)
314 assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
316 int val = pBits->storage[num >> 5] & (1 << (num & 0x1f));
321 * Count the number of bits that are set.
323 int dvmCountSetBits(const BitVector* pBits)
328 for (word = 0; word < pBits->storageSize; word++) {
329 u4 val = pBits->storage[word];
332 if (val == 0xffffffff) {
335 /* count the number of '1' bits */
348 * Return a newly-allocated string in which all occurrences of '.' have
349 * been changed to '/'. If we find a '/' in the original string, NULL
350 * is returned to avoid ambiguity.
352 char* dvmDotToSlash(const char* str)
354 char* newStr = strdup(str);
357 while (*cp != '\0') {
371 * Return a newly-allocated string for the "dot version" of the class
372 * name for the given type descriptor. That is, The initial "L" and
373 * final ";" (if any) have been removed and all occurrences of '/'
374 * have been changed to '.'.
376 char* dvmDescriptorToDot(const char* str)
378 size_t at = strlen(str);
381 if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
382 at -= 2; /* Two fewer chars to copy. */
383 str++; /* Skip the 'L'. */
386 newStr = malloc(at + 1); /* Add one for the '\0'. */
391 newStr[at] = (str[at] == '/') ? '.' : str[at];
398 * Return a newly-allocated string for the type descriptor
399 * corresponding to the "dot version" of the given class name. That
400 * is, non-array names are surrounded by "L" and ";", and all
401 * occurrences of '.' are changed to '/'.
403 char* dvmDotToDescriptor(const char* str)
405 size_t length = strlen(str);
411 length += 2; /* for "L" and ";" */
415 newStr = at = malloc(length + 1); /* + 1 for the '\0' */
417 if (newStr == NULL) {
442 * Return a newly-allocated string for the internal-form class name for
443 * the given type descriptor. That is, the initial "L" and final ";" (if
444 * any) have been removed.
446 char* dvmDescriptorToName(const char* str)
449 size_t length = strlen(str) - 1;
450 char* newStr = malloc(length);
452 if (newStr == NULL) {
456 strlcpy(newStr, str + 1, length);
464 * Return a newly-allocated string for the type descriptor for the given
465 * internal-form class name. That is, a non-array class name will get
466 * surrounded by "L" and ";", while array names are left as-is.
468 char* dvmNameToDescriptor(const char* str)
471 size_t length = strlen(str);
472 char* descriptor = malloc(length + 3);
474 if (descriptor == NULL) {
479 strcpy(descriptor + 1, str);
480 descriptor[length + 1] = ';';
481 descriptor[length + 2] = '\0';
490 * Get a notion of the current time, in nanoseconds. This is meant for
491 * computing durations (e.g. "operation X took 52nsec"), so the result
492 * should not be used to get the current date/time.
494 u8 dvmGetRelativeTimeNsec(void)
496 #ifdef HAVE_POSIX_CLOCKS
498 clock_gettime(CLOCK_MONOTONIC, &now);
499 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
502 gettimeofday(&now, NULL);
503 return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
508 * Get the per-thread CPU time, in nanoseconds.
510 * Only useful for time deltas.
512 u8 dvmGetThreadCpuTimeNsec(void)
514 #ifdef HAVE_POSIX_CLOCKS
516 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
517 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
524 * Get the per-thread CPU time, in nanoseconds, for the specified thread.
526 u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
528 #if 0 /*def HAVE_POSIX_CLOCKS*/
531 if (pthread_getcpuclockid(thread, &clockId) != 0)
535 clock_gettime(clockId, &now);
536 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
544 * Call this repeatedly, with successively higher values for "iteration",
545 * to sleep for a period of time not to exceed "maxTotalSleep".
547 * For example, when called with iteration==0 we will sleep for a very
548 * brief time. On the next call we will sleep for a longer time. When
549 * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
551 * The initial start time value for "relStartTime" MUST come from the
552 * dvmGetRelativeTimeUsec call. On the device this must come from the
553 * monotonic clock source, not the wall clock.
555 * This should be used wherever you might be tempted to call sched_yield()
556 * in a loop. The problem with sched_yield is that, for a high-priority
557 * thread, the kernel might not actually transfer control elsewhere.
559 * Returns "false" if we were unable to sleep because our time was up.
561 bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
563 const int minSleep = 10000;
568 * Get current time, and see if we've already exceeded the limit.
570 curTime = dvmGetRelativeTimeUsec();
571 if (curTime >= relStartTime + maxTotalSleep) {
572 LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
573 relStartTime, maxTotalSleep, curTime);
578 * Compute current delay. We're bounded by "maxTotalSleep", so no
579 * real risk of overflow assuming "usleep" isn't returning early.
580 * (Besides, 2^30 usec is about 18 minutes by itself.)
582 * For iteration==0 we just call sched_yield(), so the first sleep
583 * at iteration==1 is actually (minSleep * 2).
586 while (iteration-- > 0)
588 assert(curDelay > 0);
590 if (curTime + curDelay >= relStartTime + maxTotalSleep) {
591 LOGVV("exsl: reduced delay from %d to %d\n",
592 curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
593 curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
596 if (iteration == 0) {
597 LOGVV("exsl: yield\n");
600 LOGVV("exsl: sleep for %d\n", curDelay);
608 * Set the "close on exec" flag so we don't expose our file descriptors
609 * to processes launched by us.
611 bool dvmSetCloseOnExec(int fd)
616 * There's presently only one flag defined, so getting the previous
617 * value of the fd flags is probably unnecessary.
619 flags = fcntl(fd, F_GETFD);
621 LOGW("Unable to get fd flags for fd %d\n", fd);
624 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
625 LOGW("Unable to set close-on-exec for fd %d\n", fd);
632 /* Implementation of strlcpy() for platforms that don't already have it. */
633 size_t strlcpy(char *dst, const char *src, size_t size) {
634 size_t srcLength = strlen(src);
635 size_t copyLength = srcLength;
637 if (srcLength > (size - 1)) {
638 copyLength = size - 1;
642 strncpy(dst, src, copyLength);
643 dst[copyLength] = '\0';