diff --git a/src/apps/activitymonitor/ActivityView.cpp b/src/apps/activitymonitor/ActivityView.cpp index 0b12cf27fc..36212df8ac 100644 --- a/src/apps/activitymonitor/ActivityView.cpp +++ b/src/apps/activitymonitor/ActivityView.cpp @@ -14,6 +14,7 @@ # include #endif #include +#include #include #include #include @@ -93,7 +94,6 @@ private: const bigtime_t kInitialRefreshInterval = 500000LL; -const uint32 kMsgRefresh = 'refr'; const uint32 kMsgToggleDataSource = 'tgds'; const uint32 kMsgToggleLegend = 'tglg'; @@ -392,7 +392,8 @@ ActivityView::LegendLayoutItem::BaseAlignment() ActivityView::ActivityView(BRect frame, const char* name, const BMessage* settings, uint32 resizingMode) : BView(frame, name, resizingMode, - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS) + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), + fSourcesLock("data sources") { _Init(settings); @@ -407,10 +408,12 @@ ActivityView::ActivityView(BRect frame, const char* name, ActivityView::ActivityView(const char* name, const BMessage* settings) #ifdef __HAIKU__ - : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS) + : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), #else - : BView(BRect(0,0,300,200), name, B_FOLLOW_NONE, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS) + : BView(BRect(0,0,300,200), name, B_FOLLOW_NONE, + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS), #endif + fSourcesLock("data sources") { SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); @@ -585,6 +588,8 @@ ActivityView::CreateLegendLayoutItem() DataSource* ActivityView::FindDataSource(const DataSource* search) { + BAutolock _(fSourcesLock); + for (int32 i = fSources.CountItems(); i-- > 0;) { DataSource* source = fSources.ItemAt(i); if (!strcmp(source->Name(), search->Name())) @@ -601,6 +606,8 @@ ActivityView::AddDataSource(const DataSource* source, const BMessage* state) if (source == NULL) return B_BAD_VALUE; + BAutolock _(fSourcesLock); + int32 insert = DataSource::IndexOf(source); for (int32 i = 0; i < fSources.CountItems() && i < insert; i++) { DataSource* before = fSources.ItemAt(i); @@ -667,6 +674,8 @@ ActivityView::RemoveDataSource(const DataSource* remove) { bool removed = false; + BAutolock _(fSourcesLock); + while (true) { DataSource* source = FindDataSource(remove); debug_printf("SEARCH %s, found %p\n", remove->Name(), source); @@ -697,6 +706,8 @@ debug_printf("SEARCH %s, found %p\n", remove->Name(), source); void ActivityView::RemoveAllDataSources() { + BAutolock _(fSourcesLock); + fSources.MakeEmpty(); fValues.MakeEmpty(); } @@ -708,8 +719,10 @@ ActivityView::AttachedToWindow() Looper()->AddHandler(fSystemInfoHandler); fSystemInfoHandler->StartWatching(); - BMessage refresh(kMsgRefresh); - fRunner = new BMessageRunner(this, &refresh, fRefreshInterval); + fRefreshSem = create_sem(0, "refresh sem"); + fRefreshThread = spawn_thread(&_RefreshThread, "source refresh", + B_NORMAL_PRIORITY, this); + resume_thread(fRefreshThread); FrameResized(Bounds().Width(), Bounds().Height()); } @@ -721,7 +734,8 @@ ActivityView::DetachedFromWindow() fSystemInfoHandler->StopWatching(); Looper()->RemoveHandler(fSystemInfoHandler); - delete fRunner; + delete_sem(fRefreshSem); + wait_for_thread(fRefreshThread, NULL); } @@ -896,6 +910,8 @@ ActivityView::MessageReceived(BMessage* message) Invalidate(_HistoryFrame()); } else { // check each legend color box + BAutolock _(fSourcesLock); + BRect legendFrame = _LegendFrame(); for (int32 i = 0; i < fSources.CountItems(); i++) { BRect frame = _LegendColorFrameAt(legendFrame, i); @@ -923,10 +939,6 @@ ActivityView::MessageReceived(BMessage* message) ActivityMonitor::ShowAbout(); break; - case kMsgRefresh: - _Refresh(); - break; - case kMsgToggleDataSource: { int32 index; @@ -1022,6 +1034,8 @@ ActivityView::_LegendHeight() const font_height fontHeight; GetFontHeight(&fontHeight); + BAutolock _(fSourcesLock); + int32 rows = (fSources.CountItems() + 1) / 2; return rows * (4 + ceilf(fontHeight.ascent) + ceilf(fontHeight.descent) + ceilf(fontHeight.leading)); @@ -1056,6 +1070,8 @@ ActivityView::_LegendFrameAt(BRect frame, int32 index) const else frame.left = frame.right - floorf(frame.Width() / 2) + 5; + BAutolock _(fSourcesLock); + int32 rows = (fSources.CountItems() + 1) / 2; float height = floorf((frame.Height() - 5) / rows); @@ -1146,6 +1162,7 @@ ActivityView::_DrawHistory() // Draw values view->SetPenSize(2); + BAutolock _(fSourcesLock); for (uint32 i = fSources.CountItems(); i-- > 0;) { DataSource* source = fSources.ItemAt(i); @@ -1210,6 +1227,7 @@ ActivityView::Draw(BRect /*updateRect*/) // draw legend + BAutolock _(fSourcesLock); BRect legendFrame = _LegendFrame(); SetLowColor(fLegendBackgroundColor); @@ -1252,22 +1270,46 @@ ActivityView::Draw(BRect /*updateRect*/) void ActivityView::_Refresh() { - SystemInfo info(fSystemInfoHandler); + bigtime_t lastTimeout = system_time() - fRefreshInterval; - // TODO: run refresh in another thread to decouple it from the UI! + while (true) { + status_t status = acquire_sem_etc(fRefreshSem, 1, B_ABSOLUTE_TIMEOUT, + lastTimeout + fRefreshInterval); + if (status == B_OK || status == B_BAD_SEM_ID) + break; + if (status == B_INTERRUPTED) + continue; - for (uint32 i = fSources.CountItems(); i-- > 0;) { - DataSource* source = fSources.ItemAt(i); - DataHistory* values = fValues.ItemAt(i); + SystemInfo info(fSystemInfoHandler); + lastTimeout += fRefreshInterval; - int64 value = source->NextValue(info); - values->AddValue(info.Time(), value); - } + fSourcesLock.Lock(); - bigtime_t now = info.Time(); - if (fLastRefresh + fDrawInterval <= now) { - Invalidate(); - fLastRefresh = now; + for (uint32 i = fSources.CountItems(); i-- > 0;) { + DataSource* source = fSources.ItemAt(i); + DataHistory* values = fValues.ItemAt(i); + + int64 value = source->NextValue(info); + values->AddValue(info.Time(), value); + } + + fSourcesLock.Unlock(); + + bigtime_t now = info.Time(); + if (fLastRefresh + fDrawInterval <= now) { + if (LockLooper()) { + Invalidate(); + UnlockLooper(); + fLastRefresh = now; + } + } } } + +/*static*/ status_t +ActivityView::_RefreshThread(void* self) +{ + ((ActivityView*)self)->_Refresh(); + return B_OK; +} diff --git a/src/apps/activitymonitor/ActivityView.h b/src/apps/activitymonitor/ActivityView.h index 2774da49ca..240a9062ca 100644 --- a/src/apps/activitymonitor/ActivityView.h +++ b/src/apps/activitymonitor/ActivityView.h @@ -8,8 +8,9 @@ #include -#include +#include #include +#include #include "CircularBuffer.h" #include "DataSource.h" @@ -95,6 +96,7 @@ private: void _Init(const BMessage* settings); ::Scale* _ScaleFor(scale_type type); void _Refresh(); + static status_t _RefreshThread(void* self); void _UpdateOffscreenBitmap(); BView* _OffscreenView(); void _UpdateFrame(); @@ -121,9 +123,11 @@ private: BLayoutItem* fHistoryLayoutItem; BLayoutItem* fLegendLayoutItem; #endif + mutable BLocker fSourcesLock; BObjectList fSources; BObjectList fValues; - BMessageRunner* fRunner; + thread_id fRefreshThread; + sem_id fRefreshSem; bigtime_t fRefreshInterval; bigtime_t fLastRefresh; bigtime_t fDrawInterval;