Merge "liblog: event_tag_map use unordered_map" am: 8b99ef6c21
am: 5f1b27fdbb
am: aeb972ae64
am: e856791073
Change-Id: I1789794919b6ce022430fcd278dc4bc1b9a389ce
This commit is contained in:
commit
f7b0c9bc4f
liblog
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
* Copyright (C) 2007-2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,362 +24,106 @@
|
|||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <experimental/string_view>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <log/event_tag_map.h>
|
||||
|
||||
#include "log_portability.h"
|
||||
|
||||
#define OUT_TAG "EventTagMap"
|
||||
|
||||
/*
|
||||
* Single entry.
|
||||
*/
|
||||
typedef struct EventTag {
|
||||
uint32_t tagIndex;
|
||||
char* tagStr;
|
||||
size_t tagLen;
|
||||
char* fmtStr;
|
||||
size_t fmtLen;
|
||||
} EventTag;
|
||||
typedef std::experimental::string_view MapString;
|
||||
|
||||
/*
|
||||
* Map.
|
||||
*/
|
||||
struct EventTagMap {
|
||||
/* memory-mapped source file; we get strings from here */
|
||||
void* mapAddr;
|
||||
size_t mapLen;
|
||||
typedef std::pair<MapString, MapString> TagFmt;
|
||||
|
||||
/* array of event tags, sorted numerically by tag index */
|
||||
EventTag* tagArray;
|
||||
int numTags;
|
||||
template <> struct _LIBCPP_TYPE_VIS_ONLY std::hash<TagFmt>
|
||||
: public std::unary_function<const TagFmt&, size_t> {
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
size_t operator()(const TagFmt& __t) const _NOEXCEPT {
|
||||
// Tag is typically unique. Will cost us an extra 100ns for the
|
||||
// unordered_map lookup if we instead did a hash that combined
|
||||
// both of tag and fmt members, e.g.:
|
||||
//
|
||||
// return std::hash<MapString>()(__t.first) ^
|
||||
// std::hash<MapString>()(__t.second);
|
||||
return std::hash<MapString>()(__t.first);
|
||||
}
|
||||
};
|
||||
|
||||
/* fwd */
|
||||
static int processFile(EventTagMap* map);
|
||||
static int countMapLines(const EventTagMap* map);
|
||||
static int parseMapLines(EventTagMap* map);
|
||||
static int scanTagLine(char** pData, EventTag* tag, int lineNum);
|
||||
static int sortTags(EventTagMap* map);
|
||||
// Map
|
||||
struct EventTagMap {
|
||||
// memory-mapped source file; we get strings from here
|
||||
void* mapAddr;
|
||||
size_t mapLen;
|
||||
|
||||
/*
|
||||
* Open the map file and allocate a structure to manage it.
|
||||
*
|
||||
* We create a private mapping because we want to terminate the log tag
|
||||
* strings with '\0'.
|
||||
*/
|
||||
LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName)
|
||||
{
|
||||
EventTagMap* newTagMap;
|
||||
off_t end;
|
||||
int save_errno;
|
||||
const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
|
||||
private:
|
||||
std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
|
||||
|
||||
int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
save_errno = errno;
|
||||
fprintf(stderr, "%s: unable to open map '%s': %s\n",
|
||||
OUT_TAG, tagfile, strerror(save_errno));
|
||||
goto fail_errno;
|
||||
}
|
||||
public:
|
||||
EventTagMap() : mapAddr(NULL), mapLen(0) { }
|
||||
|
||||
end = lseek(fd, 0L, SEEK_END);
|
||||
save_errno = errno;
|
||||
(void) lseek(fd, 0L, SEEK_SET);
|
||||
if (end < 0) {
|
||||
fprintf(stderr, "%s: unable to seek map '%s' %s\n",
|
||||
OUT_TAG, tagfile, strerror(save_errno));
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
newTagMap = (EventTagMap*)calloc(1, sizeof(EventTagMap));
|
||||
if (newTagMap == NULL) {
|
||||
save_errno = errno;
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
save_errno = errno;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
|
||||
fprintf(stderr, "%s: mmap(%s) failed: %s\n",
|
||||
OUT_TAG, tagfile, strerror(save_errno));
|
||||
goto fail_free;
|
||||
}
|
||||
|
||||
newTagMap->mapLen = end;
|
||||
|
||||
if (processFile(newTagMap) != 0) goto fail_unmap;
|
||||
|
||||
return newTagMap;
|
||||
|
||||
fail_unmap:
|
||||
munmap(newTagMap->mapAddr, newTagMap->mapLen);
|
||||
save_errno = EINVAL;
|
||||
fail_free:
|
||||
free(newTagMap);
|
||||
fail_close:
|
||||
close(fd);
|
||||
fail_errno:
|
||||
errno = save_errno;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the map.
|
||||
*/
|
||||
LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map)
|
||||
{
|
||||
if (map == NULL) return;
|
||||
|
||||
munmap(map->mapAddr, map->mapLen);
|
||||
free(map->tagArray);
|
||||
free(map);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an entry in the map.
|
||||
*
|
||||
* The entries are sorted by tag number, so we can do a binary search.
|
||||
*/
|
||||
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
|
||||
size_t *len,
|
||||
unsigned int tag)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = map->numTags - 1;
|
||||
|
||||
while (lo <= hi) {
|
||||
int mid = (lo + hi) / 2;
|
||||
int cmp = map->tagArray[mid].tagIndex - tag;
|
||||
|
||||
if (cmp < 0) {
|
||||
/* tag is bigger */
|
||||
lo = mid + 1;
|
||||
} else if (cmp > 0) {
|
||||
/* tag is smaller */
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
/* found */
|
||||
if (len) *len = map->tagArray[mid].tagLen;
|
||||
/*
|
||||
* b/31456426 to check if gTest can detect copy-on-write issue
|
||||
* add the following line to break us:
|
||||
* map->tagArray[mid].tagStr[map->tagArray[mid].tagLen] = '\0';
|
||||
* or explicitly use deprecated android_lookupEventTag().
|
||||
*/
|
||||
return map->tagArray[mid].tagStr;
|
||||
~EventTagMap() {
|
||||
Idx2TagFmt.clear();
|
||||
if (mapAddr) {
|
||||
munmap(mapAddr, mapLen);
|
||||
mapAddr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
if (len) *len = 0;
|
||||
return NULL;
|
||||
}
|
||||
bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
|
||||
const TagFmt* find(uint32_t tag) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Look up an entry in the map.
|
||||
*
|
||||
* The entries are sorted by tag number, so we can do a binary search.
|
||||
*/
|
||||
LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
|
||||
const EventTagMap* map, size_t *len, unsigned int tag)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = map->numTags - 1;
|
||||
|
||||
while (lo <= hi) {
|
||||
int mid = (lo + hi) / 2;
|
||||
int cmp = map->tagArray[mid].tagIndex - tag;
|
||||
|
||||
if (cmp < 0) {
|
||||
/* tag is bigger */
|
||||
lo = mid + 1;
|
||||
} else if (cmp > 0) {
|
||||
/* tag is smaller */
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
/* found */
|
||||
if (len) *len = map->tagArray[mid].fmtLen;
|
||||
return map->tagArray[mid].fmtStr;
|
||||
bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose) {
|
||||
std::unordered_map<uint32_t, TagFmt>::const_iterator it;
|
||||
it = Idx2TagFmt.find(tag);
|
||||
if (it != Idx2TagFmt.end()) {
|
||||
if (verbose) {
|
||||
fprintf(stderr,
|
||||
OUT_TAG ": duplicate tag entries %" PRIu32
|
||||
":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
|
||||
it->first,
|
||||
(int)it->second.first.length(), it->second.first.data(),
|
||||
(int)it->second.second.length(), it->second.second.data(),
|
||||
tag,
|
||||
(int)tagfmt.first.length(), tagfmt.first.data(),
|
||||
(int)tagfmt.second.length(), tagfmt.second.data());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
if (len) *len = 0;
|
||||
return NULL;
|
||||
Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
|
||||
return true;
|
||||
}
|
||||
|
||||
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
|
||||
unsigned int tag)
|
||||
{
|
||||
size_t len;
|
||||
const char* tagStr = android_lookupEventTag_len(map, &len, tag);
|
||||
const TagFmt* EventTagMap::find(uint32_t tag) const {
|
||||
std::unordered_map<uint32_t, TagFmt>::const_iterator it;
|
||||
it = Idx2TagFmt.find(tag);
|
||||
if (it == Idx2TagFmt.end()) return NULL;
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
// Scan one tag line.
|
||||
//
|
||||
// "*pData" should be pointing to the first digit in the tag number. On
|
||||
// successful return, it will be pointing to the last character in the
|
||||
// tag line (i.e. the character before the start of the next line).
|
||||
//
|
||||
// Returns 0 on success, nonzero on failure.
|
||||
static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
|
||||
char* cp;
|
||||
|
||||
if (!tagStr) return tagStr;
|
||||
cp = (char*)tagStr;
|
||||
cp += len;
|
||||
if (*cp) *cp = '\0'; /* Trigger copy on write :-( */
|
||||
return tagStr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crunch through the file, parsing the contents and creating a tag index.
|
||||
*/
|
||||
static int processFile(EventTagMap* map)
|
||||
{
|
||||
/* get a tag count */
|
||||
map->numTags = countMapLines(map);
|
||||
if (map->numTags < 0) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate storage for the tag index array */
|
||||
map->tagArray = (EventTag*)calloc(1, sizeof(EventTag) * map->numTags);
|
||||
if (map->tagArray == NULL) return -1;
|
||||
|
||||
/* parse the file, null-terminating tag strings */
|
||||
if (parseMapLines(map) != 0) return -1;
|
||||
|
||||
/* sort the tags and check for duplicates */
|
||||
if (sortTags(map) != 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through all lines in the file, determining whether they're blank,
|
||||
* comments, or possibly have a tag entry.
|
||||
*
|
||||
* This is a very "loose" scan. We don't try to detect syntax errors here.
|
||||
* The later pass is more careful, but the number of tags found there must
|
||||
* match the number of tags found here.
|
||||
*
|
||||
* Returns the number of potential tag entries found.
|
||||
*/
|
||||
static int countMapLines(const EventTagMap* map)
|
||||
{
|
||||
const char* cp = (const char*) map->mapAddr;
|
||||
const char* endp = cp + map->mapLen;
|
||||
int numTags = 0;
|
||||
int unknown = 1;
|
||||
|
||||
while (cp < endp) {
|
||||
if (*cp == '\n') {
|
||||
unknown = 1;
|
||||
} else if (unknown) {
|
||||
if (isdigit(*cp)) {
|
||||
/* looks like a tag to me */
|
||||
numTags++;
|
||||
unknown = 0;
|
||||
} else if (isspace(*cp)) {
|
||||
/* might be leading whitespace before tag num, keep going */
|
||||
} else {
|
||||
/* assume comment; second pass can complain in detail */
|
||||
unknown = 0;
|
||||
}
|
||||
} else {
|
||||
/* we've made up our mind; just scan to end of line */
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
|
||||
return numTags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the tags out of the file.
|
||||
*/
|
||||
static int parseMapLines(EventTagMap* map)
|
||||
{
|
||||
int tagNum, lineStart, lineNum;
|
||||
char* cp = (char*) map->mapAddr;
|
||||
char* endp = cp + map->mapLen;
|
||||
|
||||
/* insist on EOL at EOF; simplifies parsing and null-termination */
|
||||
if (*(endp - 1) != '\n') {
|
||||
fprintf(stderr, "%s: map file missing EOL on last line\n", OUT_TAG);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tagNum = 0;
|
||||
lineStart = 1;
|
||||
lineNum = 1;
|
||||
while (cp < endp) {
|
||||
if (*cp == '\n') {
|
||||
lineStart = 1;
|
||||
lineNum++;
|
||||
} else if (lineStart) {
|
||||
if (*cp == '#') {
|
||||
/* comment; just scan to end */
|
||||
lineStart = 0;
|
||||
} else if (isdigit(*cp)) {
|
||||
/* looks like a tag; scan it out */
|
||||
if (tagNum >= map->numTags) {
|
||||
fprintf(stderr,
|
||||
"%s: more tags than expected (%d)\n", OUT_TAG, tagNum);
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
}
|
||||
if (scanTagLine(&cp, &map->tagArray[tagNum], lineNum) != 0) {
|
||||
return -1;
|
||||
}
|
||||
tagNum++;
|
||||
lineNum++; // we eat the '\n'
|
||||
/* leave lineStart==1 */
|
||||
} else if (isspace(*cp)) {
|
||||
/* looks like leading whitespace; keep scanning */
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"%s: unexpected chars (0x%02x) in tag number on line %d\n",
|
||||
OUT_TAG, *cp, lineNum);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* this is a blank or comment line */
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (tagNum != map->numTags) {
|
||||
fprintf(stderr, "%s: parsed %d tags, expected %d\n",
|
||||
OUT_TAG, tagNum, map->numTags);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan one tag line.
|
||||
*
|
||||
* "*pData" should be pointing to the first digit in the tag number. On
|
||||
* successful return, it will be pointing to the last character in the
|
||||
* tag line (i.e. the character before the start of the next line).
|
||||
*
|
||||
* Returns 0 on success, nonzero on failure.
|
||||
*/
|
||||
static int scanTagLine(char** pData, EventTag* tag, int lineNum)
|
||||
{
|
||||
char* cp;
|
||||
|
||||
unsigned long val = strtoul(*pData, &cp, 10);
|
||||
if (cp == *pData) {
|
||||
fprintf(stderr, "%s: malformed tag number on line %d\n", OUT_TAG, lineNum);
|
||||
fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tag->tagIndex = val;
|
||||
if (tag->tagIndex != val) {
|
||||
fprintf(stderr, "%s: tag number too large on line %d\n", OUT_TAG, lineNum);
|
||||
uint32_t tagIndex = val;
|
||||
if (tagIndex != val) {
|
||||
fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
@ -388,76 +132,192 @@ static int scanTagLine(char** pData, EventTag* tag, int lineNum)
|
|||
}
|
||||
|
||||
if (*cp == '\n') {
|
||||
fprintf(stderr, "%s: missing tag string on line %d\n", OUT_TAG, lineNum);
|
||||
fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tag->tagStr = cp;
|
||||
|
||||
/* Determine whether "c" is a valid tag char. */
|
||||
while (isalnum(*++cp) || (*cp == '_')) {
|
||||
}
|
||||
tag->tagLen = cp - tag->tagStr;
|
||||
const char* tag = cp;
|
||||
// Determine whether "c" is a valid tag char.
|
||||
while (isalnum(*++cp) || (*cp == '_')) { }
|
||||
size_t tagLen = cp - tag;
|
||||
|
||||
if (!isspace(*cp)) {
|
||||
fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
|
||||
fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (isspace(*cp) && (*cp != '\n')) ++cp;
|
||||
const char* fmt = NULL;
|
||||
size_t fmtLen = 0;
|
||||
if (*cp != '#') {
|
||||
tag->fmtStr = cp;
|
||||
fmt = cp;
|
||||
while ((*cp != '\n') && (*cp != '#')) ++cp;
|
||||
while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
|
||||
tag->fmtLen = cp - tag->fmtStr;
|
||||
while ((cp > fmt) && isspace(*(cp - 1))) --cp;
|
||||
fmtLen = cp - fmt;
|
||||
}
|
||||
|
||||
while (*cp != '\n') ++cp;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
|
||||
#endif
|
||||
*pData = cp;
|
||||
|
||||
return 0;
|
||||
if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
|
||||
MapString(tag, tagLen), MapString(fmt, fmtLen))), true)) {
|
||||
return 0;
|
||||
}
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two EventTags.
|
||||
*/
|
||||
static int compareEventTags(const void* v1, const void* v2)
|
||||
{
|
||||
const EventTag* tag1 = (const EventTag*) v1;
|
||||
const EventTag* tag2 = (const EventTag*) v2;
|
||||
// Parse the tags out of the file.
|
||||
static int parseMapLines(EventTagMap* map) {
|
||||
char* cp = static_cast<char*>(map->mapAddr);
|
||||
size_t len = map->mapLen;
|
||||
char* endp = cp + len;
|
||||
|
||||
return tag1->tagIndex - tag2->tagIndex;
|
||||
}
|
||||
// insist on EOL at EOF; simplifies parsing and null-termination
|
||||
if (!len || (*(endp - 1) != '\n')) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, OUT_TAG ": map file missing EOL on last line\n");
|
||||
#endif
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the EventTag array so we can do fast lookups by tag index. After
|
||||
* the sort we do a quick check for duplicate tag indices.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int sortTags(EventTagMap* map)
|
||||
{
|
||||
int i;
|
||||
|
||||
qsort(map->tagArray, map->numTags, sizeof(EventTag), compareEventTags);
|
||||
|
||||
for (i = 1; i < map->numTags; i++) {
|
||||
if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
|
||||
fprintf(stderr,
|
||||
"%s: duplicate tag entries (%" PRIu32 ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
|
||||
OUT_TAG,
|
||||
map->tagArray[i].tagIndex,
|
||||
(int)map->tagArray[i].tagLen, map->tagArray[i].tagStr,
|
||||
(int)map->tagArray[i].fmtLen, map->tagArray[i].fmtStr,
|
||||
map->tagArray[i - 1].tagIndex,
|
||||
(int)map->tagArray[i - 1].tagLen, map->tagArray[i - 1].fmtStr,
|
||||
(int)map->tagArray[i - 1].fmtLen, map->tagArray[i - 1].fmtStr);
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
bool lineStart = true;
|
||||
int lineNum = 1;
|
||||
while (cp < endp) {
|
||||
if (*cp == '\n') {
|
||||
lineStart = true;
|
||||
lineNum++;
|
||||
} else if (lineStart) {
|
||||
if (*cp == '#') {
|
||||
// comment; just scan to end
|
||||
lineStart = false;
|
||||
} else if (isdigit(*cp)) {
|
||||
// looks like a tag; scan it out
|
||||
if (scanTagLine(map, &cp, lineNum) != 0) {
|
||||
return -1;
|
||||
}
|
||||
lineNum++; // we eat the '\n'
|
||||
// leave lineStart==true
|
||||
} else if (isspace(*cp)) {
|
||||
// looks like leading whitespace; keep scanning
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
OUT_TAG ": unexpected chars (0x%02x) in tag number on line %d\n",
|
||||
*cp, lineNum);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
// this is a blank or comment line
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Open the map file and allocate a structure to manage it.
|
||||
//
|
||||
// We create a private mapping because we want to terminate the log tag
|
||||
// strings with '\0'.
|
||||
LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
|
||||
int save_errno;
|
||||
|
||||
const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
|
||||
int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
save_errno = errno;
|
||||
fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n",
|
||||
tagfile, strerror(save_errno));
|
||||
errno = save_errno;
|
||||
return NULL;
|
||||
}
|
||||
off_t end = lseek(fd, 0L, SEEK_END);
|
||||
save_errno = errno;
|
||||
(void)lseek(fd, 0L, SEEK_SET);
|
||||
if (end < 0) {
|
||||
fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n",
|
||||
tagfile, strerror(save_errno));
|
||||
close(fd);
|
||||
errno = save_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EventTagMap* newTagMap = new EventTagMap;
|
||||
if (newTagMap == NULL) {
|
||||
save_errno = errno;
|
||||
close(fd);
|
||||
errno = save_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0);
|
||||
save_errno = errno;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
|
||||
fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n",
|
||||
tagfile, strerror(save_errno));
|
||||
delete newTagMap;
|
||||
errno = save_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newTagMap->mapLen = end;
|
||||
|
||||
if (parseMapLines(newTagMap) != 0) {
|
||||
delete newTagMap;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newTagMap;
|
||||
}
|
||||
|
||||
// Close the map.
|
||||
LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
|
||||
if (map) delete map;
|
||||
}
|
||||
|
||||
// Look up an entry in the map.
|
||||
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
|
||||
size_t *len,
|
||||
unsigned int tag) {
|
||||
if (len) *len = 0;
|
||||
const TagFmt* str = map->find(tag);
|
||||
if (!str) return NULL;
|
||||
if (len) *len = str->first.length();
|
||||
return str->first.data();
|
||||
}
|
||||
|
||||
// Look up an entry in the map.
|
||||
LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
|
||||
const EventTagMap* map, size_t *len, unsigned int tag) {
|
||||
if (len) *len = 0;
|
||||
const TagFmt* str = map->find(tag);
|
||||
if (!str) return NULL;
|
||||
if (len) *len = str->second.length();
|
||||
return str->second.data();
|
||||
}
|
||||
|
||||
// This function is deprecated and replaced with android_lookupEventTag_len
|
||||
// since it will cause the map to change from Shared and backed by a file,
|
||||
// to Private Dirty and backed up by swap, albeit highly compressible. By
|
||||
// deprecating this function everywhere, we save 100s of MB of memory space.
|
||||
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
|
||||
unsigned int tag) {
|
||||
size_t len;
|
||||
const char* tagStr = android_lookupEventTag_len(map, &len, tag);
|
||||
|
||||
if (!tagStr) return tagStr;
|
||||
char* cp = const_cast<char*>(tagStr);
|
||||
cp += len;
|
||||
if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
|
||||
return tagStr;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue