xref: /haiku/src/apps/debuganalyzer/model_loader/ThreadModelLoader.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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 
18 static int
19 compare_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 
32 ThreadModelLoader::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 
43 ThreadModelLoader::~ThreadModelLoader()
44 {
45 	delete fThreadModel;
46 }
47 
48 
49 ThreadModel*
50 ThreadModelLoader::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 
64 status_t
65 ThreadModelLoader::PrepareForLoading()
66 {
67 	return B_OK;
68 }
69 
70 
71 status_t
72 ThreadModelLoader::Load()
73 {
74 	try {
75 		return _Load();
76 	} catch(...) {
77 		return B_ERROR;
78 	}
79 }
80 
81 
82 void
83 ThreadModelLoader::FinishLoading(bool success)
84 {
85 	if (!success) {
86 		delete fThreadModel;
87 		fThreadModel = NULL;
88 	}
89 }
90 
91 
92 status_t
93 ThreadModelLoader::_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("%ld wait objects\n", waitObjectCount);
118 	for (int32 i = 0; i < waitObjectCount;) {
119 printf("new wait object group at %ld\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