1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "ThreadModelLoader.h"
7
8#include <stdio.h>
9
10#include <new>
11
12#include <AutoLocker.h>
13#include <DebugEventStream.h>
14
15#include "ThreadModel.h"
16
17
18static int
19compare_by_type_and_name(const Model::ThreadWaitObject* a,
20	const Model::ThreadWaitObject* b)
21{
22	if (a->Type() != b->Type())
23		return a->Type() < b->Type() ? -1 : 1;
24
25	return strcmp(a->Name(), b->Name());
26}
27
28
29// #pragma mark -
30
31
32ThreadModelLoader::ThreadModelLoader(Model* model, Model::Thread* thread,
33	const BMessenger& target, void* targetCookie)
34	:
35	AbstractModelLoader(target, targetCookie),
36	fModel(model),
37	fThread(thread),
38	fThreadModel(NULL)
39{
40}
41
42
43ThreadModelLoader::~ThreadModelLoader()
44{
45	delete fThreadModel;
46}
47
48
49ThreadModel*
50ThreadModelLoader::DetachModel()
51{
52	AutoLocker<BLocker> locker(fLock);
53
54	if (fThreadModel == NULL || fLoading)
55		return NULL;
56
57	ThreadModel* model = fThreadModel;
58	fThreadModel = NULL;
59
60	return model;
61}
62
63
64status_t
65ThreadModelLoader::PrepareForLoading()
66{
67	return B_OK;
68}
69
70
71status_t
72ThreadModelLoader::Load()
73{
74	try {
75		return _Load();
76	} catch(...) {
77		return B_ERROR;
78	}
79}
80
81
82void
83ThreadModelLoader::FinishLoading(bool success)
84{
85	if (!success) {
86		delete fThreadModel;
87		fThreadModel = NULL;
88	}
89}
90
91
92status_t
93ThreadModelLoader::_Load()
94{
95	// create a model
96	fThreadModel = new(std::nothrow) ThreadModel(fModel, fThread);
97	if (fThreadModel == NULL)
98		return B_NO_MEMORY;
99
100	// collect all wait objects
101	BObjectList<Model::ThreadWaitObject> waitObjects;
102
103	int32 groupCount = fThread->CountThreadWaitObjectGroups();
104	for (int32 i = 0; i < groupCount; i++) {
105		Model::ThreadWaitObjectGroup* group
106			= fThread->ThreadWaitObjectGroupAt(i);
107
108		if (!group->GetThreadWaitObjects(waitObjects))
109			return B_NO_MEMORY;
110	}
111
112	// sort them by type and name
113	waitObjects.SortItems(&compare_by_type_and_name);
114
115	// create the groups
116	int32 waitObjectCount = waitObjects.CountItems();
117	printf("%" B_PRId32 " wait objects\n", waitObjectCount);
118	for (int32 i = 0; i < waitObjectCount;) {
119		printf("new wait object group at %" B_PRId32 "\n", i);
120		// collect the objects for this group
121		Model::ThreadWaitObject* firstObject = waitObjects.ItemAt(i);
122		int32 k = i + 1;
123		for (; k < waitObjectCount; k++) {
124			if (compare_by_type_and_name(firstObject, waitObjects.ItemAt(k))
125					!= 0) {
126				break;
127			}
128		}
129
130		if (fThreadModel->AddWaitObjectGroup(waitObjects, i, k) == NULL)
131			return B_NO_MEMORY;
132
133		i = k;
134	}
135
136	// filter the events
137	thread_id threadID = fThread->ID();
138	bool done = false;
139	uint32 count = 0;
140
141	system_profiler_event_header** events = fModel->Events();
142	size_t eventCount = fModel->CountEvents();
143	for (size_t i = 0; i < eventCount; i++) {
144		system_profiler_event_header* header = events[i];
145		void* buffer = header + 1;
146
147		// process the event
148		bool keepEvent = false;
149
150		switch (header->event) {
151			case B_SYSTEM_PROFILER_THREAD_REMOVED:
152			{
153				system_profiler_thread_removed* event
154					= (system_profiler_thread_removed*)buffer;
155				if (event->thread == threadID)
156					done = true;
157				break;
158			}
159
160			case B_SYSTEM_PROFILER_THREAD_SCHEDULED:
161			{
162				system_profiler_thread_scheduled* event
163					= (system_profiler_thread_scheduled*)buffer;
164				keepEvent = event->thread == threadID
165					|| event->previous_thread == threadID ;
166				break;
167			}
168
169			case B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE:
170			{
171				thread_enqueued_in_run_queue* event
172					= (thread_enqueued_in_run_queue*)buffer;
173				keepEvent = event->thread == threadID;
174				break;
175			}
176
177			case B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE:
178			{
179				thread_removed_from_run_queue* event
180					= (thread_removed_from_run_queue*)buffer;
181				keepEvent = event->thread == threadID;
182				break;
183			}
184
185			default:
186				break;
187		}
188
189		if (keepEvent)
190			fThreadModel->AddSchedulingEvent(header);
191
192		// periodically check whether we're supposed to abort
193		if (++count % 32 == 0) {
194			AutoLocker<BLocker> locker(fLock);
195			if (fAborted)
196				return B_ERROR;
197		}
198	}
199
200	return B_OK;
201}
202