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
compare_by_type_and_name(const Model::ThreadWaitObject * a,const Model::ThreadWaitObject * b)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
ThreadModelLoader(Model * model,Model::Thread * thread,const BMessenger & target,void * targetCookie)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
~ThreadModelLoader()43 ThreadModelLoader::~ThreadModelLoader()
44 {
45 delete fThreadModel;
46 }
47
48
49 ThreadModel*
DetachModel()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
PrepareForLoading()65 ThreadModelLoader::PrepareForLoading()
66 {
67 return B_OK;
68 }
69
70
71 status_t
Load()72 ThreadModelLoader::Load()
73 {
74 try {
75 return _Load();
76 } catch(...) {
77 return B_ERROR;
78 }
79 }
80
81
82 void
FinishLoading(bool success)83 ThreadModelLoader::FinishLoading(bool success)
84 {
85 if (!success) {
86 delete fThreadModel;
87 fThreadModel = NULL;
88 }
89 }
90
91
92 status_t
_Load()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("%" 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