* Added an abstraction for getting an BDataIO, DataSource and derived classes,
  which allows to move I/O completely out of the GUI threads.
* Fleshed out application start, window creation, and file loading. We do now
  create a window for every command line argument and load the referenced file
  or, if none, create an empty window.
* Some improvements in the file loader. It does now correctly load the file,
  but doesn't process the stored data yet.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30274 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-04-19 23:55:17 +00:00
parent 4d8d8c1f38
commit c442235ebd
9 changed files with 456 additions and 74 deletions

View File

@ -0,0 +1,84 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "DataSource.h"
#include <new>
// #pragma mark - DataSource
DataSource::DataSource()
{
}
DataSource::~DataSource()
{
}
// #pragma mark - FileDataSource
status_t
FileDataSource::CreateDataIO(BDataIO** _io)
{
BFile* file = new(std::nothrow) BFile;
if (file == NULL)
return B_NO_MEMORY;
status_t error = OpenFile(*file);
if (error != B_OK) {
delete file;
return error;
}
*_io = file;
return B_OK;
}
// #pragma mark - PathDataSource
status_t
PathDataSource::Init(const char* path)
{
return fPath.SetTo(path);
}
status_t
PathDataSource::OpenFile(BFile& file)
{
return file.SetTo(fPath.Path(), B_READ_ONLY);
}
// #pragma mark - EntryRefDataSource
status_t
EntryRefDataSource::Init(const entry_ref* ref)
{
if (ref->name == NULL)
return B_BAD_VALUE;
fRef = *ref;
if (fRef.name == NULL)
return B_NO_MEMORY;
return B_OK;
}
status_t
EntryRefDataSource::OpenFile(BFile& file)
{
return file.SetTo(&fRef, B_READ_ONLY);
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef DATA_SOURCE_H
#define DATA_SOURCE_H
#include <Entry.h>
#include <File.h>
#include <Path.h>
class DataSource {
public:
DataSource();
virtual ~DataSource();
virtual status_t CreateDataIO(BDataIO** _io) = 0;
};
class FileDataSource : public DataSource {
public:
virtual status_t CreateDataIO(BDataIO** _io);
protected:
virtual status_t OpenFile(BFile& file) = 0;
};
class PathDataSource : public FileDataSource {
public:
status_t Init(const char* path);
protected:
virtual status_t OpenFile(BFile& file);
private:
BPath fPath;
};
class EntryRefDataSource : public FileDataSource {
public:
status_t Init(const entry_ref* ref);
protected:
virtual status_t OpenFile(BFile& file);
private:
entry_ref fRef;
};
#endif // DATA_SOURCE_H

View File

@ -3,13 +3,19 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <new> #include <new>
#include <Application.h> #include <Application.h>
#include <AutoDeleter.h>
#include "DataSource.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "MessageCodes.h"
static const char* const kSignature = "application/x-vnd.Haiku-DebugAnalyzer"; static const char* const kSignature = "application/x-vnd.Haiku-DebugAnalyzer";
@ -19,23 +25,89 @@ class DebugAnalyzer : public BApplication {
public: public:
DebugAnalyzer() DebugAnalyzer()
: :
BApplication(kSignature) BApplication(kSignature),
fWindowCount(0)
{ {
} }
virtual void ReadyToRun() virtual void ReadyToRun()
{ {
MainWindow* window; printf("ReadyToRun()\n");
try { if (fWindowCount == 0 && _CreateWindow(NULL) != B_OK)
window = new MainWindow; PostMessage(B_QUIT_REQUESTED);
} catch (std::bad_alloc) { }
exit(1);
virtual void ArgvReceived(int32 argc, char** argv)
{
printf("ArgvReceived()\n");
for (int32 i = 0; i < argc; i++)
printf(" arg %ld: \"%s\"\n", i, argv[i]);
for (int32 i = 1; i < argc; i++) {
PathDataSource* dataSource = new(std::nothrow) PathDataSource;
if (dataSource == NULL) {
// no memory
fprintf(stderr, "DebugAnalyzer::ArgvReceived(): Out of "
"memory!");
return;
}
status_t error = dataSource->Init(argv[i]);
if (error != B_OK) {
fprintf(stderr, "Failed to create data source for path "
"\"%s\": %s\n", argv[i], strerror(error));
// TODO: Alert!
continue;
}
_CreateWindow(dataSource);
} }
window->Show(); }
virtual void RefsReceived(BMessage* message)
{
printf("RefsReceived()\n");
} }
private: private:
status_t _CreateWindow(DataSource* dataSource)
{
ObjectDeleter<DataSource> dataSourceDeleter(dataSource);
MainWindow* window;
try {
window = new MainWindow(dataSource);
} catch (std::bad_alloc) {
fprintf(stderr, "DebugAnalyzer::_CreateWindow(): Out of memory!\n");
return B_NO_MEMORY;
}
// the data source is owned by the window now
dataSourceDeleter.Detach();
window->Show();
fWindowCount++;
return B_OK;
}
virtual void MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_WINDOW_QUIT:
if (--fWindowCount == 0)
PostMessage(B_QUIT_REQUESTED);
break;
default:
BApplication::MessageReceived(message);
break;
}
}
private:
int32 fWindowCount;
}; };

View File

@ -5,6 +5,7 @@ UsePrivateSystemHeaders ;
Application DebugAnalyzer Application DebugAnalyzer
: :
DataSource.cpp
DebugAnalyzer.cpp DebugAnalyzer.cpp
MainModel.cpp MainModel.cpp
MainModelLoader.cpp MainModelLoader.cpp

View File

@ -5,22 +5,30 @@
#include "MainModelLoader.h" #include "MainModelLoader.h"
#include <stdio.h>
#include <string.h>
#include <new> #include <new>
#include <AutoDeleter.h> #include <AutoDeleter.h>
#include <AutoLocker.h> #include <AutoLocker.h>
#include <DebugEventStream.h> #include <DebugEventStream.h>
#include <system_profiler_defs.h>
#include "DataSource.h"
#include "MainModel.h" #include "MainModel.h"
#include "MessageCodes.h" #include "MessageCodes.h"
MainModelLoader::MainModelLoader() MainModelLoader::MainModelLoader(DataSource* dataSource,
const BMessenger& target, void* targetCookie)
: :
fLock("main model loader"), fLock("main model loader"),
fModel(NULL), fModel(NULL),
fInput(NULL), fDataSource(dataSource),
fTarget(), fTarget(target),
fTargetCookie(targetCookie),
fLoaderThread(-1), fLoaderThread(-1),
fLoading(false), fLoading(false),
fAborted(false) fAborted(false)
@ -35,13 +43,13 @@ MainModelLoader::~MainModelLoader()
wait_for_thread(fLoaderThread, NULL); wait_for_thread(fLoaderThread, NULL);
} }
delete fInput; delete fDataSource;
delete fModel; delete fModel;
} }
status_t status_t
MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target) MainModelLoader::StartLoading()
{ {
// check initialization // check initialization
status_t error = fLock.InitCheck(); status_t error = fLock.InitCheck();
@ -50,7 +58,7 @@ MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target)
AutoLocker<BLocker> locker(fLock); AutoLocker<BLocker> locker(fLock);
if (fModel != NULL) if (fModel != NULL || fLoading || fDataSource == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
// create a model // create a model
@ -59,17 +67,6 @@ MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target)
return B_NO_MEMORY; return B_NO_MEMORY;
ObjectDeleter<MainModel> modelDeleter(model); ObjectDeleter<MainModel> modelDeleter(model);
// create a debug input stream
BDebugEventInputStream* inputStream
= new(std::nothrow) BDebugEventInputStream;
if (inputStream == NULL)
return B_NO_MEMORY;
ObjectDeleter<BDebugEventInputStream> inputDeleter(inputStream);
error = inputStream->SetTo(&input);
if (error != B_OK)
return error;
// spawn the loader thread // spawn the loader thread
fLoaderThread = spawn_thread(&_LoaderEntry, "main model loader", fLoaderThread = spawn_thread(&_LoaderEntry, "main model loader",
B_NORMAL_PRIORITY, this); B_NORMAL_PRIORITY, this);
@ -77,9 +74,7 @@ MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target)
return fLoaderThread; return fLoaderThread;
modelDeleter.Detach(); modelDeleter.Detach();
inputDeleter.Detach();
fModel = model; fModel = model;
fInput = inputStream;
fLoading = true; fLoading = true;
fAborted = false; fAborted = false;
@ -127,64 +122,134 @@ MainModelLoader::_LoaderEntry(void* data)
status_t status_t
MainModelLoader::_Loader() MainModelLoader::_Loader()
{ {
bool success = false; printf("MainModelLoader::_Loader()\n");
status_t error;
uint32 count = 0;
try { try {
while (true) { error = _Load();
// get next event } catch(...) {
uint32 event; printf("MainModelLoader::_Loader(): caught exception\n");
uint32 cpu; error = B_ERROR;
const void* buffer;
ssize_t bufferSize = fInput->ReadNextEvent(&event, &cpu, &buffer);
if (bufferSize < 0)
break;
if (buffer == NULL) {
success = true;
break;
}
// process the event
status_t error = _ProcessEvent(event, cpu, buffer, bufferSize);
if (error != B_OK)
break;
if (++count % 32 == 0) {
AutoLocker<BLocker> locker(fLock);
if (fAborted)
break;
}
}
} catch (...) {
} }
printf("MainModelLoader::_Loader(): _Load() done: %s\n", strerror(error));
// clean up and notify the target // clean up and notify the target
AutoLocker<BLocker> locker(fLock); AutoLocker<BLocker> locker(fLock);
delete fInput; BMessage message;
fInput = NULL; if (error == B_OK) {
message.what = MSG_MODEL_LOADED_SUCCESSFULLY;
if (success) {
fTarget.SendMessage(MSG_MODEL_LOADED_SUCCESSFULLY);
} else { } else {
delete fModel; delete fModel;
fModel = NULL; fModel = NULL;
fTarget.SendMessage( message.what = fAborted
fAborted ? MSG_MODEL_LOADED_ABORTED : MSG_MODEL_LOADED_FAILED); ? MSG_MODEL_LOADED_ABORTED : MSG_MODEL_LOADED_FAILED;
} }
message.AddPointer("loader", this);
message.AddPointer("targetCookie", fTargetCookie);
fTarget.SendMessage(&message);
fLoading = false; fLoading = false;
return B_OK; return B_OK;
} }
status_t
MainModelLoader::_Load()
{
// get a BDataIO from the data source
BDataIO* io;
status_t error = fDataSource->CreateDataIO(&io);
if (error != B_OK)
return error;
ObjectDeleter<BDataIO> dataIOtDeleter(io);
// create a debug input stream
BDebugEventInputStream* input = new(std::nothrow) BDebugEventInputStream;
if (input == NULL)
return B_NO_MEMORY;
ObjectDeleter<BDebugEventInputStream> inputDeleter(input);
error = input->SetTo(io);
if (error != B_OK)
{
printf("MainModelLoader::_Load(): initializing the debug input stream failed: %s\n", strerror(error));
return error;
}
// process the events
uint32 count = 0;
while (true) {
// get next event
uint32 event;
uint32 cpu;
const void* buffer;
ssize_t bufferSize = input->ReadNextEvent(&event, &cpu, &buffer);
if (bufferSize < 0)
{
printf("MainModelLoader::_Load(): reading event failed: %s\n", strerror(bufferSize));
return bufferSize;
}
if (buffer == NULL)
return B_OK;
// process the event
status_t error = _ProcessEvent(event, cpu, buffer, bufferSize);
if (error != B_OK)
return error;
// periodically check whether we're supposed to abort
if (++count % 32 == 0) {
AutoLocker<BLocker> locker(fLock);
if (fAborted)
return B_ERROR;
}
}
}
status_t status_t
MainModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, MainModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer,
size_t size) size_t size)
{ {
switch (event) {
case B_SYSTEM_PROFILER_TEAM_ADDED:
printf("B_SYSTEM_PROFILER_TEAM_ADDED: %lu\n", size);
break;
case B_SYSTEM_PROFILER_TEAM_REMOVED:
printf("B_SYSTEM_PROFILER_TEAM_REMOVED: %lu\n", size);
break;
case B_SYSTEM_PROFILER_TEAM_EXEC:
printf("B_SYSTEM_PROFILER_TEAM_EXEC: %lu\n", size);
break;
case B_SYSTEM_PROFILER_THREAD_ADDED:
printf("B_SYSTEM_PROFILER_THREAD_ADDED: %lu\n", size);
break;
case B_SYSTEM_PROFILER_THREAD_REMOVED:
printf("B_SYSTEM_PROFILER_THREAD_REMOVED: %lu\n", size);
break;
case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
printf("B_SYSTEM_PROFILER_THREAD_SCHEDULED: %lu\n", size);
break;
case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
printf("B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE: %lu\n", size);
break;
case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
printf("B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE: %lu\n", size);
break;
case B_SYSTEM_PROFILER_WAIT_OBJECT_INFO:
printf("B_SYSTEM_PROFILER_WAIT_OBJECT_INFO: %lu\n", size);
break;
default:
printf("unsupported event type %lu, size: %lu\n", event, size);
return B_BAD_DATA;
break;
}
// TODO: Implement! // TODO: Implement!
return B_ERROR; return B_OK;
} }

View File

@ -11,17 +11,19 @@
class BDataIO; class BDataIO;
class BDebugEventInputStream; class BDebugEventInputStream;
class DataSource;
class MainModel; class MainModel;
struct system_profiler_event_header; struct system_profiler_event_header;
class MainModelLoader { class MainModelLoader {
public: public:
MainModelLoader(); MainModelLoader(DataSource* dataSource,
const BMessenger& target,
void* targetCookie);
~MainModelLoader(); ~MainModelLoader();
status_t StartLoading(BDataIO& input, status_t StartLoading();
const BMessenger& target);
void Abort(); void Abort();
MainModel* DetachModel(); MainModel* DetachModel();
@ -29,14 +31,16 @@ public:
private: private:
static status_t _LoaderEntry(void* data); static status_t _LoaderEntry(void* data);
status_t _Loader(); status_t _Loader();
status_t _Load();
status_t _ProcessEvent(uint32 event, uint32 cpu, status_t _ProcessEvent(uint32 event, uint32 cpu,
const void* buffer, size_t size); const void* buffer, size_t size);
private: private:
BLocker fLock; BLocker fLock;
MainModel* fModel; MainModel* fModel;
BDebugEventInputStream* fInput; DataSource* fDataSource;
BMessenger fTarget; BMessenger fTarget;
void* fTargetCookie;
thread_id fLoaderThread; thread_id fLoaderThread;
bool fLoading; bool fLoading;
bool fAborted; bool fAborted;

View File

@ -5,17 +5,28 @@
#include "MainWindow.h" #include "MainWindow.h"
#include <stdio.h>
#include <Application.h>
#include <GroupLayoutBuilder.h> #include <GroupLayoutBuilder.h>
#include <TabView.h> #include <TabView.h>
#include <AutoLocker.h>
#include "DataSource.h"
#include "MainModel.h"
#include "MainModelLoader.h"
#include "MessageCodes.h"
#include "ThreadsPage.h" #include "ThreadsPage.h"
MainWindow::MainWindow() MainWindow::MainWindow(DataSource* dataSource)
: :
BWindow(BRect(50, 50, 599, 499), "DebugAnalyzer", B_DOCUMENT_WINDOW, BWindow(BRect(50, 50, 599, 499), "DebugAnalyzer", B_DOCUMENT_WINDOW,
B_ASYNCHRONOUS_CONTROLS), B_ASYNCHRONOUS_CONTROLS),
fMainTabView(NULL) fMainTabView(NULL),
fModel(NULL),
fModelLoader(NULL)
{ {
BGroupLayout* rootLayout = new BGroupLayout(B_VERTICAL); BGroupLayout* rootLayout = new BGroupLayout(B_VERTICAL);
SetLayout(rootLayout); SetLayout(rootLayout);
@ -27,9 +38,83 @@ MainWindow::MainWindow()
fMainTabView->AddTab(new BView("Teams", 0)); fMainTabView->AddTab(new BView("Teams", 0));
fMainTabView->AddTab(new ThreadsPage); fMainTabView->AddTab(new ThreadsPage);
// create a model loader, if we have a data source
if (dataSource != NULL)
fModelLoader = new MainModelLoader(dataSource, BMessenger(this), NULL);
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete fModelLoader;
delete fModel;
}
void
MainWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_MODEL_LOADED_SUCCESSFULLY:
{
printf("MSG_MODEL_LOADED_SUCCESSFULLY\n");
MainModel* model = fModelLoader->DetachModel();
delete fModelLoader;
fModelLoader = NULL;
_SetModel(model);
break;
}
case MSG_MODEL_LOADED_FAILED:
case MSG_MODEL_LOADED_ABORTED:
{
printf("MSG_MODEL_LOADED_FAILED/MSG_MODEL_LOADED_ABORTED\n");
delete fModelLoader;
fModelLoader = NULL;
// TODO: User feedback (in failed case)!
break;
}
default:
BWindow::MessageReceived(message);
break;
}
}
void
MainWindow::Quit()
{
be_app->PostMessage(MSG_WINDOW_QUIT);
BWindow::Quit();
}
void
MainWindow::Show()
{
BWindow::Show();
AutoLocker<MainWindow> locker;
if (fModelLoader == NULL)
return;
status_t error = fModelLoader->StartLoading();
if (error != B_OK) {
delete fModelLoader;
fModelLoader = NULL;
// TODO: User feedback!
}
}
void
MainWindow::_SetModel(MainModel* model)
{
delete fModel;
fModel = model;
} }

View File

@ -9,15 +9,29 @@
class BTabView; class BTabView;
class DataSource;
class MainModel;
class MainModelLoader;
class MainWindow : public BWindow { class MainWindow : public BWindow {
public: public:
MainWindow(); MainWindow(DataSource* dataSource);
virtual ~MainWindow(); virtual ~MainWindow();
virtual void MessageReceived(BMessage* message);
virtual void Quit();
virtual void Show();
private:
void _SetModel(MainModel* model);
private: private:
BTabView* fMainTabView; BTabView* fMainTabView;
MainModel* fModel;
MainModelLoader* fModelLoader;
}; };

View File

@ -7,9 +7,11 @@
enum { enum {
MSG_MODEL_LOADED_SUCCESSFULLY = 'mlsc', MSG_MODEL_LOADED_SUCCESSFULLY = 'mlsc',
MSG_MODEL_LOADED_FAILED = 'mlfl', MSG_MODEL_LOADED_FAILED = 'mlfl',
MSG_MODEL_LOADED_ABORTED = 'mlab' MSG_MODEL_LOADED_ABORTED = 'mlab',
MSG_WINDOW_QUIT = 'wiqt'
}; };