blob: 21b7fcef6789a0acd53c05cc0f39a015d7f6bc9d [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>
29
30
31/*
32 * Print a hex dump in this format:
33 *
3401234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef\n
35 *
36 * If "mode" is kHexDumpLocal, we start at offset zero, and show a full
37 * 16 bytes on the first line. If it's kHexDumpMem, we make this look
38 * like a memory dump, using the actual address, outputting a partial line
39 * if "vaddr" isn't aligned on a 16-byte boundary.
40 *
41 * "priority" and "tag" determine the values passed to the log calls.
42 *
43 * Does not use printf() or other string-formatting calls.
44 */
45void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
46 size_t length, HexDumpMode mode)
47{
48 static const char gHexDigit[] = "0123456789abcdef";
49 const unsigned char* addr = vaddr;
50 char out[77]; /* exact fit */
51 unsigned int offset; /* offset to show while printing */
52 char* hex;
53 char* asc;
54 int gap;
55 //int trickle = 0;
56
57 if (mode == kHexDumpLocal)
58 offset = 0;
59 else
60 offset = (int) addr;
61
62 memset(out, ' ', sizeof(out)-1);
63 out[8] = ':';
64 out[sizeof(out)-2] = '\n';
65 out[sizeof(out)-1] = '\0';
66
67 gap = (int) offset & 0x0f;
68 while (length) {
69 unsigned int lineOffset = offset & ~0x0f;
70 int i, count;
71
72 hex = out;
73 asc = out + 59;
74
75 for (i = 0; i < 8; i++) {
76 *hex++ = gHexDigit[lineOffset >> 28];
77 lineOffset <<= 4;
78 }
79 hex++;
80 hex++;
81
82 count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */
83 assert(count != 0);
84 assert(count+gap <= 16);
85
86 if (gap) {
87 /* only on first line */
88 hex += gap * 3;
89 asc += gap;
90 }
91
92 for (i = gap ; i < count+gap; i++) {
93 *hex++ = gHexDigit[*addr >> 4];
94 *hex++ = gHexDigit[*addr & 0x0f];
95 hex++;
96 if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/)
97 *asc++ = *addr;
98 else
99 *asc++ = '.';
100 addr++;
101 }
102 for ( ; i < 16; i++) {
103 /* erase extra stuff; only happens on last line */
104 *hex++ = ' ';
105 *hex++ = ' ';
106 hex++;
107 *asc++ = ' ';
108 }
109
110 LOG_PRI(priority, tag, "%s", out);
111#if 0 //def HAVE_ANDROID_OS
112 /*
113 * We can overrun logcat easily by writing at full speed. On the
114 * other hand, we can make Eclipse time out if we're showing
115 * packet dumps while debugging JDWP.
116 */
117 {
118 if (trickle++ == 8) {
119 trickle = 0;
120 usleep(20000);
121 }
122 }
123#endif
124
125 gap = 0;
126 length -= count;
127 offset += count;
128 }
129}
130
131
132/*
133 * Fill out a DebugOutputTarget, suitable for printing to the log.
134 */
135void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
136 const char* tag)
137{
138 assert(target != NULL);
139 assert(tag != NULL);
140
141 target->which = kDebugTargetLog;
142 target->data.log.priority = priority;
143 target->data.log.tag = tag;
144}
145
146/*
147 * Fill out a DebugOutputTarget suitable for printing to a file pointer.
148 */
149void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp)
150{
151 assert(target != NULL);
152 assert(fp != NULL);
153
154 target->which = kDebugTargetFile;
155 target->data.file.fp = fp;
156}
157
158/*
159 * Free "target" and any associated data.
160 */
161void dvmFreeOutputTarget(DebugOutputTarget* target)
162{
163 free(target);
164}
165
166/*
167 * Print a debug message, to either a file or the log.
168 */
169void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
170 ...)
171{
172 va_list args;
173
174 va_start(args, format);
175
176 switch (target->which) {
177 case kDebugTargetLog:
178 LOG_PRI_VA(target->data.log.priority, target->data.log.tag,
179 format, args);
180 break;
181 case kDebugTargetFile:
182 vfprintf(target->data.file.fp, format, args);
183 break;
184 default:
185 LOGE("unexpected 'which' %d\n", target->which);
186 break;
187 }
188
189 va_end(args);
190}
191
192
193/*
194 * Allocate a bit vector with enough space to hold at least the specified
195 * number of bits.
196 */
197BitVector* dvmAllocBitVector(int startBits, bool expandable)
198{
199 BitVector* bv;
200 int count;
201
202 assert(sizeof(bv->storage[0]) == 4); /* assuming 32-bit units */
203 assert(startBits >= 0);
204
205 bv = (BitVector*) malloc(sizeof(BitVector));
206
207 count = (startBits + 31) >> 5;
208
209 bv->storageSize = count;
210 bv->expandable = expandable;
211 bv->storage = (u4*) malloc(count * sizeof(u4));
212 memset(bv->storage, 0x00, count * sizeof(u4));
213 return bv;
214}
215
216/*
217 * Free a BitVector.
218 */
219void dvmFreeBitVector(BitVector* pBits)
220{
221 if (pBits == NULL)
222 return;
223
224 free(pBits->storage);
225 free(pBits);
226}
227
228/*
229 * "Allocate" the first-available bit in the bitmap.
230 *
231 * This is not synchronized. The caller is expected to hold some sort of
232 * lock that prevents multiple threads from executing simultaneously in
233 * dvmAllocBit/dvmFreeBit.
234 */
235int dvmAllocBit(BitVector* pBits)
236{
237 int word, bit;
238
239retry:
240 for (word = 0; word < pBits->storageSize; word++) {
241 if (pBits->storage[word] != 0xffffffff) {
242 /*
243 * There are unallocated bits in this word. Return the first.
244 */
245 bit = ffs(~(pBits->storage[word])) -1;
246 assert(bit >= 0 && bit < 32);
247 pBits->storage[word] |= 1 << bit;
248 return (word << 5) | bit;
249 }
250 }
251
252 /*
253 * Ran out of space, allocate more if we're allowed to.
254 */
255 if (!pBits->expandable)
256 return -1;
257
258 pBits->storage = realloc(pBits->storage,
259 (pBits->storageSize + kBitVectorGrowth) * sizeof(u4));
260 memset(&pBits->storage[pBits->storageSize], 0x00,
261 kBitVectorGrowth * sizeof(u4));
262 pBits->storageSize += kBitVectorGrowth;
263 goto retry;
264}
265
266/*
267 * Mark the specified bit as "set".
268 *
269 * Returns "false" if the bit is outside the range of the vector and we're
270 * not allowed to expand.
271 */
272bool dvmSetBit(BitVector* pBits, int num)
273{
274 assert(num >= 0);
275 if (num >= pBits->storageSize * (int)sizeof(u4) * 8) {
276 if (!pBits->expandable)
277 return false;
278
279 int newSize = (num + 31) >> 5;
280 assert(newSize > pBits->storageSize);
281 pBits->storage = realloc(pBits->storage, newSize * sizeof(u4));
282 memset(&pBits->storage[pBits->storageSize], 0x00,
283 (newSize - pBits->storageSize) * sizeof(u4));
Andy McFadden01651b42009-08-19 10:32:01 -0700284 pBits->storageSize = newSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800285 }
286
287 pBits->storage[num >> 5] |= 1 << (num & 0x1f);
288 return true;
289}
290
291/*
292 * Mark the specified bit as "clear".
293 */
294void dvmClearBit(BitVector* pBits, int num)
295{
296 assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
297
298 pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
299}
300
301/*
Ben Chenge9695e52009-06-16 16:11:47 -0700302 * Mark all bits bit as "clear".
303 */
304void dvmClearAllBits(BitVector* pBits)
305{
306 int count = pBits->storageSize;
307 memset(pBits->storage, 0, count * sizeof(u4));
308}
309
310/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800311 * Determine whether or not the specified bit is set.
312 */
313bool dvmIsBitSet(const BitVector* pBits, int num)
314{
315 assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
316
317 int val = pBits->storage[num >> 5] & (1 << (num & 0x1f));
318 return (val != 0);
319}
320
321/*
322 * Count the number of bits that are set.
323 */
324int dvmCountSetBits(const BitVector* pBits)
325{
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700326 int word;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800327 int count = 0;
328
329 for (word = 0; word < pBits->storageSize; word++) {
330 u4 val = pBits->storage[word];
331
332 if (val != 0) {
333 if (val == 0xffffffff) {
334 count += 32;
335 } else {
336 /* count the number of '1' bits */
337 while (val != 0) {
338 val &= val - 1;
339 count++;
340 }
341 }
342 }
343 }
344
345 return count;
346}
347
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800348/*
Ben Cheng4238ec22009-08-24 16:32:22 -0700349 * Copy a whole vector to the other. Only do that when the both vectors have
350 * the same size and attribute.
351 */
352bool dvmCopyBitVector(BitVector *dest, const BitVector *src)
353{
354 if (dest->storageSize != src->storageSize ||
355 dest->expandable != src->expandable)
356 return false;
357 memcpy(dest->storage, src->storage, sizeof(u4) * dest->storageSize);
358 return true;
359}
360
361/*
362 * Intersect two bit vectores and merge the result on top of the pre-existing
363 * value in the dest vector.
364 */
365bool dvmIntersectBitVectors(BitVector *dest, const BitVector *src1,
366 const BitVector *src2)
367{
368 if (dest->storageSize != src1->storageSize ||
369 dest->storageSize != src2->storageSize ||
370 dest->expandable != src1->expandable ||
371 dest->expandable != src2->expandable)
372 return false;
373
374 int i;
375 for (i = 0; i < dest->storageSize; i++) {
376 dest->storage[i] |= src1->storage[i] & src2->storage[i];
377 }
378 return true;
379}
380
381/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800382 * Return a newly-allocated string in which all occurrences of '.' have
383 * been changed to '/'. If we find a '/' in the original string, NULL
384 * is returned to avoid ambiguity.
385 */
386char* dvmDotToSlash(const char* str)
387{
388 char* newStr = strdup(str);
389 char* cp = newStr;
390
Andy McFaddenf9058532009-09-03 14:48:10 -0700391 if (newStr == NULL)
392 return NULL;
393
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800394 while (*cp != '\0') {
395 if (*cp == '/') {
396 assert(false);
397 return NULL;
398 }
399 if (*cp == '.')
400 *cp = '/';
401 cp++;
402 }
403
404 return newStr;
405}
406
407/*
408 * Return a newly-allocated string for the "dot version" of the class
409 * name for the given type descriptor. That is, The initial "L" and
410 * final ";" (if any) have been removed and all occurrences of '/'
411 * have been changed to '.'.
412 */
413char* dvmDescriptorToDot(const char* str)
414{
415 size_t at = strlen(str);
416 char* newStr;
417
418 if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
419 at -= 2; /* Two fewer chars to copy. */
420 str++; /* Skip the 'L'. */
421 }
422
423 newStr = malloc(at + 1); /* Add one for the '\0'. */
Andy McFaddenf9058532009-09-03 14:48:10 -0700424 if (newStr == NULL)
425 return NULL;
426
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800427 newStr[at] = '\0';
428
429 while (at > 0) {
430 at--;
431 newStr[at] = (str[at] == '/') ? '.' : str[at];
432 }
433
434 return newStr;
435}
436
437/*
438 * Return a newly-allocated string for the type descriptor
439 * corresponding to the "dot version" of the given class name. That
440 * is, non-array names are surrounded by "L" and ";", and all
441 * occurrences of '.' are changed to '/'.
442 */
443char* dvmDotToDescriptor(const char* str)
444{
445 size_t length = strlen(str);
446 int wrapElSemi = 0;
447 char* newStr;
448 char* at;
449
450 if (str[0] != '[') {
451 length += 2; /* for "L" and ";" */
452 wrapElSemi = 1;
453 }
454
455 newStr = at = malloc(length + 1); /* + 1 for the '\0' */
456
457 if (newStr == NULL) {
458 return NULL;
459 }
460
461 if (wrapElSemi) {
462 *(at++) = 'L';
463 }
464
465 while (*str) {
466 char c = *(str++);
467 if (c == '.') {
468 c = '/';
469 }
470 *(at++) = c;
471 }
472
473 if (wrapElSemi) {
474 *(at++) = ';';
475 }
476
477 *at = '\0';
478 return newStr;
479}
480
481/*
482 * Return a newly-allocated string for the internal-form class name for
483 * the given type descriptor. That is, the initial "L" and final ";" (if
484 * any) have been removed.
485 */
486char* dvmDescriptorToName(const char* str)
487{
488 if (str[0] == 'L') {
489 size_t length = strlen(str) - 1;
490 char* newStr = malloc(length);
491
492 if (newStr == NULL) {
493 return NULL;
494 }
495
496 strlcpy(newStr, str + 1, length);
497 return newStr;
498 }
499
500 return strdup(str);
501}
502
503/*
504 * Return a newly-allocated string for the type descriptor for the given
505 * internal-form class name. That is, a non-array class name will get
506 * surrounded by "L" and ";", while array names are left as-is.
507 */
508char* dvmNameToDescriptor(const char* str)
509{
510 if (str[0] != '[') {
511 size_t length = strlen(str);
512 char* descriptor = malloc(length + 3);
513
514 if (descriptor == NULL) {
515 return NULL;
516 }
517
518 descriptor[0] = 'L';
519 strcpy(descriptor + 1, str);
520 descriptor[length + 1] = ';';
521 descriptor[length + 2] = '\0';
522
523 return descriptor;
524 }
525
526 return strdup(str);
527}
528
529/*
530 * Get a notion of the current time, in nanoseconds. This is meant for
531 * computing durations (e.g. "operation X took 52nsec"), so the result
532 * should not be used to get the current date/time.
533 */
534u8 dvmGetRelativeTimeNsec(void)
535{
536#ifdef HAVE_POSIX_CLOCKS
537 struct timespec now;
538 clock_gettime(CLOCK_MONOTONIC, &now);
539 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
540#else
541 struct timeval now;
542 gettimeofday(&now, NULL);
543 return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
544#endif
545}
546
547/*
548 * Get the per-thread CPU time, in nanoseconds.
549 *
550 * Only useful for time deltas.
551 */
552u8 dvmGetThreadCpuTimeNsec(void)
553{
554#ifdef HAVE_POSIX_CLOCKS
555 struct timespec now;
556 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
557 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
558#else
559 return (u8) -1;
560#endif
561}
562
563/*
564 * Get the per-thread CPU time, in nanoseconds, for the specified thread.
565 */
566u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
567{
568#if 0 /*def HAVE_POSIX_CLOCKS*/
569 int clockId;
570
571 if (pthread_getcpuclockid(thread, &clockId) != 0)
572 return (u8) -1;
573
574 struct timespec now;
575 clock_gettime(clockId, &now);
576 return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
577#else
578 return (u8) -1;
579#endif
580}
581
582
583/*
584 * Call this repeatedly, with successively higher values for "iteration",
585 * to sleep for a period of time not to exceed "maxTotalSleep".
586 *
587 * For example, when called with iteration==0 we will sleep for a very
588 * brief time. On the next call we will sleep for a longer time. When
589 * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
590 *
591 * The initial start time value for "relStartTime" MUST come from the
592 * dvmGetRelativeTimeUsec call. On the device this must come from the
593 * monotonic clock source, not the wall clock.
594 *
595 * This should be used wherever you might be tempted to call sched_yield()
596 * in a loop. The problem with sched_yield is that, for a high-priority
597 * thread, the kernel might not actually transfer control elsewhere.
598 *
599 * Returns "false" if we were unable to sleep because our time was up.
600 */
601bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
602{
603 const int minSleep = 10000;
604 u8 curTime;
605 int curDelay;
606
607 /*
608 * Get current time, and see if we've already exceeded the limit.
609 */
610 curTime = dvmGetRelativeTimeUsec();
611 if (curTime >= relStartTime + maxTotalSleep) {
612 LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
613 relStartTime, maxTotalSleep, curTime);
614 return false;
615 }
616
617 /*
618 * Compute current delay. We're bounded by "maxTotalSleep", so no
619 * real risk of overflow assuming "usleep" isn't returning early.
620 * (Besides, 2^30 usec is about 18 minutes by itself.)
621 *
622 * For iteration==0 we just call sched_yield(), so the first sleep
623 * at iteration==1 is actually (minSleep * 2).
624 */
625 curDelay = minSleep;
626 while (iteration-- > 0)
627 curDelay *= 2;
628 assert(curDelay > 0);
629
630 if (curTime + curDelay >= relStartTime + maxTotalSleep) {
631 LOGVV("exsl: reduced delay from %d to %d\n",
632 curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
633 curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
634 }
635
636 if (iteration == 0) {
637 LOGVV("exsl: yield\n");
638 sched_yield();
639 } else {
640 LOGVV("exsl: sleep for %d\n", curDelay);
641 usleep(curDelay);
642 }
643 return true;
644}
645
646
647/*
648 * Set the "close on exec" flag so we don't expose our file descriptors
649 * to processes launched by us.
650 */
651bool dvmSetCloseOnExec(int fd)
652{
653 int flags;
654
655 /*
656 * There's presently only one flag defined, so getting the previous
657 * value of the fd flags is probably unnecessary.
658 */
659 flags = fcntl(fd, F_GETFD);
660 if (flags < 0) {
661 LOGW("Unable to get fd flags for fd %d\n", fd);
662 return false;
663 }
664 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
665 LOGW("Unable to set close-on-exec for fd %d\n", fd);
666 return false;
667 }
668 return true;
669}
670
671#if (!HAVE_STRLCPY)
672/* Implementation of strlcpy() for platforms that don't already have it. */
673size_t strlcpy(char *dst, const char *src, size_t size) {
674 size_t srcLength = strlen(src);
675 size_t copyLength = srcLength;
676
677 if (srcLength > (size - 1)) {
678 copyLength = size - 1;
679 }
680
681 if (size != 0) {
682 strncpy(dst, src, copyLength);
683 dst[copyLength] = '\0';
684 }
685
686 return srcLength;
687}
688#endif