OSDN Git Service

Merge change 9384
[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     }
284
285     pBits->storage[num >> 5] |= 1 << (num & 0x1f);
286     return true;
287 }
288
289 /*
290  * Mark the specified bit as "clear".
291  */
292 void dvmClearBit(BitVector* pBits, int num)
293 {
294     assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
295
296     pBits->storage[num >> 5] &= ~(1 << (num & 0x1f));
297 }
298
299 /*
300  * Mark all bits bit as "clear".
301  */
302 void dvmClearAllBits(BitVector* pBits)
303 {
304     int count = pBits->storageSize;
305     memset(pBits->storage, 0, count * sizeof(u4));
306 }
307
308 /*
309  * Determine whether or not the specified bit is set.
310  */
311 bool dvmIsBitSet(const BitVector* pBits, int num)
312 {
313     assert(num >= 0 && num < (int) pBits->storageSize * (int)sizeof(u4) * 8);
314
315     int val = pBits->storage[num >> 5] & (1 << (num & 0x1f));
316     return (val != 0);
317 }
318
319 /*
320  * Count the number of bits that are set.
321  */
322 int dvmCountSetBits(const BitVector* pBits)
323 {
324     int word, bit;
325     int count = 0;
326
327     for (word = 0; word < pBits->storageSize; word++) {
328         u4 val = pBits->storage[word];
329
330         if (val != 0) {
331             if (val == 0xffffffff) {
332                 count += 32;
333             } else {
334                 /* count the number of '1' bits */
335                 while (val != 0) {
336                     val &= val - 1;
337                     count++;
338                 }
339             }
340         }
341     }
342
343     return count;
344 }
345
346 /*
347  * Return a newly-allocated string in which all occurrences of '.' have
348  * been changed to '/'.  If we find a '/' in the original string, NULL
349  * is returned to avoid ambiguity.
350  */
351 char* dvmDotToSlash(const char* str)
352 {
353     char* newStr = strdup(str);
354     char* cp = newStr;
355
356     while (*cp != '\0') {
357         if (*cp == '/') {
358             assert(false);
359             return NULL;
360         }
361         if (*cp == '.')
362             *cp = '/';
363         cp++;
364     }
365
366     return newStr;
367 }
368
369 /*
370  * Return a newly-allocated string for the "dot version" of the class
371  * name for the given type descriptor. That is, The initial "L" and
372  * final ";" (if any) have been removed and all occurrences of '/'
373  * have been changed to '.'.
374  */
375 char* dvmDescriptorToDot(const char* str)
376 {
377     size_t at = strlen(str);
378     char* newStr;
379
380     if ((at >= 2) && (str[0] == 'L') && (str[at - 1] == ';')) {
381         at -= 2; /* Two fewer chars to copy. */
382         str++; /* Skip the 'L'. */
383     }
384
385     newStr = malloc(at + 1); /* Add one for the '\0'. */
386     newStr[at] = '\0';
387
388     while (at > 0) {
389         at--;
390         newStr[at] = (str[at] == '/') ? '.' : str[at];
391     }
392
393     return newStr;
394 }
395
396 /*
397  * Return a newly-allocated string for the type descriptor
398  * corresponding to the "dot version" of the given class name. That
399  * is, non-array names are surrounded by "L" and ";", and all
400  * occurrences of '.' are changed to '/'.
401  */
402 char* dvmDotToDescriptor(const char* str)
403 {
404     size_t length = strlen(str);
405     int wrapElSemi = 0;
406     char* newStr;
407     char* at;
408
409     if (str[0] != '[') {
410         length += 2; /* for "L" and ";" */
411         wrapElSemi = 1;
412     }
413
414     newStr = at = malloc(length + 1); /* + 1 for the '\0' */
415
416     if (newStr == NULL) {
417         return NULL;
418     }
419
420     if (wrapElSemi) {
421         *(at++) = 'L';
422     }
423
424     while (*str) {
425         char c = *(str++);
426         if (c == '.') {
427             c = '/';
428         }
429         *(at++) = c;
430     }
431
432     if (wrapElSemi) {
433         *(at++) = ';';
434     }
435
436     *at = '\0';
437     return newStr;
438 }
439
440 /*
441  * Return a newly-allocated string for the internal-form class name for
442  * the given type descriptor. That is, the initial "L" and final ";" (if
443  * any) have been removed.
444  */
445 char* dvmDescriptorToName(const char* str)
446 {
447     if (str[0] == 'L') {
448         size_t length = strlen(str) - 1;
449         char* newStr = malloc(length);
450
451         if (newStr == NULL) {
452             return NULL;
453         }
454
455         strlcpy(newStr, str + 1, length);
456         return newStr;
457     }
458
459     return strdup(str);
460 }
461
462 /*
463  * Return a newly-allocated string for the type descriptor for the given
464  * internal-form class name. That is, a non-array class name will get
465  * surrounded by "L" and ";", while array names are left as-is.
466  */
467 char* dvmNameToDescriptor(const char* str)
468 {
469     if (str[0] != '[') {
470         size_t length = strlen(str);
471         char* descriptor = malloc(length + 3);
472
473         if (descriptor == NULL) {
474             return NULL;
475         }
476
477         descriptor[0] = 'L';
478         strcpy(descriptor + 1, str);
479         descriptor[length + 1] = ';';
480         descriptor[length + 2] = '\0';
481
482         return descriptor;
483     }
484
485     return strdup(str);
486 }
487
488 /*
489  * Get a notion of the current time, in nanoseconds.  This is meant for
490  * computing durations (e.g. "operation X took 52nsec"), so the result
491  * should not be used to get the current date/time.
492  */
493 u8 dvmGetRelativeTimeNsec(void)
494 {
495 #ifdef HAVE_POSIX_CLOCKS
496     struct timespec now;
497     clock_gettime(CLOCK_MONOTONIC, &now);
498     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
499 #else
500     struct timeval now;
501     gettimeofday(&now, NULL);
502     return (u8)now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
503 #endif
504 }
505
506 /*
507  * Get the per-thread CPU time, in nanoseconds.
508  *
509  * Only useful for time deltas.
510  */
511 u8 dvmGetThreadCpuTimeNsec(void)
512 {
513 #ifdef HAVE_POSIX_CLOCKS
514     struct timespec now;
515     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
516     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
517 #else
518     return (u8) -1;
519 #endif
520 }
521
522 /*
523  * Get the per-thread CPU time, in nanoseconds, for the specified thread.
524  */
525 u8 dvmGetOtherThreadCpuTimeNsec(pthread_t thread)
526 {
527 #if 0 /*def HAVE_POSIX_CLOCKS*/
528     int clockId;
529
530     if (pthread_getcpuclockid(thread, &clockId) != 0)
531         return (u8) -1;
532
533     struct timespec now;
534     clock_gettime(clockId, &now);
535     return (u8)now.tv_sec*1000000000LL + now.tv_nsec;
536 #else
537     return (u8) -1;
538 #endif
539 }
540
541
542 /*
543  * Call this repeatedly, with successively higher values for "iteration",
544  * to sleep for a period of time not to exceed "maxTotalSleep".
545  *
546  * For example, when called with iteration==0 we will sleep for a very
547  * brief time.  On the next call we will sleep for a longer time.  When
548  * the sum total of all sleeps reaches "maxTotalSleep", this returns false.
549  *
550  * The initial start time value for "relStartTime" MUST come from the
551  * dvmGetRelativeTimeUsec call.  On the device this must come from the
552  * monotonic clock source, not the wall clock.
553  *
554  * This should be used wherever you might be tempted to call sched_yield()
555  * in a loop.  The problem with sched_yield is that, for a high-priority
556  * thread, the kernel might not actually transfer control elsewhere.
557  *
558  * Returns "false" if we were unable to sleep because our time was up.
559  */
560 bool dvmIterativeSleep(int iteration, int maxTotalSleep, u8 relStartTime)
561 {
562     const int minSleep = 10000;
563     u8 curTime;
564     int curDelay;
565
566     /*
567      * Get current time, and see if we've already exceeded the limit.
568      */
569     curTime = dvmGetRelativeTimeUsec();
570     if (curTime >= relStartTime + maxTotalSleep) {
571         LOGVV("exsl: sleep exceeded (start=%llu max=%d now=%llu)\n",
572             relStartTime, maxTotalSleep, curTime);
573         return false;
574     }
575
576     /*
577      * Compute current delay.  We're bounded by "maxTotalSleep", so no
578      * real risk of overflow assuming "usleep" isn't returning early.
579      * (Besides, 2^30 usec is about 18 minutes by itself.)
580      *
581      * For iteration==0 we just call sched_yield(), so the first sleep
582      * at iteration==1 is actually (minSleep * 2).
583      */
584     curDelay = minSleep;
585     while (iteration-- > 0)
586         curDelay *= 2;
587     assert(curDelay > 0);
588
589     if (curTime + curDelay >= relStartTime + maxTotalSleep) {
590         LOGVV("exsl: reduced delay from %d to %d\n",
591             curDelay, (int) ((relStartTime + maxTotalSleep) - curTime));
592         curDelay = (int) ((relStartTime + maxTotalSleep) - curTime);
593     }
594
595     if (iteration == 0) {
596         LOGVV("exsl: yield\n");
597         sched_yield();
598     } else {
599         LOGVV("exsl: sleep for %d\n", curDelay);
600         usleep(curDelay);
601     }
602     return true;
603 }
604
605
606 /*
607  * Set the "close on exec" flag so we don't expose our file descriptors
608  * to processes launched by us.
609  */
610 bool dvmSetCloseOnExec(int fd)
611 {
612     int flags;
613
614     /*
615      * There's presently only one flag defined, so getting the previous
616      * value of the fd flags is probably unnecessary.
617      */
618     flags = fcntl(fd, F_GETFD);
619     if (flags < 0) {
620         LOGW("Unable to get fd flags for fd %d\n", fd);
621         return false;
622     }
623     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
624         LOGW("Unable to set close-on-exec for fd %d\n", fd);
625         return false;
626     }
627     return true;
628 }
629
630 #if (!HAVE_STRLCPY)
631 /* Implementation of strlcpy() for platforms that don't already have it. */
632 size_t strlcpy(char *dst, const char *src, size_t size) {
633     size_t srcLength = strlen(src);
634     size_t copyLength = srcLength;
635
636     if (srcLength > (size - 1)) {
637         copyLength = size - 1;
638     }
639
640     if (size != 0) {
641         strncpy(dst, src, copyLength);
642         dst[copyLength] = '\0';
643     }
644
645     return srcLength;
646 }
647 #endif