OSDN Git Service

Merge change 21907 into eclair
[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 <ctype.h>
25 #include <time.h>
26 #include <sys/time.h>
27 #include <fcntl.h>
28
29
30 /*
31  * Print a hex dump in this format:
32  *
33 01234567: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff  0123456789abcdef\n
34  *
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.
39  *
40  * "priority" and "tag" determine the values passed to the log calls.
41  *
42  * Does not use printf() or other string-formatting calls.
43  */
44 void dvmPrintHexDumpEx(int priority, const char* tag, const void* vaddr,
45     size_t length, HexDumpMode mode)
46 {
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 */
51     char* hex;
52     char* asc;
53     int gap;
54     //int trickle = 0;
55
56     if (mode == kHexDumpLocal)
57         offset = 0;
58     else
59         offset = (int) addr;
60
61     memset(out, ' ', sizeof(out)-1);
62     out[8] = ':';
63     out[sizeof(out)-2] = '\n';
64     out[sizeof(out)-1] = '\0';
65
66     gap = (int) offset & 0x0f;
67     while (length) {
68         unsigned int lineOffset = offset & ~0x0f;
69         int i, count;
70
71         hex = out;
72         asc = out + 59;
73
74         for (i = 0; i < 8; i++) {
75             *hex++ = gHexDigit[lineOffset >> 28];
76             lineOffset <<= 4;
77         }
78         hex++;
79         hex++;
80
81         count = ((int)length > 16-gap) ? 16-gap : (int)length; /* cap length */
82         assert(count != 0);
83         assert(count+gap <= 16);
84
85         if (gap) {
86             /* only on first line */
87             hex += gap * 3;
88             asc += gap;
89         }
90
91         for (i = gap ; i < count+gap; i++) {
92             *hex++ = gHexDigit[*addr >> 4];
93             *hex++ = gHexDigit[*addr & 0x0f];
94             hex++;
95             if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/)
96                 *asc++ = *addr;
97             else
98                 *asc++ = '.';
99             addr++;
100         }
101         for ( ; i < 16; i++) {
102             /* erase extra stuff; only happens on last line */
103             *hex++ = ' ';
104             *hex++ = ' ';
105             hex++;
106             *asc++ = ' ';
107         }
108
109         LOG_PRI(priority, tag, "%s", out);
110 #if 0 //def HAVE_ANDROID_OS
111         /*
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.
115          */
116         {
117             if (trickle++ == 8) {
118                 trickle = 0;
119                 usleep(20000);
120             }
121         }
122 #endif
123
124         gap = 0;
125         length -= count;
126         offset += count;
127     }
128 }
129
130
131 /*
132  * Fill out a DebugOutputTarget, suitable for printing to the log.
133  */
134 void dvmCreateLogOutputTarget(DebugOutputTarget* target, int priority,
135     const char* tag)
136 {
137     assert(target != NULL);
138     assert(tag != NULL);
139
140     target->which = kDebugTargetLog;
141     target->data.log.priority = priority;
142     target->data.log.tag = tag;
143 }
144
145 /*
146  * Fill out a DebugOutputTarget suitable for printing to a file pointer.
147  */
148 void dvmCreateFileOutputTarget(DebugOutputTarget* target, FILE* fp)
149 {
150     assert(target != NULL);
151     assert(fp != NULL);
152
153     target->which = kDebugTargetFile;
154     target->data.file.fp = fp;
155 }
156
157 /*
158  * Free "target" and any associated data.
159  */
160 void dvmFreeOutputTarget(DebugOutputTarget* target)
161 {
162     free(target);
163 }
164
165 /*
166  * Print a debug message, to either a file or the log.
167  */
168 void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
169     ...)
170 {
171     va_list args;
172
173     va_start(args, format);
174
175     switch (target->which) {
176     case kDebugTargetLog:
177         LOG_PRI_VA(target->data.log.priority, target->data.log.tag,
178             format, args);
179         break;
180     case kDebugTargetFile:
181         vfprintf(target->data.file.fp, format, args);
182         break;
183     default:
184         LOGE("unexpected 'which' %d\n", target->which);
185         break;
186     }
187
188     va_end(args);
189 }
190
191
192 /*
193  * Allocate a bit vector with enough space to hold at least the specified
194  * number of bits.
195  */
196 BitVector* dvmAllocBitVector(int startBits, bool expandable)
197 {
198     BitVector* bv;
199     int count;
200
201     assert(sizeof(bv->storage[0]) == 4);        /* assuming 32-bit units */
202     assert(startBits >= 0);
203
204     bv = (BitVector*) malloc(sizeof(BitVector));
205
206     count = (startBits + 31) >> 5;
207
208     bv->storageSize = count;
209     bv->expandable = expandable;
210     bv->storage = (u4*) malloc(count * sizeof(u4));
211     memset(bv->storage, 0x00, count * sizeof(u4));
212     return bv;
213 }
214
215 /*
216  * Free a BitVector.
217  */
218 void dvmFreeBitVector(BitVector* pBits)
219 {
220     if (pBits == NULL)
221         return;
222
223     free(pBits->storage);
224     free(pBits);
225 }
226
227 /*
228  * "Allocate" the first-available bit in the bitmap.
229  *
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.
233  */
234 int dvmAllocBit(BitVector* pBits)
235 {
236     int word, bit;
237
238 retry:
239     for (word = 0; word < pBits->storageSize; word++) {
240         if (pBits->storage[word] != 0xffffffff) {
241             /*
242              * There are unallocated bits in this word.  Return the first.
243              */
244             bit = ffs(~(pBits->storage[word])) -1;
245             assert(bit >= 0 && bit < 32);
246             pBits->storage[word] |= 1 << bit;
247             return (word << 5) | bit;
248         }
249     }
250
251     /*
252      * Ran out of space, allocate more if we're allowed to.
253      */
254     if (!pBits->expandable)
255         return -1;
256
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;
262     goto retry;
263 }
264
265 /*
266  * Mark the specified bit as "set".
267  *
268  * Returns "false" if the bit is outside the range of the vector and we're
269  * not allowed to expand.
270  */
271 bool dvmSetBit(BitVector* pBits, int num)
272 {
273     assert(num >= 0);
274     if (num >= pBits->storageSize * (int)sizeof(u4) * 8) {
275         if (!pBits->expandable)
276             return false;
277
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;
284     }
285
286     pBits->storage[num >> 5] |= 1 << (num & 0x1f);
287     return true;
288 }
289
290 /*
291  * Mark the specified bit as "clear".
292  */
293 void dvmClearBit(BitVector* pBits, int num)
294 {
295     assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
296
297     pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
298 }
299
300 /*
301  * Mark all bits bit as "clear".
302  */
303 void dvmClearAllBits(BitVector* pBits)
304 {
305     int count = pBits->storageSize;
306     memset(pBits->storage, 0, count * sizeof(u4));
307 }
308
309 /*
310  * Determine whether or not the specified bit is set.
311  */
312 bool dvmIsBitSet(const BitVector* pBits, int num)
313 {
314     assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
315
316     int val = pBits->storage[num >> 5] & (1 << (num & 0x1f));
317     return (val != 0);
318 }
319
320 /*
321  * Count the number of bits that are set.
322  */
323 int dvmCountSetBits(const BitVector* pBits)
324 {
325     int word, bit;
326     int count = 0;
327
328     for (word = 0; word < pBits->storageSize; word++) {
329         u4 val = pBits->storage[word];
330
331         if (val != 0) {
332             if (val == 0xffffffff) {
333                 count += 32;
334             } else {
335                 /* count the number of '1' bits */
336                 while (val != 0) {
337                     val &= val - 1;
338                     count++;
339                 }
340             }
341         }
342     }
343
344     return count;
345 }
346
347 /*
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.
351  */
352 char* dvmDotToSlash(const char* str)
353 {
354     char* newStr = strdup(str);
355     char* cp = newStr;
356
357     while (*cp != '\0') {
358         if (*cp == '/') {
359             assert(false);
360             return NULL;
361         }
362         if (*cp == '.')
363             *cp = '/';
364         cp++;
365     }
366
367     return newStr;
368 }
369
370 /*
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 '.'.
375  */
376 char* dvmDescriptorToDot(const char* str)
377 {
378     size_t at = strlen(str);
379     char* newStr;
380
381     if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
382         at -= 2; /* Two fewer chars to copy. */
383         str++; /* Skip the 'L'. */
384     }
385
386     newStr = malloc(at + 1); /* Add one for the '\0'. */
387     newStr[at] = '\0';
388
389     while (at > 0) {
390         at--;
391         newStr[at] = (str[at] == '/') ? '.' : str[at];
392     }
393
394     return newStr;
395 }
396
397 /*
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 '/'.
402  */
403 char* dvmDotToDescriptor(const char* str)
404 {
405     size_t length = strlen(str);
406     int wrapElSemi = 0;
407     char* newStr;
408     char* at;
409
410     if (str[0] != '[') {
411         length += 2; /* for "L" and ";" */
412         wrapElSemi = 1;
413     }
414
415     newStr = at = malloc(length + 1); /* + 1 for the '\0' */
416
417     if (newStr == NULL) {
418         return NULL;
419     }
420
421     if (wrapElSemi) {
422         *(at++) = 'L';
423     }
424
425     while (*str) {
426         char c = *(str++);
427         if (c == '.') {
428             c = '/';
429         }
430         *(at++) = c;
431     }
432
433     if (wrapElSemi) {
434         *(at++) = ';';
435     }
436
437     *at = '\0';
438     return newStr;
439 }
440
441 /*
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.
445  */
446 char* dvmDescriptorToName(const char* str)
447 {
448     if (str[0] == 'L') {
449         size_t length = strlen(str) - 1;
450         char* newStr = malloc(length);
451
452         if (newStr == NULL) {
453             return NULL;
454         }
455
456         strlcpy(newStr, str + 1, length);
457         return newStr;
458     }
459
460     return strdup(str);
461 }
462
463 /*
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.
467  */
468 char* dvmNameToDescriptor(const char* str)
469 {
470     if (str[0] != '[') {
471         size_t length = strlen(str);
472         char* descriptor = malloc(length + 3);
473
474         if (descriptor == NULL) {
475             return NULL;
476         }
477
478         descriptor[0] = 'L';
479         strcpy(descriptor + 1, str);
480         descriptor[length + 1] = ';';
481         descriptor[length + 2] = '\0';
482
483         return descriptor;
484     }
485
486     return strdup(str);
487 }
488
489 /*
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.
493  */
494 u8 dvmGetRelativeTimeNsec(void)
495 {
496 #ifdef HAVE_POSIX_CLOCKS
497     struct timespec now;
498     clock_gettime(CLOCK_MONOTONIC, &now);
499     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
500 #else
501     struct timeval now;
502     gettimeofday(&now, NULL);
503     return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
504 #endif
505 }
506
507 /*
508  * Get the per-thread CPU time, in nanoseconds.
509  *
510  * Only useful for time deltas.
511  */
512 u8 dvmGetThreadCpuTimeNsec(void)
513 {
514 #ifdef HAVE_POSIX_CLOCKS
515     struct timespec now;
516     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
517     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
518 #else
519     return (u8) -1;
520 #endif
521 }
522
523 /*
524  * Get the per-thread CPU time, in nanoseconds, for the specified thread.
525  */
526 u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
527 {
528 #if 0 /*def HAVE_POSIX_CLOCKS*/
529     int clockId;
530
531     if (pthread_getcpuclockid(thread, &clockId) != 0)
532         return (u8) -1;
533
534     struct timespec now;
535     clock_gettime(clockId, &now);
536     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
537 #else
538     return (u8) -1;
539 #endif
540 }
541
542
543 /*
544  * Call this repeatedly, with successively higher values for "iteration",
545  * to sleep for a period of time not to exceed "maxTotalSleep".
546  *
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.
550  *
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.
554  *
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.
558  *
559  * Returns "false" if we were unable to sleep because our time was up.
560  */
561 bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
562 {
563     const int minSleep = 10000;
564     u8 curTime;
565     int curDelay;
566
567     /*
568      * Get current time, and see if we've already exceeded the limit.
569      */
570     curTime = dvmGetRelativeTimeUsec();
571     if (curTime >= relStartTime + maxTotalSleep) {
572         LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
573             relStartTime, maxTotalSleep, curTime);
574         return false;
575     }
576
577     /*
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.)
581      *
582      * For iteration==0 we just call sched_yield(), so the first sleep
583      * at iteration==1 is actually (minSleep * 2).
584      */
585     curDelay = minSleep;
586     while (iteration-- > 0)
587         curDelay *= 2;
588     assert(curDelay > 0);
589
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);
594     }
595
596     if (iteration == 0) {
597         LOGVV("exsl: yield\n");
598         sched_yield();
599     } else {
600         LOGVV("exsl: sleep for %d\n", curDelay);
601         usleep(curDelay);
602     }
603     return true;
604 }
605
606
607 /*
608  * Set the "close on exec" flag so we don't expose our file descriptors
609  * to processes launched by us.
610  */
611 bool dvmSetCloseOnExec(int fd)
612 {
613     int flags;
614
615     /*
616      * There's presently only one flag defined, so getting the previous
617      * value of the fd flags is probably unnecessary.
618      */
619     flags = fcntl(fd, F_GETFD);
620     if (flags < 0) {
621         LOGW("Unable to get fd flags for fd %d\n", fd);
622         return false;
623     }
624     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
625         LOGW("Unable to set close-on-exec for fd %d\n", fd);
626         return false;
627     }
628     return true;
629 }
630
631 #if (!HAVE_STRLCPY)
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;
636
637     if (srcLength > (size - 1)) {
638         copyLength = size - 1;
639     }
640
641     if (size != 0) {
642         strncpy(dst, src, copyLength);
643         dst[copyLength] = '\0';
644     }
645
646     return srcLength;
647 }
648 #endif