2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include <DebugLooper.h>
11 #include <AutoLocker.h>
12 #include <DebugMessageHandler.h>
13 #include <TeamDebugger.h>
14 #include <util/DoublyLinkedList.h>
17 struct BDebugLooper::Debugger
{
18 BTeamDebugger
* debugger
;
19 BDebugMessageHandler
* handler
;
21 Debugger(BTeamDebugger
* debugger
, BDebugMessageHandler
* handler
)
30 struct BDebugLooper::Job
: DoublyLinkedListLinkImpl
<Job
> {
41 status_t
Wait(BLocker
& lock
)
43 fDoneSemaphore
= create_sem(0, "debug looper job");
47 while (acquire_sem(fDoneSemaphore
) == B_INTERRUPTED
) {
52 delete_sem(fDoneSemaphore
);
58 void Done(status_t result
)
61 release_sem(fDoneSemaphore
);
64 virtual status_t
Do(BDebugLooper
* looper
) = 0;
67 sem_id fDoneSemaphore
;
72 struct BDebugLooper::JobList
: DoublyLinkedList
<Job
> {
76 struct BDebugLooper::AddDebuggerJob
: Job
{
77 AddDebuggerJob(BTeamDebugger
* debugger
,
78 BDebugMessageHandler
* handler
)
85 virtual status_t
Do(BDebugLooper
* looper
)
87 Debugger
* debugger
= new(std::nothrow
) Debugger(fDebugger
, fHandler
);
88 if (debugger
== NULL
|| !looper
->fDebuggers
.AddItem(debugger
)) {
97 BTeamDebugger
* fDebugger
;
98 BDebugMessageHandler
* fHandler
;
102 struct BDebugLooper::RemoveDebuggerJob
: Job
{
103 RemoveDebuggerJob(team_id team
)
109 virtual status_t
Do(BDebugLooper
* looper
)
111 for (int32 i
= 0; Debugger
* debugger
= looper
->fDebuggers
.ItemAt(i
);
113 if (debugger
->debugger
->Team() == fTeam
) {
114 delete looper
->fDebuggers
.RemoveItemAt(i
);
119 return B_ENTRY_NOT_FOUND
;
130 BDebugLooper::BDebugLooper()
132 fLock("debug looper"),
143 BDebugLooper::~BDebugLooper()
151 status_t error
= fLock
.InitCheck();
155 AutoLocker
<BLocker
> locker(fLock
);
161 fJobs
= new(std::nothrow
) JobList
;
166 if (fEventSemaphore
< 0) {
167 fEventSemaphore
= create_sem(0, "debug looper event");
168 if (fEventSemaphore
< 0)
169 return fEventSemaphore
;
177 BDebugLooper::Run(bool spawnThread
)
179 AutoLocker
<BLocker
> locker(fLock
);
187 fThread
= spawn_thread(&_MessageLoopEntry
, "debug looper",
188 B_NORMAL_PRIORITY
, this);
194 resume_thread(fThread
);
198 fThread
= find_thread(NULL
);
209 AutoLocker
<BLocker
> locker(fLock
);
217 BDebugLooper::AddTeamDebugger(BTeamDebugger
* debugger
,
218 BDebugMessageHandler
* handler
)
220 if (debugger
== NULL
|| handler
== NULL
)
223 AddDebuggerJob
job(debugger
, handler
);
229 BDebugLooper::RemoveTeamDebugger(BTeamDebugger
* debugger
)
231 if (debugger
== NULL
)
234 RemoveDebuggerJob
job(debugger
->Team());
235 return _DoJob(&job
) == B_OK
;
240 BDebugLooper::RemoveTeamDebugger(team_id team
)
245 RemoveDebuggerJob
job(team
);
246 return _DoJob(&job
) == B_OK
;
251 BDebugLooper::_MessageLoopEntry(void* data
)
253 return ((BDebugLooper
*)data
)->_MessageLoop();
258 BDebugLooper::_MessageLoop()
261 // prepare the wait info array
262 int32 debuggerCount
= fDebuggers
.CountItems();
263 object_wait_info waitInfos
[debuggerCount
+ 1];
265 for (int32 i
= 0; i
< debuggerCount
; i
++) {
267 = fDebuggers
.ItemAt(i
)->debugger
->DebuggerPort();
268 waitInfos
[i
].type
= B_OBJECT_TYPE_PORT
;
269 waitInfos
[i
].events
= B_EVENT_READ
;
272 waitInfos
[debuggerCount
].object
= fEventSemaphore
;
273 waitInfos
[debuggerCount
].type
= B_OBJECT_TYPE_SEMAPHORE
;
274 waitInfos
[debuggerCount
].events
= B_EVENT_ACQUIRE_SEMAPHORE
;
276 // wait for the next event
277 wait_for_objects(waitInfos
, debuggerCount
+ 1);
279 AutoLocker
<BLocker
> locker(fLock
);
281 // handle all pending jobs
282 bool handledJobs
= fJobs
->Head() != NULL
;
283 while (Job
* job
= fJobs
->RemoveHead())
284 job
->Done(job
->Do(this));
286 // acquire notification semaphore and mark unnotified
287 if ((waitInfos
[debuggerCount
].events
& B_EVENT_ACQUIRE_SEMAPHORE
) != 0)
288 acquire_sem(fEventSemaphore
);
294 // Always loop when jobs were executed, since that might add/remove
299 // read a pending port message
300 for (int32 i
= 0; i
< debuggerCount
; i
++) {
301 if ((waitInfos
[i
].events
& B_EVENT_READ
) != 0) {
302 Debugger
* debugger
= fDebuggers
.ItemAt(i
);
305 debug_debugger_message_data message
;
307 ssize_t messageSize
= read_port(
308 debugger
->debugger
->DebuggerPort(), &code
, &message
,
313 // handle the message
314 bool continueThread
= debugger
->handler
->HandleDebugMessage(
317 // If requested, tell the thread to continue (only when there
318 // is a thread and the message was synchronous).
319 if (continueThread
&& message
.origin
.thread
>= 0
320 && message
.origin
.nub_port
>= 0) {
321 debugger
->debugger
->ContinueThread(message
.origin
.thread
);
324 // Handle only one message -- the hook might have added/removed
325 // debuggers which makes further iteration problematic.
334 BDebugLooper::_DoJob(Job
* job
)
336 AutoLocker
<BLocker
> locker(fLock
);
338 // execute directly, if in looper thread or not running yet
339 if (fThread
< 0 || fThread
== find_thread(NULL
))
340 return job
->Do(this);
342 // execute in the looper thread
346 return job
->Wait(fLock
);
351 BDebugLooper::_Notify()
357 release_sem(fEventSemaphore
);