C++ified the code. Introduced new trace entry flags, which will eventually be

used to mark entries after recovering a tracing log from a previous session.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31991 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-07-30 19:50:50 +00:00
parent 8b24b02f06
commit 3fccf0679f
2 changed files with 377 additions and 263 deletions
+3 -3
View File
@@ -16,9 +16,9 @@
struct trace_entry { struct trace_entry {
uint32 size : 14; // actual size is *4 uint32 size : 13; // actual size is *4
uint32 previous_size : 14; // actual size is *4 uint32 previous_size : 13; // actual size is *4
uint32 flags : 4; uint32 flags : 6;
}; };
struct tracing_stack_trace; struct tracing_stack_trace;
+374 -260
View File
@@ -41,12 +41,14 @@ enum {
WRAP_ENTRY = 0x01, WRAP_ENTRY = 0x01,
ENTRY_INITIALIZED = 0x02, ENTRY_INITIALIZED = 0x02,
BUFFER_ENTRY = 0x04, BUFFER_ENTRY = 0x04,
FILTER_MATCH = 0x08 FILTER_MATCH = 0x08,
INVALID_ENTRY = 0x10,
CHECK_ENTRY = 0x20,
}; };
static const size_t kTraceOutputBufferSize = 10240; static const size_t kTraceOutputBufferSize = 10240;
static const size_t kBufferSize = MAX_TRACE_SIZE / 4; static const size_t kBufferSize = MAX_TRACE_SIZE / sizeof(trace_entry);
static const addr_t kMetaDataBaseAddress = 32 * 1024 * 1024; static const addr_t kMetaDataBaseAddress = 32 * 1024 * 1024;
static const addr_t kMetaDataBaseEndAddress = 128 * 1024 * 1024; static const addr_t kMetaDataBaseEndAddress = 128 * 1024 * 1024;
@@ -55,247 +57,203 @@ static const uint32 kMetaDataMagic1 = 'Vali';
static const uint32 kMetaDataMagic2 = 'dTra'; static const uint32 kMetaDataMagic2 = 'dTra';
static const uint32 kMetaDataMagic3 = 'cing'; static const uint32 kMetaDataMagic3 = 'cing';
// the maximum we can address with the trace_entry::[previous_]size fields
static const size_t kMaxTracingEntrySize
= ((1 << 13) - 1) * sizeof(trace_entry);
class TracingMetaData { class TracingMetaData {
public: public:
uint32 magic1; static status_t Create(TracingMetaData*& _metaData);
trace_entry* buffer;
trace_entry* firstEntry;
trace_entry* afterLastEntry;
uint32 entries;
uint32 magic2;
uint32 written;
spinlock lock;
char* traceOutputBuffer;
addr_t physicalAddress;
uint32 magic3;
static status_t Create(TracingMetaData*& _metaData) inline bool Lock();
{ inline void Unlock();
// search meta data in memory (from previous session)
area_id area;
TracingMetaData* metaData;
status_t error = _CreateMetaDataArea(true, area, metaData);
if (error == B_OK) {
if (_InitPreviousTracingData(metaData)) {
_metaData = metaData;
return B_OK;
}
dprintf("Found previous tracing meta data, but failed to init.\n"); inline trace_entry* FirstEntry() const;
inline trace_entry* AfterLastEntry() const;
// invalidate the meta data inline uint32 Entries() const;
metaData->magic1 = 0; inline uint32 EntriesEver() const;
metaData->magic2 = 0;
metaData->magic3 = 0;
delete_area(area);
} else
dprintf("No previous tracing meta data found.\n");
// no previous tracng data found -- create new one inline void IncrementEntriesEver();
error = _CreateMetaDataArea(false, area, metaData);
if (error != B_OK)
return error;
area = create_area("tracing log", inline char* TraceOutputBuffer() const;
(void**)&metaData->traceOutputBuffer, B_ANY_KERNEL_ADDRESS,
kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (area < 0)
return area;
// get the physical address trace_entry* NextEntry(trace_entry* entry);
physical_entry physicalEntry; trace_entry* PreviousEntry(trace_entry* entry);
if (get_memory_map(metaData->traceOutputBuffer, B_PAGE_SIZE,
&physicalEntry, 1) == B_OK) {
metaData->physicalAddress = (addr_t)physicalEntry.address;
} else {
dprintf("TracingMetaData::Create(): failed to get physical address "
"of tracing buffer\n");
metaData->physicalAddress = 0;
}
metaData->buffer = (trace_entry*)(metaData->traceOutputBuffer trace_entry* AllocateEntry(size_t size, uint16 flags);
+ kTraceOutputBufferSize);
metaData->firstEntry = metaData->buffer;
metaData->afterLastEntry = metaData->buffer;
metaData->entries = 0;
metaData->written = 0;
B_INITIALIZE_SPINLOCK(&metaData->lock);
metaData->magic1 = kMetaDataMagic1;
metaData->magic2 = kMetaDataMagic2;
metaData->magic3 = kMetaDataMagic3;
_metaData = metaData;
return B_OK;
}
private: private:
static status_t _CreateMetaDataArea(bool findPrevious, bool _FreeFirstEntry();
area_id& _area, TracingMetaData*& _metaData) bool _MakeSpace(size_t needed);
{
// search meta data in memory (from previous session)
TracingMetaData* metaData;
addr_t metaDataAddress = kMetaDataBaseAddress;
for (; metaDataAddress <= kMetaDataBaseEndAddress;
metaDataAddress += kMetaDataAddressIncrement) {
area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing metadata",
(void**)&metaData, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE,
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
metaDataAddress, CREATE_AREA_DONT_CLEAR);
if (area < 0)
continue;
if (!findPrevious) { static status_t _CreateMetaDataArea(bool findPrevious,
_area = area; area_id& _area,
_metaData = metaData; TracingMetaData*& _metaData);
return B_OK; static bool _InitPreviousTracingData(
} TracingMetaData* metaData);
if (metaData->magic1 == kMetaDataMagic1 private:
&& metaData->magic2 == kMetaDataMagic2 uint32 fMagic1;
&& metaData->magic3 == kMetaDataMagic3) { trace_entry* fBuffer;
_area = area; trace_entry* fFirstEntry;
_metaData = metaData; trace_entry* fAfterLastEntry;
return B_OK; uint32 fEntries;
} uint32 fMagic2;
uint32 fEntriesEver;
delete_area(area); spinlock fLock;
} char* fTraceOutputBuffer;
addr_t fPhysicalAddress;
return B_ENTRY_NOT_FOUND; uint32 fMagic3;
}
static bool _InitPreviousTracingData(TracingMetaData* metaData)
{
addr_t bufferStart
= (addr_t)metaData->traceOutputBuffer + kTraceOutputBufferSize;
addr_t bufferEnd = bufferStart + MAX_TRACE_SIZE;
if (bufferStart > bufferEnd || (addr_t)metaData->buffer != bufferStart
|| (addr_t)metaData->firstEntry < bufferStart
|| (addr_t)metaData->firstEntry + sizeof(trace_entry) >= bufferEnd
|| (addr_t)metaData->afterLastEntry < bufferStart
|| (addr_t)metaData->afterLastEntry > bufferEnd
|| metaData->physicalAddress == 0) {
dprintf("Failed to init tracing meta data: Sanity checks "
"failed.\n");
return false;
}
// re-map the previous tracing buffer
void* buffer = metaData->traceOutputBuffer;
area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing log",
&buffer, B_EXACT_ADDRESS, kTraceOutputBufferSize + MAX_TRACE_SIZE,
B_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
metaData->physicalAddress, CREATE_AREA_DONT_CLEAR);
if (area < 0) {
dprintf("Failed to init tracing meta data: Mapping tracing log "
"buffer failed: %s\n", strerror(area));
return false;
}
// TODO: More checks:
// * tracing entry counts
// * tracing entries (linked list)
// * tracing entries objects (vtables)
B_INITIALIZE_SPINLOCK(&metaData->lock);
return true;
}
}; };
static TracingMetaData sDummyTracingMetaData; static TracingMetaData sDummyTracingMetaData;
static TracingMetaData* sTracingMetaData = &sDummyTracingMetaData; static TracingMetaData* sTracingMetaData = &sDummyTracingMetaData;
static bool sTracingDataRecovered = false;
static inline trace_entry* // #pragma mark -
Buffer()
// #pragma mark - TracingMetaData
bool
TracingMetaData::Lock()
{ {
return sTracingMetaData->buffer; acquire_spinlock(&fLock);
return true;
} }
static inline trace_entry*& void
FirstEntry() TracingMetaData::Unlock()
{ {
return sTracingMetaData->firstEntry; release_spinlock(&fLock);
} }
static inline trace_entry*& trace_entry*
AfterLastEntry() TracingMetaData::FirstEntry() const
{ {
return sTracingMetaData->afterLastEntry; return fFirstEntry;
} }
static inline uint32& trace_entry*
Entries() TracingMetaData::AfterLastEntry() const
{ {
return sTracingMetaData->entries; return fAfterLastEntry;
} }
static inline uint32& uint32
Written() TracingMetaData::Entries() const
{ {
return sTracingMetaData->written; return fEntries;
} }
static inline spinlock& uint32
Lock() TracingMetaData::EntriesEver() const
{ {
return sTracingMetaData->lock; return fEntriesEver;
} }
static trace_entry* void
next_entry(trace_entry* entry) TracingMetaData::IncrementEntriesEver()
{
fEntriesEver++;
// TODO: Race condition on SMP machines! We should use atomic_add(),
// but that doesn't seem to fix the issue (entries ever < total entries)
// either. It's not critical, anyway.
}
char*
TracingMetaData::TraceOutputBuffer() const
{
return fTraceOutputBuffer;
}
trace_entry*
TracingMetaData::NextEntry(trace_entry* entry)
{ {
entry += entry->size; entry += entry->size;
if ((entry->flags & WRAP_ENTRY) != 0) if ((entry->flags & WRAP_ENTRY) != 0)
entry = Buffer(); entry = fBuffer;
if (entry == AfterLastEntry()) if (entry == fAfterLastEntry)
return NULL; return NULL;
return entry; return entry;
} }
static trace_entry* trace_entry*
previous_entry(trace_entry* entry) TracingMetaData::PreviousEntry(trace_entry* entry)
{ {
if (entry == FirstEntry()) if (entry == fFirstEntry)
return NULL; return NULL;
if (entry == Buffer()) { if (entry == fBuffer) {
// beginning of buffer -- previous entry is a wrap entry // beginning of buffer -- previous entry is a wrap entry
entry = Buffer() + kBufferSize - entry->previous_size; entry = fBuffer + kBufferSize - entry->previous_size;
} }
return entry - entry->previous_size; return entry - entry->previous_size;
} }
static bool trace_entry*
free_first_entry() TracingMetaData::AllocateEntry(size_t size, uint16 flags)
{ {
TRACE((" skip start %p, %lu*4 bytes\n", FirstEntry(), FirstEntry()->size)); if (fAfterLastEntry == NULL || size == 0 || size >= kMaxTracingEntrySize)
return NULL;
trace_entry* newFirst = next_entry(FirstEntry()); InterruptsSpinLocker _(fLock);
if (FirstEntry()->flags & BUFFER_ENTRY) { size = (size + 3) >> 2;
// 4 byte aligned, don't store the lower 2 bits
TRACE(("AllocateEntry(%lu), start %p, end %p, buffer %p\n", size * 4,
fFirstEntry, fAfterLastEntry, fBuffer));
if (!_MakeSpace(size))
return NULL;
trace_entry* entry = fAfterLastEntry;
entry->size = size;
entry->flags = flags;
fAfterLastEntry += size;
fAfterLastEntry->previous_size = size;
if (!(flags & BUFFER_ENTRY))
fEntries++;
TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry,
fAfterLastEntry, fFirstEntry, fEntries));
return entry;
}
bool
TracingMetaData::_FreeFirstEntry()
{
TRACE((" skip start %p, %lu*4 bytes\n", fFirstEntry, fFirstEntry->size));
trace_entry* newFirst = NextEntry(fFirstEntry);
if (fFirstEntry->flags & BUFFER_ENTRY) {
// a buffer entry -- just skip it // a buffer entry -- just skip it
} else if (FirstEntry()->flags & ENTRY_INITIALIZED) { } else if (fFirstEntry->flags & ENTRY_INITIALIZED) {
// fully initialized TraceEntry -- destroy it // fully initialized TraceEntry -- destroy it
TraceEntry::FromTraceEntry(FirstEntry())->~TraceEntry(); TraceEntry::FromTraceEntry(fFirstEntry)->~TraceEntry();
Entries()--; fEntries--;
} else { } else {
// Not fully initialized TraceEntry. We can't free it, since // Not fully initialized TraceEntry. We can't free it, since
// then it's constructor might still write into the memory and // then it's constructor might still write into the memory and
@@ -307,110 +265,260 @@ free_first_entry()
if (newFirst == NULL) { if (newFirst == NULL) {
// everything is freed -- practically this can't happen, if // everything is freed -- practically this can't happen, if
// the buffer is large enough to hold three max-sized entries // the buffer is large enough to hold three max-sized entries
FirstEntry() = AfterLastEntry() = Buffer(); fFirstEntry = fAfterLastEntry = fBuffer;
TRACE(("free_first_entry(): all entries freed!\n")); TRACE(("_FreeFirstEntry(): all entries freed!\n"));
} else } else
FirstEntry() = newFirst; fFirstEntry = newFirst;
return true; return true;
} }
/*! Makes sure we have needed * 4 bytes of memory at AfterLastEntry(). /*! Makes sure we have needed * 4 bytes of memory at fAfterLastEntry.
Returns \c false, if unable to free that much. Returns \c false, if unable to free that much.
*/ */
static bool bool
make_space(size_t needed) TracingMetaData::_MakeSpace(size_t needed)
{ {
// we need space for AfterLastEntry(), too (in case we need to wrap around // we need space for fAfterLastEntry, too (in case we need to wrap around
// later) // later)
needed++; needed++;
// If there's not enough space (free or occupied) after AfterLastEntry(), // If there's not enough space (free or occupied) after fAfterLastEntry,
// we free all entries in that region and wrap around. // we free all entries in that region and wrap around.
if (AfterLastEntry() + needed > Buffer() + kBufferSize) { if (fAfterLastEntry + needed > fBuffer + kBufferSize) {
TRACE(("make_space(%lu), wrapping around: after last: %p\n", needed, TRACE(("_MakeSpace(%lu), wrapping around: after last: %p\n", needed,
AfterLastEntry())); fAfterLastEntry));
// Free all entries after AfterLastEntry() and one more at the beginning // Free all entries after fAfterLastEntry and one more at the beginning
// of the buffer. // of the buffer.
while (FirstEntry() > AfterLastEntry()) { while (fFirstEntry > fAfterLastEntry) {
if (!free_first_entry()) if (!_FreeFirstEntry())
return false; return false;
} }
if (AfterLastEntry() != Buffer() && !free_first_entry()) if (fAfterLastEntry != fBuffer && !_FreeFirstEntry())
return false; return false;
// just in case free_first_entry() freed the very last existing entry // just in case _FreeFirstEntry() freed the very last existing entry
if (AfterLastEntry() == Buffer()) if (fAfterLastEntry == fBuffer)
return true; return true;
// mark as wrap entry and actually wrap around // mark as wrap entry and actually wrap around
trace_entry* wrapEntry = AfterLastEntry(); trace_entry* wrapEntry = fAfterLastEntry;
wrapEntry->size = 0; wrapEntry->size = 0;
wrapEntry->flags = WRAP_ENTRY; wrapEntry->flags = WRAP_ENTRY;
AfterLastEntry() = Buffer(); fAfterLastEntry = fBuffer;
AfterLastEntry()->previous_size = Buffer() + kBufferSize - wrapEntry; fAfterLastEntry->previous_size = fBuffer + kBufferSize - wrapEntry;
} }
if (FirstEntry() <= AfterLastEntry()) { if (fFirstEntry <= fAfterLastEntry) {
// buffer is empty or the space after AfterLastEntry() is unoccupied // buffer is empty or the space after fAfterLastEntry is unoccupied
return true; return true;
} }
// free the first entries, until there's enough space // free the first entries, until there's enough space
size_t space = FirstEntry() - AfterLastEntry(); size_t space = fFirstEntry - fAfterLastEntry;
if (space < needed) { if (space < needed) {
TRACE(("make_space(%lu), left %ld\n", needed, space)); TRACE(("_MakeSpace(%lu), left %ld\n", needed, space));
} }
while (space < needed) { while (space < needed) {
space += FirstEntry()->size; space += fFirstEntry->size;
if (!free_first_entry()) if (!_FreeFirstEntry())
return false; return false;
} }
TRACE((" out: start %p, entries %ld\n", FirstEntry(), Entries())); TRACE((" out: start %p, entries %ld\n", fFirstEntry, fEntries));
return true; return true;
} }
static trace_entry* /*static*/ status_t
allocate_entry(size_t size, uint16 flags) TracingMetaData::Create(TracingMetaData*& _metaData)
{ {
if (AfterLastEntry() == NULL || size == 0 || size >= 65532) // search meta data in memory (from previous session)
area_id area;
TracingMetaData* metaData;
status_t error = _CreateMetaDataArea(true, area, metaData);
if (error == B_OK) {
if (_InitPreviousTracingData(metaData)) {
_metaData = metaData;
return B_OK;
}
dprintf("Found previous tracing meta data, but failed to init.\n");
// invalidate the meta data
metaData->fMagic1 = 0;
metaData->fMagic2 = 0;
metaData->fMagic3 = 0;
delete_area(area);
} else
dprintf("No previous tracing meta data found.\n");
// no previous tracng data found -- create new one
error = _CreateMetaDataArea(false, area, metaData);
if (error != B_OK)
return error;
area = create_area("tracing log",
(void**)&metaData->fTraceOutputBuffer, B_ANY_KERNEL_ADDRESS,
kTraceOutputBufferSize + MAX_TRACE_SIZE, B_CONTIGUOUS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (area < 0)
return area;
// get the physical address
physical_entry physicalEntry;
if (get_memory_map(metaData->fTraceOutputBuffer, B_PAGE_SIZE,
&physicalEntry, 1) == B_OK) {
metaData->fPhysicalAddress = (addr_t)physicalEntry.address;
} else {
dprintf("TracingMetaData::Create(): failed to get physical address "
"of tracing buffer\n");
metaData->fPhysicalAddress = 0;
}
metaData->fBuffer = (trace_entry*)(metaData->fTraceOutputBuffer
+ kTraceOutputBufferSize);
metaData->fFirstEntry = metaData->fBuffer;
metaData->fAfterLastEntry = metaData->fBuffer;
metaData->fEntries = 0;
metaData->fEntriesEver = 0;
B_INITIALIZE_SPINLOCK(&metaData->fLock);
metaData->fMagic1 = kMetaDataMagic1;
metaData->fMagic2 = kMetaDataMagic2;
metaData->fMagic3 = kMetaDataMagic3;
_metaData = metaData;
return B_OK;
}
/*static*/ status_t
TracingMetaData::_CreateMetaDataArea(bool findPrevious, area_id& _area,
TracingMetaData*& _metaData)
{
// search meta data in memory (from previous session)
TracingMetaData* metaData;
addr_t metaDataAddress = kMetaDataBaseAddress;
for (; metaDataAddress <= kMetaDataBaseEndAddress;
metaDataAddress += kMetaDataAddressIncrement) {
area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing metadata",
(void**)&metaData, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE,
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
metaDataAddress, CREATE_AREA_DONT_CLEAR);
if (area < 0)
continue;
if (!findPrevious) {
_area = area;
_metaData = metaData;
return B_OK;
}
if (metaData->fMagic1 == kMetaDataMagic1
&& metaData->fMagic2 == kMetaDataMagic2
&& metaData->fMagic3 == kMetaDataMagic3) {
_area = area;
_metaData = metaData;
return B_OK;
}
delete_area(area);
}
return B_ENTRY_NOT_FOUND;
}
/*static*/ bool
TracingMetaData::_InitPreviousTracingData(TracingMetaData* metaData)
{
addr_t bufferStart
= (addr_t)metaData->fTraceOutputBuffer + kTraceOutputBufferSize;
addr_t bufferEnd = bufferStart + MAX_TRACE_SIZE;
if (bufferStart > bufferEnd || (addr_t)metaData->fBuffer != bufferStart
|| (addr_t)metaData->fFirstEntry % sizeof(trace_entry) != 0
|| (addr_t)metaData->fFirstEntry < bufferStart
|| (addr_t)metaData->fFirstEntry + sizeof(trace_entry) >= bufferEnd
|| (addr_t)metaData->fAfterLastEntry % sizeof(trace_entry) != 0
|| (addr_t)metaData->fAfterLastEntry < bufferStart
|| (addr_t)metaData->fAfterLastEntry > bufferEnd
|| metaData->fPhysicalAddress == 0) {
dprintf("Failed to init tracing meta data: Sanity checks "
"failed.\n");
return false;
}
// re-map the previous tracing buffer
void* buffer = metaData->fTraceOutputBuffer;
area_id area = create_area_etc(B_SYSTEM_TEAM, "tracing log",
&buffer, B_EXACT_ADDRESS, kTraceOutputBufferSize + MAX_TRACE_SIZE,
B_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
metaData->fPhysicalAddress, CREATE_AREA_DONT_CLEAR);
if (area < 0) {
dprintf("Failed to init tracing meta data: Mapping tracing log "
"buffer failed: %s\n", strerror(area));
return false;
}
#if 0
// verify/repair the tracing entry list
uint32 entry
trace_entry* entry = metaData->fFirstEntry;
while (true) {
}
static trace_entry*
next_entry(trace_entry* entry)
{
entry += entry->size;
if ((entry->flags & WRAP_ENTRY) != 0)
entry = fBuffer;
if (entry == fAfterLastEntry)
return NULL; return NULL;
InterruptsSpinLocker _(Lock());
size = (size + 3) >> 2;
// 4 byte aligned, don't store the lower 2 bits
TRACE(("allocate_entry(%lu), start %p, end %p, buffer %p\n", size * 4,
FirstEntry(), AfterLastEntry(), Buffer()));
if (!make_space(size))
return NULL;
trace_entry* entry = AfterLastEntry();
entry->size = size;
entry->flags = flags;
AfterLastEntry() += size;
AfterLastEntry()->previous_size = size;
if (!(flags & BUFFER_ENTRY))
Entries()++;
TRACE((" entry: %p, end %p, start %p, entries %ld\n", entry,
AfterLastEntry(), FirstEntry(), Entries()));
return entry; return entry;
} }
static trace_entry*
previous_entry(trace_entry* entry)
{
if (entry == fFirstEntry)
return NULL;
if (entry == fBuffer) {
// beginning of buffer -- previous entry is a wrap entry
entry = fBuffer + kBufferSize - entry->previous_size;
}
return entry - entry->previous_size;
}
#endif
// TODO: More checks:
// * tracing entry counts
// * tracing entries (linked list)
// * tracing entries objects (vtables)
B_INITIALIZE_SPINLOCK(&metaData->fLock);
sTracingDataRecovered = true;
return true;
}
#endif // ENABLE_TRACING #endif // ENABLE_TRACING
@@ -525,7 +633,7 @@ TraceEntry::Initialized()
{ {
#if ENABLE_TRACING #if ENABLE_TRACING
ToTraceEntry()->flags |= ENTRY_INITIALIZED; ToTraceEntry()->flags |= ENTRY_INITIALIZED;
Written()++; sTracingMetaData->IncrementEntriesEver();
#endif #endif
} }
@@ -534,7 +642,8 @@ void*
TraceEntry::operator new(size_t size, const std::nothrow_t&) throw() TraceEntry::operator new(size_t size, const std::nothrow_t&) throw()
{ {
#if ENABLE_TRACING #if ENABLE_TRACING
trace_entry* entry = allocate_entry(size + sizeof(trace_entry), 0); trace_entry* entry = sTracingMetaData->AllocateEntry(
size + sizeof(trace_entry), 0);
return entry != NULL ? entry + 1 : NULL; return entry != NULL ? entry + 1 : NULL;
#endif #endif
return NULL; return NULL;
@@ -927,10 +1036,10 @@ TraceEntry*
TraceEntryIterator::Next() TraceEntryIterator::Next()
{ {
if (fIndex == 0) { if (fIndex == 0) {
fEntry = _NextNonBufferEntry(FirstEntry()); fEntry = _NextNonBufferEntry(sTracingMetaData->FirstEntry());
fIndex = 1; fIndex = 1;
} else if (fEntry != NULL) { } else if (fEntry != NULL) {
fEntry = _NextNonBufferEntry(next_entry(fEntry)); fEntry = _NextNonBufferEntry(sTracingMetaData->NextEntry(fEntry));
fIndex++; fIndex++;
} }
@@ -941,11 +1050,12 @@ TraceEntryIterator::Next()
TraceEntry* TraceEntry*
TraceEntryIterator::Previous() TraceEntryIterator::Previous()
{ {
if (fIndex == (int32)Entries() + 1) if (fIndex == (int32)sTracingMetaData->Entries() + 1)
fEntry = AfterLastEntry(); fEntry = sTracingMetaData->AfterLastEntry();
if (fEntry != NULL) { if (fEntry != NULL) {
fEntry = _PreviousNonBufferEntry(previous_entry(fEntry)); fEntry = _PreviousNonBufferEntry(
sTracingMetaData->PreviousEntry(fEntry));
fIndex--; fIndex--;
} }
@@ -959,8 +1069,8 @@ TraceEntryIterator::MoveTo(int32 index)
if (index == fIndex) if (index == fIndex)
return Current(); return Current();
if (index <= 0 || index > (int32)Entries()) { if (index <= 0 || index > (int32)sTracingMetaData->Entries()) {
fIndex = (index <= 0 ? 0 : Entries() + 1); fIndex = (index <= 0 ? 0 : sTracingMetaData->Entries() + 1);
fEntry = NULL; fEntry = NULL;
return NULL; return NULL;
} }
@@ -976,11 +1086,11 @@ TraceEntryIterator::MoveTo(int32 index)
fEntry = NULL; fEntry = NULL;
fIndex = 0; fIndex = 0;
} }
if ((int32)Entries() + 1 - fIndex < distance) { if ((int32)sTracingMetaData->Entries() + 1 - fIndex < distance) {
distance = Entries() + 1 - fIndex; distance = sTracingMetaData->Entries() + 1 - fIndex;
direction = -1; direction = -1;
fEntry = NULL; fEntry = NULL;
fIndex = Entries() + 1; fIndex = sTracingMetaData->Entries() + 1;
} }
// iterate to the index // iterate to the index
@@ -1000,7 +1110,7 @@ trace_entry*
TraceEntryIterator::_NextNonBufferEntry(trace_entry* entry) TraceEntryIterator::_NextNonBufferEntry(trace_entry* entry)
{ {
while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0) while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0)
entry = next_entry(entry); entry = sTracingMetaData->NextEntry(entry);
return entry; return entry;
} }
@@ -1010,7 +1120,7 @@ trace_entry*
TraceEntryIterator::_PreviousNonBufferEntry(trace_entry* entry) TraceEntryIterator::_PreviousNonBufferEntry(trace_entry* entry)
{ {
while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0) while (entry != NULL && (entry->flags & BUFFER_ENTRY) != 0)
entry = previous_entry(entry); entry = sTracingMetaData->PreviousEntry(entry);
return entry; return entry;
} }
@@ -1029,11 +1139,13 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
static int32 _previousFirstChecked = 1; static int32 _previousFirstChecked = 1;
static int32 _previousLastChecked = -1; static int32 _previousLastChecked = -1;
static int32 _previousDirection = 1; static int32 _previousDirection = 1;
static uint32 _previousWritten = 0; static uint32 _previousEntriesEver = 0;
static uint32 _previousEntries = 0; static uint32 _previousEntries = 0;
static uint32 _previousOutputFlags = 0; static uint32 _previousOutputFlags = 0;
static TraceEntryIterator iterator; static TraceEntryIterator iterator;
uint32 entriesEver = sTracingMetaData->EntriesEver();
// Note: start and index are Pascal-like indices (i.e. in [1, Entries()]). // Note: start and index are Pascal-like indices (i.e. in [1, Entries()]).
int32 start = 0; // special index: print the last count entries int32 start = 0; // special index: print the last count entries
int32 count = 0; int32 count = 0;
@@ -1074,8 +1186,8 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
print_debugger_command_usage(argv[0]); print_debugger_command_usage(argv[0]);
return 0; return 0;
} }
if (Written() == 0 || Written() != _previousWritten if (entriesEver == 0 || entriesEver != _previousEntriesEver
|| Entries() != _previousEntries) { || sTracingMetaData->Entries() != _previousEntries) {
kprintf("Can't continue iteration. \"%s\" has not been invoked " kprintf("Can't continue iteration. \"%s\" has not been invoked "
"before, or there were new entries written since the last " "before, or there were new entries written since the last "
"invocation.\n", argv[0]); "invocation.\n", argv[0]);
@@ -1133,7 +1245,7 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
if (maxToCheck == 0 || !hasFilter) if (maxToCheck == 0 || !hasFilter)
maxToCheck = count; maxToCheck = count;
else if (maxToCheck < 0) else if (maxToCheck < 0)
maxToCheck = Entries(); maxToCheck = sTracingMetaData->Entries();
// determine iteration direction // determine iteration direction
direction = (start <= 0 || count < 0 ? -1 : 1); direction = (start <= 0 || count < 0 ? -1 : 1);
@@ -1143,14 +1255,14 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
count = -count; count = -count;
if (maxToCheck < 0) if (maxToCheck < 0)
maxToCheck = -maxToCheck; maxToCheck = -maxToCheck;
if (maxToCheck > (int32)Entries()) if (maxToCheck > (int32)sTracingMetaData->Entries())
maxToCheck = Entries(); maxToCheck = sTracingMetaData->Entries();
if (count > maxToCheck) if (count > maxToCheck)
count = maxToCheck; count = maxToCheck;
// validate start // validate start
if (start <= 0 || start > (int32)Entries()) if (start <= 0 || start > (int32)sTracingMetaData->Entries())
start = max_c(1, Entries()); start = max_c(1, sTracingMetaData->Entries());
} }
if (direction < 0) { if (direction < 0) {
@@ -1158,16 +1270,17 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
lastToCheck = start; lastToCheck = start;
} else { } else {
firstToCheck = start; firstToCheck = start;
lastToCheck = min_c((int32)Entries(), start + maxToCheck - 1); lastToCheck = min_c((int32)sTracingMetaData->Entries(),
start + maxToCheck - 1);
} }
// reset the iterator, if something changed in the meantime // reset the iterator, if something changed in the meantime
if (Written() == 0 || Written() != _previousWritten if (entriesEver == 0 || entriesEver != _previousEntriesEver
|| Entries() != _previousEntries) { || sTracingMetaData->Entries() != _previousEntries) {
iterator.Reset(); iterator.Reset();
} }
LazyTraceOutput out(sTracingMetaData->traceOutputBuffer, LazyTraceOutput out(sTracingMetaData->TraceOutputBuffer(),
kTraceOutputBufferSize, outputFlags); kTraceOutputBufferSize, outputFlags);
bool markedMatching = false; bool markedMatching = false;
@@ -1271,7 +1384,8 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, " kprintf("printed %ld entries within range %ld to %ld (%ld of %ld total, "
"%ld ever)\n", dumped, firstToCheck, lastToCheck, "%ld ever)\n", dumped, firstToCheck, lastToCheck,
lastToCheck - firstToCheck + 1, Entries(), Written()); lastToCheck - firstToCheck + 1, sTracingMetaData->Entries(),
entriesEver);
// store iteration state // store iteration state
_previousCount = count; _previousCount = count;
@@ -1281,8 +1395,8 @@ dump_tracing_internal(int argc, char** argv, WrapperTraceFilter* wrapperFilter)
_previousFirstChecked = firstToCheck; _previousFirstChecked = firstToCheck;
_previousLastChecked = lastToCheck; _previousLastChecked = lastToCheck;
_previousDirection = direction; _previousDirection = direction;
_previousWritten = Written(); _previousEntriesEver = entriesEver;
_previousEntries = Entries(); _previousEntries = sTracingMetaData->Entries();
_previousOutputFlags = outputFlags; _previousOutputFlags = outputFlags;
return cont != 0 ? B_KDEBUG_CONT : 0; return cont != 0 ? B_KDEBUG_CONT : 0;
@@ -1303,8 +1417,8 @@ extern "C" uint8*
alloc_tracing_buffer(size_t size) alloc_tracing_buffer(size_t size)
{ {
#if ENABLE_TRACING #if ENABLE_TRACING
trace_entry* entry = allocate_entry(size + sizeof(trace_entry), trace_entry* entry = sTracingMetaData->AllocateEntry(
BUFFER_ENTRY); size + sizeof(trace_entry), BUFFER_ENTRY);
if (entry == NULL) if (entry == NULL)
return NULL; return NULL;
@@ -1409,7 +1523,7 @@ void
lock_tracing_buffer() lock_tracing_buffer()
{ {
#if ENABLE_TRACING #if ENABLE_TRACING
acquire_spinlock(&Lock()); sTracingMetaData->Lock();
#endif #endif
} }
@@ -1418,7 +1532,7 @@ void
unlock_tracing_buffer() unlock_tracing_buffer()
{ {
#if ENABLE_TRACING #if ENABLE_TRACING
release_spinlock(&Lock()); sTracingMetaData->Unlock();
#endif #endif
} }