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