From c442235ebd8660cbc5544829a811b439c8029fe6 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Apr 2009 23:55:17 +0000 Subject: [PATCH] WiP: * 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 --- src/apps/debuganalyzer/DataSource.cpp | 84 ++++++++++ src/apps/debuganalyzer/DataSource.h | 55 +++++++ src/apps/debuganalyzer/DebugAnalyzer.cpp | 86 +++++++++- src/apps/debuganalyzer/Jamfile | 1 + src/apps/debuganalyzer/MainModelLoader.cpp | 179 ++++++++++++++------- src/apps/debuganalyzer/MainModelLoader.h | 12 +- src/apps/debuganalyzer/MainWindow.cpp | 89 +++++++++- src/apps/debuganalyzer/MainWindow.h | 16 +- src/apps/debuganalyzer/MessageCodes.h | 8 +- 9 files changed, 456 insertions(+), 74 deletions(-) create mode 100644 src/apps/debuganalyzer/DataSource.cpp create mode 100644 src/apps/debuganalyzer/DataSource.h diff --git a/src/apps/debuganalyzer/DataSource.cpp b/src/apps/debuganalyzer/DataSource.cpp new file mode 100644 index 0000000000..a7f175d8c1 --- /dev/null +++ b/src/apps/debuganalyzer/DataSource.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "DataSource.h" + +#include + + +// #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); +} diff --git a/src/apps/debuganalyzer/DataSource.h b/src/apps/debuganalyzer/DataSource.h new file mode 100644 index 0000000000..a5fa2c566a --- /dev/null +++ b/src/apps/debuganalyzer/DataSource.h @@ -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 +#include +#include + + +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 diff --git a/src/apps/debuganalyzer/DebugAnalyzer.cpp b/src/apps/debuganalyzer/DebugAnalyzer.cpp index f1387b8753..3405f8e05f 100644 --- a/src/apps/debuganalyzer/DebugAnalyzer.cpp +++ b/src/apps/debuganalyzer/DebugAnalyzer.cpp @@ -3,13 +3,19 @@ * Distributed under the terms of the MIT License. */ +#include #include +#include #include #include +#include + +#include "DataSource.h" #include "MainWindow.h" +#include "MessageCodes.h" static const char* const kSignature = "application/x-vnd.Haiku-DebugAnalyzer"; @@ -19,23 +25,89 @@ class DebugAnalyzer : public BApplication { public: DebugAnalyzer() : - BApplication(kSignature) + BApplication(kSignature), + fWindowCount(0) { } virtual void ReadyToRun() { - MainWindow* window; - try { - window = new MainWindow; - } catch (std::bad_alloc) { - exit(1); +printf("ReadyToRun()\n"); + if (fWindowCount == 0 && _CreateWindow(NULL) != B_OK) + PostMessage(B_QUIT_REQUESTED); + } + + 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: + status_t _CreateWindow(DataSource* dataSource) + { + ObjectDeleter 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; }; diff --git a/src/apps/debuganalyzer/Jamfile b/src/apps/debuganalyzer/Jamfile index 509bb1a553..dc264926fa 100644 --- a/src/apps/debuganalyzer/Jamfile +++ b/src/apps/debuganalyzer/Jamfile @@ -5,6 +5,7 @@ UsePrivateSystemHeaders ; Application DebugAnalyzer : + DataSource.cpp DebugAnalyzer.cpp MainModel.cpp MainModelLoader.cpp diff --git a/src/apps/debuganalyzer/MainModelLoader.cpp b/src/apps/debuganalyzer/MainModelLoader.cpp index ad0b884c7f..4360f780a0 100644 --- a/src/apps/debuganalyzer/MainModelLoader.cpp +++ b/src/apps/debuganalyzer/MainModelLoader.cpp @@ -5,22 +5,30 @@ #include "MainModelLoader.h" +#include +#include + #include #include #include #include +#include + +#include "DataSource.h" #include "MainModel.h" #include "MessageCodes.h" -MainModelLoader::MainModelLoader() +MainModelLoader::MainModelLoader(DataSource* dataSource, + const BMessenger& target, void* targetCookie) : fLock("main model loader"), fModel(NULL), - fInput(NULL), - fTarget(), + fDataSource(dataSource), + fTarget(target), + fTargetCookie(targetCookie), fLoaderThread(-1), fLoading(false), fAborted(false) @@ -35,13 +43,13 @@ MainModelLoader::~MainModelLoader() wait_for_thread(fLoaderThread, NULL); } - delete fInput; + delete fDataSource; delete fModel; } status_t -MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target) +MainModelLoader::StartLoading() { // check initialization status_t error = fLock.InitCheck(); @@ -50,7 +58,7 @@ MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target) AutoLocker locker(fLock); - if (fModel != NULL) + if (fModel != NULL || fLoading || fDataSource == NULL) return B_BAD_VALUE; // create a model @@ -59,17 +67,6 @@ MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target) return B_NO_MEMORY; ObjectDeleter modelDeleter(model); - // create a debug input stream - BDebugEventInputStream* inputStream - = new(std::nothrow) BDebugEventInputStream; - if (inputStream == NULL) - return B_NO_MEMORY; - ObjectDeleter inputDeleter(inputStream); - - error = inputStream->SetTo(&input); - if (error != B_OK) - return error; - // spawn the loader thread fLoaderThread = spawn_thread(&_LoaderEntry, "main model loader", B_NORMAL_PRIORITY, this); @@ -77,9 +74,7 @@ MainModelLoader::StartLoading(BDataIO& input, const BMessenger& target) return fLoaderThread; modelDeleter.Detach(); - inputDeleter.Detach(); fModel = model; - fInput = inputStream; fLoading = true; fAborted = false; @@ -127,64 +122,134 @@ MainModelLoader::_LoaderEntry(void* data) status_t MainModelLoader::_Loader() { - bool success = false; - - uint32 count = 0; - +printf("MainModelLoader::_Loader()\n"); + status_t error; try { - while (true) { - // get next event - uint32 event; - uint32 cpu; - 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 locker(fLock); - if (fAborted) - break; - } - } - } catch (...) { + error = _Load(); + } catch(...) { +printf("MainModelLoader::_Loader(): caught exception\n"); + error = B_ERROR; } - +printf("MainModelLoader::_Loader(): _Load() done: %s\n", strerror(error)); + // clean up and notify the target AutoLocker locker(fLock); - delete fInput; - fInput = NULL; - - if (success) { - fTarget.SendMessage(MSG_MODEL_LOADED_SUCCESSFULLY); + BMessage message; + if (error == B_OK) { + message.what = MSG_MODEL_LOADED_SUCCESSFULLY; } else { delete fModel; fModel = NULL; - fTarget.SendMessage( - fAborted ? MSG_MODEL_LOADED_ABORTED : MSG_MODEL_LOADED_FAILED); + message.what = fAborted + ? MSG_MODEL_LOADED_ABORTED : MSG_MODEL_LOADED_FAILED; } + message.AddPointer("loader", this); + message.AddPointer("targetCookie", fTargetCookie); + fTarget.SendMessage(&message); + fLoading = false; 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 dataIOtDeleter(io); + + // create a debug input stream + BDebugEventInputStream* input = new(std::nothrow) BDebugEventInputStream; + if (input == NULL) + return B_NO_MEMORY; + ObjectDeleter 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 locker(fLock); + if (fAborted) + return B_ERROR; + } + } +} + + status_t MainModelLoader::_ProcessEvent(uint32 event, uint32 cpu, const void* buffer, 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! - return B_ERROR; + return B_OK; } diff --git a/src/apps/debuganalyzer/MainModelLoader.h b/src/apps/debuganalyzer/MainModelLoader.h index a8fcba097f..57e280da6f 100644 --- a/src/apps/debuganalyzer/MainModelLoader.h +++ b/src/apps/debuganalyzer/MainModelLoader.h @@ -11,17 +11,19 @@ class BDataIO; class BDebugEventInputStream; +class DataSource; class MainModel; struct system_profiler_event_header; class MainModelLoader { public: - MainModelLoader(); + MainModelLoader(DataSource* dataSource, + const BMessenger& target, + void* targetCookie); ~MainModelLoader(); - status_t StartLoading(BDataIO& input, - const BMessenger& target); + status_t StartLoading(); void Abort(); MainModel* DetachModel(); @@ -29,14 +31,16 @@ public: private: static status_t _LoaderEntry(void* data); status_t _Loader(); + status_t _Load(); status_t _ProcessEvent(uint32 event, uint32 cpu, const void* buffer, size_t size); private: BLocker fLock; MainModel* fModel; - BDebugEventInputStream* fInput; + DataSource* fDataSource; BMessenger fTarget; + void* fTargetCookie; thread_id fLoaderThread; bool fLoading; bool fAborted; diff --git a/src/apps/debuganalyzer/MainWindow.cpp b/src/apps/debuganalyzer/MainWindow.cpp index af645f0a7d..6e9321c1fc 100644 --- a/src/apps/debuganalyzer/MainWindow.cpp +++ b/src/apps/debuganalyzer/MainWindow.cpp @@ -5,17 +5,28 @@ #include "MainWindow.h" +#include + +#include #include #include +#include + +#include "DataSource.h" +#include "MainModel.h" +#include "MainModelLoader.h" +#include "MessageCodes.h" #include "ThreadsPage.h" -MainWindow::MainWindow() +MainWindow::MainWindow(DataSource* dataSource) : BWindow(BRect(50, 50, 599, 499), "DebugAnalyzer", B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS), - fMainTabView(NULL) + fMainTabView(NULL), + fModel(NULL), + fModelLoader(NULL) { BGroupLayout* rootLayout = new BGroupLayout(B_VERTICAL); SetLayout(rootLayout); @@ -27,9 +38,83 @@ MainWindow::MainWindow() fMainTabView->AddTab(new BView("Teams", 0)); 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() { + 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 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; } diff --git a/src/apps/debuganalyzer/MainWindow.h b/src/apps/debuganalyzer/MainWindow.h index 609dd4698d..e0b95207bd 100644 --- a/src/apps/debuganalyzer/MainWindow.h +++ b/src/apps/debuganalyzer/MainWindow.h @@ -9,15 +9,29 @@ class BTabView; +class DataSource; +class MainModel; +class MainModelLoader; class MainWindow : public BWindow { public: - MainWindow(); + MainWindow(DataSource* dataSource); virtual ~MainWindow(); + virtual void MessageReceived(BMessage* message); + + virtual void Quit(); + + virtual void Show(); + +private: + void _SetModel(MainModel* model); + private: BTabView* fMainTabView; + MainModel* fModel; + MainModelLoader* fModelLoader; }; diff --git a/src/apps/debuganalyzer/MessageCodes.h b/src/apps/debuganalyzer/MessageCodes.h index e91699303a..52de0b0da6 100644 --- a/src/apps/debuganalyzer/MessageCodes.h +++ b/src/apps/debuganalyzer/MessageCodes.h @@ -7,9 +7,11 @@ enum { - MSG_MODEL_LOADED_SUCCESSFULLY = 'mlsc', - MSG_MODEL_LOADED_FAILED = 'mlfl', - MSG_MODEL_LOADED_ABORTED = 'mlab' + MSG_MODEL_LOADED_SUCCESSFULLY = 'mlsc', + MSG_MODEL_LOADED_FAILED = 'mlfl', + MSG_MODEL_LOADED_ABORTED = 'mlab', + + MSG_WINDOW_QUIT = 'wiqt' };