VirtualBox

source: kStuff/trunk/kProfiler2/prfcore.cpp.h

Last change on this file was 29, checked in by bird, 15 years ago

Finally got around execute the switch to the MIT license.

  • Property svn:keywords set to Id Revision
File size: 20.1 KB
Line 
1/* $Id: prfcore.cpp.h 29 2009-07-01 20:30:29Z bird $ */
2/** @file
3 * kProfiler Mark 2 - Core Code Template.
4 */
5
6/*
7 * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/**
33 * Gets a function, create a new one if necessary.
34 */
35static KPRF_TYPE(P,FUNC) KPRF_NAME(GetFunction)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC)
36{
37 /*
38 * Perform a binary search of the function lookup table.
39 */
40 KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr);
41
42 KPRF_FUNCS_READ_LOCK();
43 KI32 iStart = 0;
44 KI32 iLast = pHdr->cFunctions - 1;
45 KI32 i = iLast / 2;
46 for (;;)
47 {
48 KU32 iFunction = pHdr->aiFunctions[i];
49 KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr;
50 if (!iDiff)
51 {
52 KPRF_FUNCS_READ_UNLOCK();
53 return &paFunctions[iFunction];
54 }
55 if (iLast == iStart)
56 break;
57 if (iDiff < 0)
58 iLast = i - 1;
59 else
60 iStart = i + 1;
61 if (iLast < iStart)
62 break;
63 i = iStart + (iLast - iStart) / 2;
64 }
65 KPRF_FUNCS_READ_UNLOCK();
66
67 /*
68 * It wasn't found, try add it.
69 */
70 if (pHdr->cFunctions < pHdr->cMaxFunctions)
71 return KPRF_NAME(NewFunction)(pHdr, uPC);
72 return NULL;
73}
74
75
76/**
77 * Unwind one frame.
78 */
79static KU64* KPRF_NAME(UnwindOne)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KU64 TS)
80{
81 /*
82 * Pop off the frame and update the frame below / thread.
83 */
84 KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[--pStack->cFrames];
85 KU64 *pCurOverheadTicks;
86 if (pStack->cFrames)
87 {
88 KPRF_TYPE(P,FRAME) pTopFrame = pFrame - 1;
89 pTopFrame->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks;
90 pTopFrame->SleepTicks += pFrame->SleepTicks;
91 pTopFrame->OnTopOfStackStart = TS;
92 pTopFrame->CurOverheadTicks = 0;
93
94 pCurOverheadTicks = &pTopFrame->CurOverheadTicks;
95 }
96 else
97 {
98 KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr);
99 pThread->ProfiledTicks += TS - pFrame->OnStackStart - pFrame->CurOverheadTicks - pFrame->OverheadTicks - pFrame->SleepTicks;
100 pThread->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks;
101 pThread->SleepTicks += pFrame->SleepTicks;
102
103 pCurOverheadTicks = &pThread->OverheadTicks;
104 }
105
106 /*
107 * Update the function (if any).
108 */
109 if (pFrame->offFunction)
110 {
111 KPRF_TYPE(P,FUNC) pFunc = KPRF_OFF2PTR(P,FUNC, pFrame->offFunction, pHdr);
112
113 /* Time on stack */
114 KU64 Ticks = TS - pFrame->OnStackStart;
115 Ticks -= pFrame->OverheadTicks + pFrame->CurOverheadTicks + pFrame->SleepTicks;
116/** @todo adjust overhead */
117KPRF_ASSERT(!(Ticks >> 63));
118 if (pFunc->OnStack.MinTicks > Ticks)
119 KPRF_ATOMIC_SET64(&pFunc->OnStack.MinTicks, Ticks);
120 if (pFunc->OnStack.MaxTicks < Ticks)
121 KPRF_ATOMIC_SET64(&pFunc->OnStack.MaxTicks, Ticks);
122 KPRF_ATOMIC_ADD64(&pFunc->OnStack.SumTicks, Ticks);
123
124 /* Time on top of stack */
125 Ticks = TS - pFrame->OnTopOfStackStart;
126 Ticks -= pFrame->CurOverheadTicks;
127 Ticks += pFrame->OnTopOfStackTicks;
128/** @todo adjust overhead */
129KPRF_ASSERT(!(Ticks >> 63));
130 if (pFunc->OnTopOfStack.MinTicks > Ticks)
131 KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MinTicks, Ticks);
132 if (pFunc->OnTopOfStack.MaxTicks < Ticks)
133 KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MaxTicks, Ticks);
134 KPRF_ATOMIC_ADD64(&pFunc->OnTopOfStack.SumTicks, Ticks);
135
136 /* calls */
137 if (pFrame->cCalls)
138 KPRF_ATOMIC_ADD64(&pFunc->cCalls, pFrame->cCalls);
139 }
140
141 return pCurOverheadTicks;
142}
143
144
145/**
146 * Unwinds the stack.
147 *
148 * On MSC+AMD64 we have to be very very careful here, because the uFramePtr cannot be trusted.
149 */
150static KU64* KPRF_NAME(UnwindInt)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, KU64 TS)
151{
152 /** @todo need to deal with alternative stacks! */
153
154 /*
155 * Pop the stack until we're down below the current frame (uFramePtr).
156 */
157 KI32 iFrame = pStack->cFrames - 1;
158 KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame];
159
160 /* the most frequent case first. */
161#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
162 if ( uFramePtr == pFrame->uFramePtr
163 || ( pFrame->uFramePtr < uFramePtr
164 && iFrame > 0
165 && pFrame[-1].uFramePtr > uFramePtr))
166 return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
167#else
168 if (uFramePtr == pFrame->uFramePtr)
169 return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
170#endif
171
172 /* none? */
173 if (pFrame->uFramePtr > uFramePtr)
174 return &pFrame->CurOverheadTicks;
175
176 /* one or more, possibly all */
177 KU64 *pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
178 pFrame--;
179 if ( iFrame > 0
180#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
181 && pFrame->uFramePtr <= uFramePtr
182 && pFrame[-1].uFramePtr > uFramePtr)
183#else
184 && pFrame->uFramePtr <= uFramePtr)
185#endif
186 {
187 KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr);
188 pThread->cUnwinds++; /* (This is the reason for what looks like a bad loop unrolling.) */
189
190 pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
191 iFrame -= 2;
192 pFrame--;
193#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
194 while ( iFrame > 0
195 && pFrame->uFramePtr <= uFramePtr
196 && pFrame[-1].uFramePtr > uFramePtr)
197#else
198 while ( iFrame >= 0
199 && pFrame->uFramePtr <= uFramePtr)
200#endif
201 {
202 pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS);
203 iFrame--;
204 pFrame--;
205 }
206 }
207
208 return pCurOverheadTicks;
209}
210
211
212
213/**
214 * Enter function.
215 *
216 * @returns Where to account overhead.
217 * @returns NULL if profiling is inactive.
218 *
219 * @param uPC The program counter register. (not relative)
220 * @param uFramePtr The stack frame address. This must match the one passed to kPrfLeave. (not relative)
221 * @param TS The timestamp when we entered into the profiler.
222 * This must not be modified touched!
223 *
224 * @internal ?
225 */
226KPRF_DECL_FUNC(KU64 *, Enter)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS)
227{
228 /*
229 * Is profiling active ?
230 */
231 if (!KPRF_IS_ACTIVE())
232 return NULL;
233
234 /*
235 * Get the header and adjust input addresses.
236 */
237 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
238 if (!pHdr)
239 return NULL;
240 const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr;
241 if (uBasePtr)
242 {
243 uFramePtr -= uBasePtr;
244 uPC -= uBasePtr;
245 }
246
247 /*
248 * Get the current thread. Reject unknown, inactive (in whatever way),
249 * and thread which has performed a stack switch.
250 */
251 KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
252 if (!pThread)
253 return NULL;
254 KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState;
255 if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE)
256 && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED)
257 )
258 return NULL;
259 if (pThread->uStackBasePtr < uFramePtr) /* ASSUMES stack direction */
260 {
261 pThread->cStackSwitchRejects++;
262 return NULL;
263 }
264 pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
265
266
267 /*
268 * Update the thread statistics.
269 */
270 pThread->cCalls++;
271 KPRF_TYPE(,UPTR) cbStack = pThread->uStackBasePtr - uFramePtr; /* ASSUMES stack direction */
272 if (pThread->cbMaxStack < cbStack)
273 pThread->cbMaxStack = cbStack;
274
275 /*
276 * Check if an longjmp or throw has taken place.
277 * This check will not work if a stack switch has taken place (can fix that later).
278 */
279 KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
280 KU32 iFrame = pStack->cFrames;
281 KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame];
282 if ( iFrame
283#if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64
284 && 0) /* don't bother her yet because of _penter/_pexit frame problems. */
285#else
286 && pThread->uStackBasePtr >= uFramePtr /* ASSUMES stack direction */
287 && pFrame[-1].uFramePtr + (KPRF_BITS - 8) / 8 < uFramePtr) /* ASSUMES stack direction */
288#endif
289 {
290 KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS);
291 iFrame = pStack->cFrames;
292 }
293
294 /*
295 * Allocate a new stack frame.
296 */
297 if (iFrame >= pHdr->cMaxStackFrames)
298 {
299 /* overflow */
300 pThread->enmState = KPRF_TYPE(,THREADSTATE_OVERFLOWED);
301 pThread->cOverflows += enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED);
302 return &pStack->aFrames[iFrame - 1].CurOverheadTicks;
303 }
304 pStack->cFrames++;
305
306 /*
307 * Update the old top frame if any.
308 */
309 if (iFrame)
310 {
311 KPRF_TYPE(P,FRAME) pOldFrame = pFrame - 1;
312 pOldFrame->OnTopOfStackTicks += TS - pOldFrame->OnTopOfStackStart;
313 pOldFrame->cCalls++;
314 }
315
316 /*
317 * Fill in the new frame.
318 */
319 pFrame->CurOverheadTicks = 0;
320 pFrame->OverheadTicks = 0;
321 pFrame->SleepTicks = 0;
322 pFrame->OnStackStart = TS;
323 pFrame->OnTopOfStackStart = TS;
324 pFrame->OnTopOfStackTicks = 0;
325 pFrame->cCalls = 0;
326 pFrame->uFramePtr = uFramePtr;
327
328 /*
329 * Find the relevant function.
330 */
331 KPRF_TYPE(P,FUNC) pFunc = KPRF_NAME(GetFunction)(pHdr, uPC);
332 if (pFunc)
333 {
334 pFrame->offFunction = KPRF_PTR2OFF(pFunc, pHdr);
335 pFunc->cOnStack++;
336 }
337 else
338 pFrame->offFunction = 0;
339
340 /*
341 * Nearly done, We only have to reactivate the thread and account overhead.
342 * The latter is delegated to the caller.
343 */
344 pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE);
345 return &pFrame->CurOverheadTicks;
346}
347
348
349/**
350 * Leave function.
351 *
352 * @returns Where to account overhead.
353 * @returns NULL if profiling is inactive.
354 *
355 * @param uPC The program counter register.
356 * @param uFramePtr The stack frame address. This must match the one passed to kPrfEnter.
357 * @param TS The timestamp when we entered into the profiler.
358 * This must not be modified because the caller could be using it!
359 * @internal
360 */
361KPRF_DECL_FUNC(KU64 *, Leave)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS)
362{
363 /*
364 * Is profiling active ?
365 */
366 if (!KPRF_IS_ACTIVE())
367 return NULL;
368
369 /*
370 * Get the header and adjust input addresses.
371 */
372 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
373 if (!pHdr)
374 return NULL;
375 const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr;
376 if (uBasePtr)
377 {
378 uFramePtr -= uBasePtr;
379 uPC -= uBasePtr;
380 }
381
382 /*
383 * Get the current thread and suspend profiling of the thread until we leave this function.
384 * Also reject threads which aren't active in some way.
385 */
386 KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
387 if (!pThread)
388 return NULL;
389 KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState;
390 if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE)
391 && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED)
392 )
393 return NULL;
394 KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
395 if (!pStack->cFrames)
396 return NULL;
397 pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
398
399 /*
400 * Unwind the stack down to and including the entry indicated by uFramePtr.
401 * Leave it to the caller to update the overhead.
402 */
403 KU64 *pCurOverheadTicks = KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS);
404
405 pThread->enmState = enmThreadState;
406 return pCurOverheadTicks;
407}
408
409
410/**
411 * Register the current thread.
412 *
413 * A thread can only be profiled if it has been registered by a call to this function.
414 *
415 * @param uPC The program counter register.
416 * @param uStackBasePtr The base of the stack.
417 */
418KPRF_DECL_FUNC(KPRF_TYPE(P,THREAD), RegisterThread)(KPRF_TYPE(,UPTR) uStackBasePtr, const char *pszName)
419{
420 /*
421 * Get the header and adjust input address.
422 * (It doesn't matter whether we're active or not.)
423 */
424 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
425 if (!pHdr)
426 return NULL;
427 const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr;
428 if (uBasePtr)
429 uStackBasePtr -= uBasePtr;
430
431
432 /*
433 * Allocate a thread and a stack.
434 */
435 KPRF_THREADS_LOCK();
436 if (pHdr->cThreads < pHdr->cMaxThreads)
437 {
438 KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pHdr->offStacks, pHdr);
439 KU32 cLeft = pHdr->cMaxStacks;
440 do
441 {
442 if (!pStack->offThread)
443 {
444 /* init the stack. */
445 pStack->cFrames = 0;
446 pStack->offThread = pHdr->offThreads + pHdr->cbThread * pHdr->cThreads++;
447 pHdr->cStacks++;
448
449 /* init the thread */
450 KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr);
451 pThread->ThreadId = KPRF_GET_THREADID();
452 unsigned i = 0;
453 if (pszName)
454 while (i < sizeof(pThread->szName) - 1 && *pszName)
455 pThread->szName[i++] = *pszName++;
456 while (i < sizeof(pThread->szName))
457 pThread->szName[i++] = '\0';
458 pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
459 pThread->Reserved0 = KPRF_TYPE(,THREADSTATE_TERMINATED);
460 pThread->uStackBasePtr = uStackBasePtr;
461 pThread->cbMaxStack = 0;
462 pThread->cCalls = 0;
463 pThread->cOverflows = 0;
464 pThread->cStackSwitchRejects = 0;
465 pThread->cUnwinds = 0;
466 pThread->ProfiledTicks = 0;
467 pThread->OverheadTicks = 0;
468 pThread->SleepTicks = 0;
469 pThread->offStack = KPRF_PTR2OFF(pStack, pHdr);
470
471
472 /* set the thread and make it active. */
473 KPRF_THREADS_UNLOCK();
474 KPRF_SET_THREAD(pThread);
475 pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE);
476 return pThread;
477 }
478
479 /* next */
480 pStack = KPRF_TYPE(P,STACK)(((KPRF_TYPE(,UPTR))pStack + pHdr->cbStack));
481 } while (--cLeft > 0);
482 }
483
484 KPRF_THREADS_UNLOCK();
485 return NULL;
486}
487
488
489/**
490 * Terminates a thread.
491 *
492 * To terminate the current thread use DeregisterThread(), because that
493 * cleans up the TLS entry too.
494 *
495 * @param pHdr The profiler data set header.
496 * @param pThread The thread to terminate.
497 * @param TS The timestamp to use when terminating the thread.
498 */
499KPRF_DECL_FUNC(void, TerminateThread)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,THREAD) pThread, KU64 TS)
500{
501 if (pThread->enmState == KPRF_TYPE(,THREADSTATE_TERMINATED))
502 return;
503 pThread->enmState = KPRF_TYPE(,THREADSTATE_TERMINATED);
504
505 /*
506 * Unwind the entire stack.
507 */
508 if (pThread->offStack)
509 {
510 KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
511 for (KU32 cFrames = pStack->cFrames; cFrames > 0; cFrames--)
512 KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS);
513
514 /*
515 * Free the stack.
516 */
517 pThread->offStack = 0;
518 KPRF_THREADS_LOCK();
519 pStack->offThread = 0;
520 pHdr->cStacks--;
521 KPRF_THREADS_UNLOCK();
522 }
523}
524
525
526/**
527 * Deregister (terminate) the current thread.
528 */
529KPRF_DECL_FUNC(void, DeregisterThread)(void)
530{
531 KU64 TS = KPRF_NOW();
532
533 /*
534 * Get the header, then get the thread and mark it terminated.
535 * (It doesn't matter whether we're active or not.)
536 */
537 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
538 if (!pHdr)
539 return;
540
541 KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
542 KPRF_SET_THREAD(NULL);
543 if (!pThread)
544 return;
545 KPRF_NAME(TerminateThread)(pHdr, pThread, TS);
546}
547
548
549/**
550 * Resumes / restarts a thread.
551 *
552 * @param fReset If set the stack is reset.
553 */
554KPRF_DECL_FUNC(void, ResumeThread)(int fReset)
555{
556 KU64 TS = KPRF_NOW();
557
558 /*
559 * Get the header, then get the thread and mark it terminated.
560 * (It doesn't matter whether we're active or not.)
561 */
562 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
563 if (!pHdr)
564 return;
565
566 KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
567 if (!pThread)
568 return;
569 if (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED))
570 return;
571
572 /*
573 * Reset (unwind) the stack?
574 */
575 KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
576 if (fReset)
577 {
578 KU32 cFrames = pStack->cFrames;
579 while (cFrames-- > 0)
580 KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS);
581 }
582 /*
583 * If we've got any thing on the stack, we'll have to stop the sleeping period.
584 */
585 else if (pStack->cFrames > 0)
586 {
587 KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1];
588
589 /* update the sleeping time and set the start of the new top-of-stack period. */
590 pFrame->SleepTicks += TS - pFrame->OnTopOfStackStart;
591 pFrame->OnTopOfStackStart = TS;
592 }
593 /** @todo we're not accounting overhead here! */
594
595 /*
596 * We're done, switch the thread to active state.
597 */
598 pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE);
599}
600
601
602/**
603 * Suspend / completes a thread.
604 *
605 * The thread will be in a suspend state where the time will be accounted for as sleeping.
606 *
607 * @param fUnwind If set the stack is unwound and the thread statistics updated.
608 */
609KPRF_DECL_FUNC(void, SuspendThread)(int fUnwind)
610{
611 KU64 TS = KPRF_NOW();
612
613 /*
614 * Get the header, then get the thread and mark it terminated.
615 * (It doesn't matter whether we're active or not.)
616 */
617 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
618 if (!pHdr)
619 return;
620
621 KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD();
622 if (!pThread)
623 return;
624 if ( pThread->enmState != KPRF_TYPE(,THREADSTATE_ACTIVE)
625 && pThread->enmState != KPRF_TYPE(,THREADSTATE_OVERFLOWED)
626 && (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED) || fUnwind))
627 return;
628
629 pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED);
630
631 /*
632 * Unwind the stack?
633 */
634 KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr);
635 if (fUnwind)
636 {
637 KU32 cFrames = pStack->cFrames;
638 while (cFrames-- > 0)
639 KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS);
640 }
641 /*
642 * If we've got any thing on the stack, we'll have to record the sleeping period
643 * of the thread. If not we'll ignore it (for now at least).
644 */
645 else if (pStack->cFrames > 0)
646 {
647 KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1];
648
649 /* update the top of stack time and set the start of the sleep period. */
650 pFrame->OnTopOfStackTicks += TS - pFrame->OnTopOfStackStart;
651 pFrame->OnTopOfStackStart = TS;
652 }
653
654 /** @todo we're not accounting overhead here! */
655}
656
657
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette