VirtualBox

source: kStuff/trunk/kProfiler2/kProfileR3.cpp@ 24

Last change on this file since 24 was 9, checked in by bird, 17 years ago

Use the kStuff template instead of cooking our own compiler setup.

  • Property svn:keywords set to Id Revision
File size: 43.7 KB
Line 
1/* $Id: kProfileR3.cpp 9 2008-04-20 03:47:01Z bird $ */
2/** @file
3 * kProfiler Mark 2 - The Ring-3 Implementation.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kProfiler.
10 *
11 * kProfiler is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * kProfiler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with kProfiler; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <k/kDefs.h>
32#if K_OS == K_OS_WINDOWS
33# include <windows.h>
34# include <psapi.h>
35# include <malloc.h>
36# if _MSC_VER >= 1400
37# include <intrin.h>
38# define HAVE_INTRIN
39# endif
40
41#elif K_OS == K_OS_LINUX || K_OS == K_OS_FREEBSD
42# define KPRF_USE_PTHREAD
43# include <pthread.h>
44# include <stdint.h>
45# define KPRF_USE_MMAN
46# include <sys/mman.h>
47# include <sys/fcntl.h>
48# include <unistd.h>
49# include <stdlib.h>
50# ifndef O_BINARY
51# define O_BINARY 0
52# endif
53
54#elif K_OS == K_OS_OS2
55# define INCL_BASE
56# include <os2.h>
57# include <stdint.h>
58# include <sys/fmutex.h>
59
60#else
61# error "not ported to this OS..."
62#endif
63
64#include <k/kDefs.h>
65#include <k/kTypes.h>
66
67/*
68 * Instantiate the header.
69 */
70#define KPRF_NAME(Suffix) KPrf##Suffix
71#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF##Suffix
72#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
73# define KPRF_DECL_FUNC(type, name) extern "C" __declspec(dllexport) type __cdecl KPRF_NAME(name)
74#else
75# define KPRF_DECL_FUNC(type, name) extern "C" type KPRF_NAME(name)
76#endif
77#if 1
78# ifdef __GNUC__
79# define KPRF_ASSERT(expr) do { if (!(expr)) { __asm__ __volatile__("int3\n\tnop\n\t");} } while (0)
80# else
81# define KPRF_ASSERT(expr) do { if (!(expr)) { __debugbreak(); } } while (0)
82# endif
83#else
84# define KPRF_ASSERT(expr) do { } while (0)
85#endif
86
87#include "prfcore.h.h"
88
89
90
91/*******************************************************************************
92* Structures and Typedefs *
93*******************************************************************************/
94/** Mutex lock type. */
95#if defined(KPRF_USE_PTHREAD)
96typedef pthread_mutex_t KPRF_TYPE(,MUTEX);
97#elif K_OS == K_OS_WINDOWS
98typedef CRITICAL_SECTION KPRF_TYPE(,MUTEX);
99#elif K_OS == K_OS_OS2
100typedef struct _fmutex KPRF_TYPE(,MUTEX);
101#endif
102/** Pointer to a mutex lock. */
103typedef KPRF_TYPE(,MUTEX) *KPRF_TYPE(P,MUTEX);
104
105
106#if defined(KPRF_USE_PTHREAD)
107/** Read/Write lock type. */
108typedef pthread_rwlock_t KPRF_TYPE(,RWLOCK);
109#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
110/** Read/Write lock state. */
111typedef enum KPRF_TYPE(,RWLOCKSTATE)
112{
113 RWLOCK_STATE_UNINITIALIZED = 0,
114 RWLOCK_STATE_SHARED,
115 RWLOCK_STATE_LOCKING,
116 RWLOCK_STATE_EXCLUSIVE,
117 RWLOCK_STATE_32BIT_HACK = 0x7fffffff
118} KPRF_TYPE(,RWLOCKSTATE);
119/** Update the state. */
120#define KPRF_RWLOCK_SETSTATE(pRWLock, enmNewState) \
121 kPrfAtomicSet32((volatile KU32 *)&(pRWLock)->enmState, (KU32)(enmNewState))
122
123/** Read/Write lock type. */
124typedef struct KPRF_TYPE(,RWLOCK)
125{
126 /** This mutex serialize the access and updating of the members
127 * of this structure. */
128 KPRF_TYPE(,MUTEX) Mutex;
129 /** The current number of readers. */
130 KU32 cReaders;
131 /** The number of readers waiting. */
132 KU32 cReadersWaiting;
133 /** The current number of waiting writers. */
134 KU32 cWritersWaiting;
135# if K_OS == K_OS_WINDOWS
136 /** The handle of the event object on which the waiting readers block. (manual reset). */
137 HANDLE hevReaders;
138 /** The handle of the event object on which the waiting writers block. (manual reset). */
139 HANDLE hevWriters;
140# elif K_OS == K_OS_OS2
141 /** The handle of the event semaphore on which the waiting readers block. */
142 HEV hevReaders;
143 /** The handle of the event semaphore on which the waiting writers block. */
144 HEV hevWriters;
145# endif
146 /** The current state of the read-write lock. */
147 KPRF_TYPE(,RWLOCKSTATE) enmState;
148} KPRF_TYPE(,RWLOCK);
149#endif
150/** Pointer to a Read/Write lock. */
151typedef KPRF_TYPE(,RWLOCK) *KPRF_TYPE(P,RWLOCK);
152
153
154
155/*******************************************************************************
156* Global Variables *
157*******************************************************************************/
158/** The TLS index / key. */
159#if K_OS == K_OS_WINDOWS
160static DWORD g_dwThreadTLS = TLS_OUT_OF_INDEXES;
161
162#elif defined(KPRF_USE_PTHREAD)
163static pthread_key_t g_ThreadKey = (pthread_key_t)-1;
164
165#elif K_OS == K_OS_OS2
166static KPRF_TYPE(P,THREAD) *g_ppThread = NULL;
167
168#else
169# error "Not ported to your OS - or you're missing the OS define(s)."
170#endif
171
172/** Pointer to the profiler header. */
173static KPRF_TYPE(P,HDR) g_pHdr = NULL;
174#define KPRF_GET_HDR() g_pHdr
175
176/** Whether the profiler is enabled or not. */
177static bool g_fEnabled = false;
178#define KPRF_IS_ACTIVE() g_fEnabled
179
180
181/** The mutex protecting the threads in g_pHdr. */
182static KPRF_TYPE(,MUTEX) g_ThreadsMutex;
183
184/** The mutex protecting the module segments in g_pHdr. */
185static KPRF_TYPE(,MUTEX) g_ModSegsMutex;
186
187/** The read-write lock protecting the functions in g_pHdr. */
188static KPRF_TYPE(,RWLOCK) g_FunctionsRWLock;
189
190
191
192/*******************************************************************************
193* Internal Functions *
194*******************************************************************************/
195static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void);
196#ifdef KPRF_USE_PTHREAD
197static void kPrfPThreadKeyDtor(void *pvThread);
198#endif
199
200
201/**
202 * Gets the pointer to the profiler data for the current thread.
203 *
204 * This implementation automatically adds unknown threads.
205 *
206 * @returns Pointer to the profiler thread data.
207 * @returns NULL if we're out of thread space.
208 */
209static inline KPRF_TYPE(P,THREAD) kPrfGetThread(void)
210{
211 KPRF_TYPE(P,THREAD) pThread;
212
213/* Win32/64 */
214#if K_OS == K_OS_WINDOWS
215 pThread = (KPRF_TYPE(P,THREAD))TlsGetValue(g_dwThreadTLS);
216
217/* Posix Threads */
218#elif defined(KPRF_USE_PTHREAD)
219 pThread = (KPRF_TYPE(P,THREAD))pthread_getspecific(g_ThreadKey);
220
221#elif K_OS == K_OS_OS2
222 pThread = *g_ppThread;
223
224#else
225# error not implemented
226#endif
227 if (!pThread)
228 pThread = kPrfGetThreadAutoReg();
229 return pThread;
230}
231#define KPRF_GET_THREAD() kPrfGetThread()
232
233
234/**
235 * The the ID of the current thread.
236 *
237 * @returns The thread id.
238 */
239static inline KUPTR kPrfGetThreadId(void)
240{
241/* Win32/64 */
242#if K_OS == K_OS_WINDOWS
243 KUPTR ThreadId = (KUPTR)GetCurrentThreadId();
244
245/* Posix Threads */
246#elif defined(KPRF_USE_PTHREAD)
247 KUPTR ThreadId = (KUPTR)pthread_self();
248
249#elif K_OS == K_OS_OS2
250 PTIB pTib;
251 PPIB pPib;
252 DosGetInfoBlocks(&pTib, &pPib);
253 ThreadId = pTib->tib_ptib2->tib2_ultid;
254
255#else
256# error not implemented
257#endif
258
259 return ThreadId;
260}
261#define KPRF_GET_THREADID() kPrfGetThreadId()
262
263
264/**
265 * The the ID of the current process.
266 *
267 * @returns The process id.
268 */
269static inline KUPTR kPrfGetProcessId(void)
270{
271/* Win32/64 */
272#if K_OS == K_OS_WINDOWS
273 KUPTR ThreadId = (KUPTR)GetProcessId(GetCurrentProcess());
274
275#elif K_OS == K_OS_OS2
276 PTIB pTib;
277 PPIB pPib;
278 DosGetInfoBlocks(&pTib, &pPib);
279 ThreadId = pPib->pib_pid;
280
281#else
282 KUPTR ThreadId = (KUPTR)getpid();
283#endif
284
285 return ThreadId;
286}
287#define KPRF_GET_PROCESSID() kPrfGetProcessId()
288
289
290/**
291 * Sets the pointer to the profiler data for the current thread.
292 *
293 * We require fast access to the profiler thread data, so we store
294 * it in a TLS (thread local storage) item/key where the implementation
295 * allows that.
296 *
297 * @param pThread The pointer to the profiler thread data for the current thread.
298 */
299static inline void kPrfSetThread(KPRF_TYPE(P,THREAD) pThread)
300{
301/* Win32/64 */
302#if K_OS == K_OS_WINDOWS
303 BOOL fRc = TlsSetValue(g_dwThreadTLS, pThread);
304
305/* Posix Threads */
306#elif defined(KPRF_USE_PTHREAD)
307 int rc = pthread_setspecific(g_ThreadKey, pThread);
308
309#elif K_OS == K_OS_OS2
310 *g_ppThread = pThread;
311
312#else
313# error not implemented
314#endif
315}
316#define KPRF_SET_THREAD(pThread) kPrfSetThread(pThread)
317
318
319/**
320 * Get the now timestamp.
321 * This must correspond to what the assembly code are doing.
322 */
323static inline KU64 kPrfNow(void)
324{
325#if defined(HAVE_INTRIN)
326 return __rdtsc();
327# else
328 union
329 {
330 KU64 u64;
331 struct
332 {
333 KU32 u32Lo;
334 KU32 u32Hi;
335 } s;
336 } u;
337# if defined(__GNUC__)
338 __asm__ __volatile__ ("rdtsc\n\t" : "=a" (u.s.u32Lo), "=d" (u.s.u32Hi));
339# else
340 __asm
341 {
342 rdtsc
343 mov [u.s.u32Lo], eax
344 mov [u.s.u32Hi], edx
345 }
346
347# endif
348 return u.u64;
349#endif
350}
351#define KPRF_NOW() kPrfNow()
352
353
354/**
355 * Atomically set a 32-bit value.
356 */
357static inline void kPrfAtomicSet32(volatile KU32 *pu32, const KU32 u32)
358{
359#if defined(HAVE_INTRIN)
360 _InterlockedExchange((long volatile *)pu32, (const long)u32);
361
362#elif defined(__GNUC__)
363 __asm__ __volatile__("xchgl %0, %1\n\t"
364 : "=m" (*pu32)
365 : "r" (u32));
366
367#elif _MSC_VER
368 __asm
369 {
370 mov edx, [pu32]
371 mov eax, [u32]
372 xchg [edx], eax
373 }
374
375#else
376 *pu32 = u32;
377#endif
378}
379#define KPRF_ATOMIC_SET32(a,b) kPrfAtomicSet32(a, b)
380
381
382
383/**
384 * Atomically set a 64-bit value.
385 */
386static inline void kPrfAtomicSet64(volatile KU64 *pu64, KU64 u64)
387{
388#if defined(HAVE_INTRIN) && KPRF_BITS == 64
389 _InterlockedExchange64((KI64 *)pu64, (const KI64)u64);
390
391#elif defined(__GNUC__) && KPRF_BITS == 64
392 __asm__ __volatile__("xchgq %0, %1\n\t"
393 : "=m" (*pu64)
394 : "r" (u64));
395
396#elif defined(__GNUC__) && KPRF_BITS == 32
397 __asm__ __volatile__("1:\n\t"
398 "lock; cmpxchg8b %1\n\t"
399 "jnz 1b\n\t"
400 : "=A" (u64),
401 "=m" (*pu64)
402 : "0" (*pu64),
403 "b" ( (KU32)u64 ),
404 "c" ( (KU32)(u64 >> 32) ));
405
406#elif _MSC_VER
407 __asm
408 {
409 mov ebx, dword ptr [u64]
410 mov ecx, dword ptr [u64 + 4]
411 mov esi, pu64
412 mov eax, dword ptr [esi]
413 mov edx, dword ptr [esi + 4]
414 retry:
415 lock cmpxchg8b [esi]
416 jnz retry
417 }
418#else
419 *pu64 = u64;
420#endif
421}
422#define KPRF_ATOMIC_SET64(a,b) kPrfAtomicSet64(a, b)
423
424
425/**
426 * Atomically add a 32-bit integer to another.
427 */
428static inline void kPrfAtomicAdd32(volatile KU32 *pu32, const KU32 u32)
429{
430#if defined(HAVE_INTRIN)
431 _InterlockedExchangeAdd((volatile long *)pu32, (const long)u32);
432
433#elif defined(__GNUC__)
434 __asm__ __volatile__("lock; addl %0, %1\n\t"
435 : "=m" (*pu32)
436 : "r" (u32));
437
438#elif _MSC_VER
439 __asm
440 {
441 mov edx, [pu32]
442 mov eax, dword ptr [u32]
443 lock add [edx], eax
444 }
445
446#else
447 *pu32 += u32;
448#endif
449}
450#define KPRF_ATOMIC_ADD32(a,b) kPrfAtomicAdd32(a, b)
451#define KPRF_ATOMIC_INC32(a) kPrfAtomicAdd32(a, 1);
452#define KPRF_ATOMIC_DEC32(a) kPrfAtomicAdd32(a, (KU32)-1);
453
454
455/**
456 * Atomically add a 64-bit integer to another.
457 * Atomically isn't quite required, just a non-corruptive manner, assuming all updates are adds.
458 */
459static inline void kPrfAtomicAdd64(volatile KU64 *pu64, const KU64 u64)
460{
461#if defined(HAVE_INTRIN) && KPRF_BITS == 64
462 _InterlockedExchangeAdd64((volatile KI64 *)pu64, (const KI64)u64);
463
464#elif defined(__GNUC__) && KPRF_BITS == 64
465 __asm__ __volatile__("lock; addq %0, %1\n\t"
466 : "=m" (*pu64)
467 : "r" (u64));
468
469#elif defined(__GNUC__) && KPRF_BITS == 32
470 __asm__ __volatile__("lock; addl %0, %2\n\t"
471 "lock; adcl %1, %3\n\t"
472 : "=m" (*(volatile KU32 *)pu64),
473 "=m" (*((volatile KU32 *)pu64 + 1))
474 : "r" ((KU32)u64),
475 "r" ((KU32)(u64 >> 32)));
476
477#elif _MSC_VER
478 __asm
479 {
480 mov edx, [pu64]
481 mov eax, dword ptr [u64]
482 mov ecx, dword ptr [u64 + 4]
483 lock add [edx], eax
484 lock adc [edx + 4], ecx
485 }
486
487#else
488 *pu64 += u64;
489#endif
490}
491#define KPRF_ATOMIC_ADD64(a,b) kPrfAtomicAdd64(a, b)
492#define KPRF_ATOMIC_INC64(a) kPrfAtomicAdd64(a, 1);
493
494
495/**
496 * Initializes a mutex.
497 *
498 * @returns 0 on success.
499 * @returns -1 on failure.
500 * @param pMutex The mutex to init.
501 */
502static int kPrfMutexInit(KPRF_TYPE(P,MUTEX) pMutex)
503{
504#if defined(KPRF_USE_PTHREAD)
505 if (!pthread_mutex_init(pMutex, NULL));
506 return 0;
507 return -1;
508
509#elif K_OS == K_OS_WINDOWS
510 InitializeCriticalSection(pMutex);
511 return 0;
512
513#elif K_OS == K_OS_OS2
514 if (!_fmutex_create(pMutex, 0))
515 return 0;
516 return -1;
517#endif
518}
519
520/**
521 * Deletes a mutex.
522 *
523 * @param pMutex The mutex to delete.
524 */
525static void kPrfMutexDelete(KPRF_TYPE(P,MUTEX) pMutex)
526{
527#if defined(KPRF_USE_PTHREAD)
528 pthread_mutex_destroy(pMutex);
529
530#elif K_OS == K_OS_WINDOWS
531 DeleteCriticalSection(pMutex);
532
533#elif K_OS == K_OS_OS2
534 _fmutex_close(pMutex);
535#endif
536}
537
538/**
539 * Locks a mutex.
540 * @param pMutex The mutex lock.
541 */
542static inline void kPrfMutexAcquire(KPRF_TYPE(P,MUTEX) pMutex)
543{
544#if K_OS == K_OS_WINDOWS
545 EnterCriticalSection(pMutex);
546
547#elif defined(KPRF_USE_PTHREAD)
548 pthread_mutex_lock(pMutex);
549
550#elif K_OS == K_OS_OS2
551 fmutex_request(pMutex);
552#endif
553}
554
555
556/**
557 * Unlocks a mutex.
558 * @param pMutex The mutex lock.
559 */
560static inline void kPrfMutexRelease(KPRF_TYPE(P,MUTEX) pMutex)
561{
562#if K_OS == K_OS_WINDOWS
563 LeaveCriticalSection(pMutex);
564
565#elif defined(KPRF_USE_PTHREAD)
566 pthread_mutex_lock(pMutex);
567
568#elif K_OS == K_OS_OS2
569 fmutex_request(pMutex);
570#endif
571}
572
573
574#define KPRF_THREADS_LOCK() kPrfMutexAcquire(&g_ThreadsMutex)
575#define KPRF_THREADS_UNLOCK() kPrfMutexRelease(&g_ThreadsMutex)
576
577#define KPRF_MODSEGS_LOCK() kPrfMutexAcquire(&g_ModSegsMutex)
578#define KPRF_MODSEGS_UNLOCK() kPrfMutexRelease(&g_ModSegsMutex)
579
580
581/**
582 * Initializes a read-write lock.
583 *
584 * @returns 0 on success.
585 * @returns -1 on failure.
586 * @param pRWLock The read-write lock to initialize.
587 */
588static inline int kPrfRWLockInit(KPRF_TYPE(P,RWLOCK) pRWLock)
589{
590#if defined(KPRF_USE_PTHREAD)
591 if (!pthread_rwlock_init(pRWLock, NULL))
592 return 0;
593 return -1;
594
595#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
596 if (kPrfMutexInit(&pRWLock->Mutex))
597 return -1;
598 pRWLock->cReaders = 0;
599 pRWLock->cReadersWaiting = 0;
600 pRWLock->cWritersWaiting = 0;
601 pRWLock->enmState = RWLOCK_STATE_SHARED;
602# if K_OS == K_OS_WINDOWS
603 pRWLock->hevReaders = CreateEvent(NULL, TRUE, TRUE, NULL);
604 pRWLock->hevWriters = CreateEvent(NULL, FALSE, FALSE, NULL);
605 if ( pRWLock->hevReaders != INVALID_HANDLE_VALUE
606 && pRWLock->hevWriters != INVALID_HANDLE_VALUE)
607 return 0;
608 CloseHandle(pRWLock->hevReaders);
609 CloseHandle(pRWLock->hevWriters);
610
611# elif K_OS == K_OS_OS2
612 APIRET rc = DosCreateEventSem(NULL, &pRWLock->hevReaders, 0, TRUE);
613 if (!rc)
614 {
615 rc = DosCreateEventSem(NULL, &pRWLock->hevWriters, 0, TRUE);
616 if (!rc)
617 return 0;
618 pRWLock->hevWriters = NULLHANDLE;
619 DosCloseEventSem(pRWLock->hevReaders);
620 }
621 pRWLock->hevReaders = NULLHANDLE;
622# endif
623
624 pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED;
625 kPrfMutexDelete(&pRWLock->Mutex);
626 return -1;
627#endif
628}
629
630
631/**
632 * Deleters a read-write lock.
633 *
634 * @param pRWLock The read-write lock to delete.
635 */
636static inline void kPrfRWLockDelete(KPRF_TYPE(P,RWLOCK) pRWLock)
637{
638#if defined(KPRF_USE_PTHREAD)
639 pthread_rwlock_destroy(pRWLock);
640
641#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
642 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
643 return;
644
645 pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED;
646 kPrfMutexDelete(&pRWLock->Mutex);
647 pRWLock->cReaders = 0;
648 pRWLock->cReadersWaiting = 0;
649 pRWLock->cWritersWaiting = 0;
650# if K_OS == K_OS_WINDOWS
651 CloseHandle(pRWLock->hevReaders);
652 pRWLock->hevReaders = INVALID_HANDLE_VALUE;
653 CloseHandle(pRWLock->hevWriters);
654 pRWLock->hevWriters = INVALID_HANDLE_VALUE;
655
656# elif K_OS == K_OS_OS2
657 DosCloseEventSem(pRWLock->hevReaders);
658 pRWLock->hevReaders = NULLHANDLE;
659 DosCloseEventSem(pRWLock->hevWriters);
660 pRWLock->hevWriters = NULLHANDLE;
661# endif
662#endif
663}
664
665
666/**
667 * Acquires read access to the read-write lock.
668 * @param pRWLock The read-write lock.
669 */
670static inline void kPrfRWLockAcquireRead(KPRF_TYPE(P,RWLOCK) pRWLock)
671{
672#if defined(KPRF_USE_PTHREAD)
673 pthread_rwlock_rdlock(pRWLock);
674
675#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
676 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
677 return;
678
679 kPrfMutexAcquire(&pRWLock->Mutex);
680 if (pRWLock->enmState == RWLOCK_STATE_SHARED)
681 {
682 KPRF_ATOMIC_INC32(&pRWLock->cReaders);
683 kPrfMutexRelease(&pRWLock->Mutex);
684 return;
685 }
686
687 for (;;)
688 {
689 /* have to wait */
690 KPRF_ATOMIC_INC32(&pRWLock->cReadersWaiting);
691# if K_OS == K_OS_WINDOWS
692 HANDLE hev = pRWLock->hevReaders;
693 ResetEvent(hev);
694
695# elif K_OS == K_OS_OS2
696 HEV hev = pRWLock->hevReaders;
697 ULONG cIgnored;
698 DosResetEventSem(hev, &cIgnored);
699
700# endif
701 kPrfMutexRelease(&pRWLock->Mutex);
702
703# if K_OS == K_OS_WINDOWS
704 switch (WaitForSingleObject(hev, INFINITE))
705 {
706 case WAIT_IO_COMPLETION:
707 case WAIT_TIMEOUT:
708 case WAIT_OBJECT_0:
709 break;
710 case WAIT_ABANDONED:
711 default:
712 return;
713 }
714
715# elif K_OS == K_OS_OS2
716 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT))
717 {
718 case NO_ERROR:
719 case ERROR_SEM_TIMEOUT:
720 case ERROR_TIMEOUT:
721 case ERROR_INTERRUPT:
722 break;
723 default:
724 return;
725 }
726# endif
727
728 kPrfMutexAcquire(&pRWLock->Mutex);
729 if (pRWLock->enmState == RWLOCK_STATE_SHARED)
730 {
731 KPRF_ATOMIC_INC32(&pRWLock->cReaders);
732 KPRF_ATOMIC_DEC32(&pRWLock->cReadersWaiting);
733 kPrfMutexRelease(&pRWLock->Mutex);
734 return;
735 }
736 }
737#endif
738}
739
740
741/**
742 * Releases read access to the read-write lock.
743 * @param pRWLock The read-write lock.
744 */
745static inline void kPrfRWLockReleaseRead(KPRF_TYPE(P,RWLOCK) pRWLock)
746{
747#if defined(KPRF_USE_PTHREAD)
748 pthread_rwlock_unlock(pRWLock);
749
750#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
751 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
752 return;
753
754 /*
755 * If we're still in the shared state, or if there
756 * are more readers out there, or if there are no
757 * waiting writers, all we have to do is decrement an leave.
758 *
759 * That's the most frequent, thing and should be fast.
760 */
761 kPrfMutexAcquire(&pRWLock->Mutex);
762 KPRF_ATOMIC_DEC32(&pRWLock->cReaders);
763 if ( pRWLock->enmState == RWLOCK_STATE_SHARED
764 || pRWLock->cReaders
765 || !pRWLock->cWritersWaiting)
766 {
767 kPrfMutexRelease(&pRWLock->Mutex);
768 return;
769 }
770
771 /*
772 * Wake up one (or more on OS/2) waiting writers.
773 */
774# if K_OS == K_OS_WINDOWS
775 SetEvent(pRWLock->hevWriters);
776# elif K_OS == K_OS_OS2
777 DosPostEvent(pRWLock->hevwriters);
778# endif
779 kPrfMutexRelease(&pRWLock->Mutex);
780
781#endif
782}
783
784
785/**
786 * Acquires write access to the read-write lock.
787 * @param pRWLock The read-write lock.
788 */
789static inline void kPrfRWLockAcquireWrite(KPRF_TYPE(P,RWLOCK) pRWLock)
790{
791#if defined(KPRF_USE_PTHREAD)
792 pthread_rwlock_wrlock(pRWLock);
793
794#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
795 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
796 return;
797
798 kPrfMutexAcquire(&pRWLock->Mutex);
799 if ( !pRWLock->cReaders
800 && ( pRWLock->enmState == RWLOCK_STATE_SHARED
801 || pRWLock->enmState == RWLOCK_STATE_LOCKING)
802 )
803 {
804 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE);
805 kPrfMutexRelease(&pRWLock->Mutex);
806 return;
807 }
808
809 /*
810 * We'll have to wait.
811 */
812 if (pRWLock->enmState == RWLOCK_STATE_SHARED)
813 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING);
814 KPRF_ATOMIC_INC32(&pRWLock->cWritersWaiting);
815 for (;;)
816 {
817# if K_OS == K_OS_WINDOWS
818 HANDLE hev = pRWLock->hevWriters;
819# elif K_OS == K_OS_OS2
820 HEV hev = pRWLock->hevWriters;
821# endif
822 kPrfMutexRelease(&pRWLock->Mutex);
823# if K_OS == K_OS_WINDOWS
824 switch (WaitForSingleObject(hev, INFINITE))
825 {
826 case WAIT_IO_COMPLETION:
827 case WAIT_TIMEOUT:
828 case WAIT_OBJECT_0:
829 break;
830 case WAIT_ABANDONED:
831 default:
832 KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
833 return;
834 }
835
836# elif K_OS == K_OS_OS2
837 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT))
838 {
839 case NO_ERROR:
840 case ERROR_SEM_TIMEOUT:
841 case ERROR_TIMEOUT:
842 case ERROR_INTERRUPT:
843 break;
844 default:
845 KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
846 return;
847 }
848 ULONG cIgnored;
849 DosResetEventSem(hev, &cIgnored);
850# endif
851
852 /*
853 * Try acquire the lock.
854 */
855 kPrfMutexAcquire(&pRWLock->Mutex);
856 if ( !pRWLock->cReaders
857 && ( pRWLock->enmState == RWLOCK_STATE_SHARED
858 || pRWLock->enmState == RWLOCK_STATE_LOCKING)
859 )
860 {
861 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE);
862 KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting);
863 kPrfMutexRelease(&pRWLock->Mutex);
864 return;
865 }
866 }
867#endif
868}
869
870
871/**
872 * Releases write access to the read-write lock.
873 * @param pRWLock The read-write lock.
874 */
875static inline void kPrfRWLockReleaseWrite(KPRF_TYPE(P,RWLOCK) pRWLock)
876{
877#if defined(KPRF_USE_PTHREAD)
878 pthread_rwlock_unlock(pRWLock);
879
880#elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
881 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED)
882 return;
883
884 /*
885 * The common thing is that there are noone waiting.
886 * But, before that usual paranoia.
887 */
888 kPrfMutexAcquire(&pRWLock->Mutex);
889 if (pRWLock->enmState != RWLOCK_STATE_EXCLUSIVE)
890 {
891 kPrfMutexRelease(&pRWLock->Mutex);
892 return;
893 }
894 if ( !pRWLock->cReadersWaiting
895 && !pRWLock->cWritersWaiting)
896 {
897 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED);
898 kPrfMutexRelease(&pRWLock->Mutex);
899 return;
900 }
901
902 /*
903 * Someone is waiting, wake them up as we change the state.
904 */
905# if K_OS == K_OS_WINDOWS
906 HANDLE hev = INVALID_HANDLE_VALUE;
907# elif K_OS == K_OS_OS2
908 HEV hev = NULLHANDLE;
909# endif
910
911 if (pRWLock->cWritersWaiting)
912 {
913 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING);
914 hev = pRWLock->hevWriters;
915 }
916 else
917 {
918 KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED);
919 hev = pRWLock->hevReaders;
920 }
921# if K_OS == K_OS_WINDOWS
922 SetEvent(hev);
923# elif K_OS == K_OS_OS2
924 DosPostEvent(pRWLock->hevwriters);
925# endif
926 kPrfMutexRelease(&pRWLock->Mutex);
927
928#endif
929}
930
931#define KPRF_FUNCS_WRITE_LOCK() kPrfRWLockAcquireWrite(&g_FunctionsRWLock)
932#define KPRF_FUNCS_WRITE_UNLOCK() kPrfRWLockReleaseWrite(&g_FunctionsRWLock)
933#define KPRF_FUNCS_READ_LOCK() kPrfRWLockAcquireRead(&g_FunctionsRWLock)
934#define KPRF_FUNCS_READ_UNLOCK() kPrfRWLockReleaseRead(&g_FunctionsRWLock)
935
936
937
938
939/**
940 * Finds the module segment which the address belongs to.
941 *
942 */
943static int kPrfGetModSeg(KPRF_TYPE(,UPTR) uAddress, char *pszPath, KU32 cchPath, KU32 *piSegment,
944 KPRF_TYPE(P,UPTR) puBasePtr, KPRF_TYPE(P,UPTR) pcbSegmentMinusOne)
945{
946#if K_OS == K_OS_WINDOWS
947 /*
948 * Enumerate the module handles.
949 */
950 HANDLE hProcess = GetCurrentProcess();
951 DWORD cbNeeded = 0;
952 HMODULE hModIgnored;
953 if ( !EnumProcessModules(hProcess, &hModIgnored, sizeof(hModIgnored), &cbNeeded)
954 && GetLastError() != ERROR_BUFFER_OVERFLOW) /** figure out what this actually returns */
955 cbNeeded = 256 * sizeof(HMODULE);
956
957 cbNeeded += sizeof(HMODULE) * 32;
958 HMODULE *pahModules = (HMODULE *)alloca(cbNeeded);
959 if (EnumProcessModules(hProcess, pahModules, cbNeeded, &cbNeeded))
960 {
961 const unsigned cModules = cbNeeded / sizeof(HMODULE);
962 for (unsigned i = 0; i < cModules; i++)
963 {
964 __try
965 {
966 const KUPTR uImageBase = (KUPTR)pahModules[i];
967 union
968 {
969 KU8 *pu8;
970 PIMAGE_DOS_HEADER pDos;
971 PIMAGE_NT_HEADERS pNt;
972 PIMAGE_NT_HEADERS32 pNt32;
973 PIMAGE_NT_HEADERS64 pNt64;
974 KUPTR u;
975 } u;
976 u.u = uImageBase;
977
978 /* reject modules higher than the address. */
979 if (uAddress < u.u)
980 continue;
981
982 /* Skip past the MZ header */
983 if (u.pDos->e_magic == IMAGE_DOS_SIGNATURE)
984 u.pu8 += u.pDos->e_lfanew;
985
986 /* Ignore anything which isn't an NT header. */
987 if (u.pNt->Signature != IMAGE_NT_SIGNATURE)
988 continue;
989
990 /* Extract necessary info from the optional header (comes in 32-bit and 64-bit variations, we simplify a bit). */
991 KU32 cbImage;
992 PIMAGE_SECTION_HEADER paSHs;
993 if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
994 {
995 paSHs = (PIMAGE_SECTION_HEADER)(u.pNt32 + 1);
996 cbImage = u.pNt32->OptionalHeader.SizeOfImage;
997 }
998 else if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
999 {
1000 paSHs = (PIMAGE_SECTION_HEADER)(u.pNt64 + 1);
1001 cbImage = u.pNt64->OptionalHeader.SizeOfImage;
1002 }
1003 else
1004 continue;
1005
1006 /* Is our address within the image size */
1007 KUPTR uRVA = uAddress - (KUPTR)pahModules[i];
1008 if (uRVA >= cbImage)
1009 continue;
1010
1011 /*
1012 * Iterate the section headers and figure which section we're in.
1013 * (segment == section + 1)
1014 */
1015 const KU32 cSHs = u.pNt->FileHeader.NumberOfSections;
1016 if (uRVA < paSHs[0].VirtualAddress)
1017 {
1018 /* the implicit header section */
1019 *puBasePtr = uImageBase;
1020 *pcbSegmentMinusOne = paSHs[0].VirtualAddress - 1;
1021 *piSegment = 0;
1022 }
1023 else
1024 {
1025 KU32 iSH = 0;
1026 for (;;)
1027 {
1028 if (iSH >= cSHs)
1029 {
1030 /* this shouldn't happen, but in case it does simply deal with it. */
1031 *puBasePtr = paSHs[iSH - 1].VirtualAddress + paSHs[iSH - 1].Misc.VirtualSize + uImageBase;
1032 *pcbSegmentMinusOne = cbImage - *puBasePtr;
1033 *piSegment = iSH + 1;
1034 break;
1035 }
1036 if (uRVA - paSHs[iSH].VirtualAddress < paSHs[iSH].Misc.VirtualSize)
1037 {
1038 *puBasePtr = paSHs[iSH].VirtualAddress + uImageBase;
1039 *pcbSegmentMinusOne = paSHs[iSH].Misc.VirtualSize;
1040 *piSegment = iSH + 1;
1041 break;
1042 }
1043 iSH++;
1044 }
1045 }
1046
1047 /*
1048 * Finally, get the module name.
1049 * There are multiple ways, try them all before giving up.
1050 */
1051 if ( !GetModuleFileNameEx(hProcess, pahModules[i], pszPath, cchPath)
1052 && !GetModuleFileName(pahModules[i], pszPath, cchPath)
1053 && !GetMappedFileName(hProcess, (PVOID)uAddress, pszPath, cchPath)
1054 && !GetModuleBaseName(hProcess, pahModules[i], pszPath, cchPath))
1055 *pszPath = '\0';
1056 return 0;
1057 }
1058 __except (EXCEPTION_EXECUTE_HANDLER)
1059 {
1060 }
1061 }
1062 }
1063
1064#elif K_OS == K_OS_OS2
1065 /*
1066 * Just ask the loader.
1067 */
1068 ULONG offObj = 0;
1069 ULONG iObj = 0;
1070 HMODULE hmod = NULLHANDLE;
1071 APIRET rc = DosQueryModFromEIP(&hmod, &iObj, cchPath, pszPath, &offObj, uAddress);
1072 if (!rc)
1073 {
1074 *piSegment = iObj;
1075 *puBasePtr = uAddress - offObj;
1076 *pcbSegmentMinusOne = KPRF_ALIGN(offObj, 0x1000) - 1; /* minimum size */
1077
1078 /*
1079 * Query the page attributes starting at the current page. The query will not enter
1080 * into the next object since PAG_BASE is requested.
1081 */
1082 ULONG cb = ~0UL;
1083 ULONG fFlags = ~0UL;
1084 uAddress &= ~(KUPTR)0xfff;
1085 rc = DosQueryMem((PVOID)(uAddress, &cb, &fFlags);
1086 if (!rc)
1087 {
1088 *pcbSegmentMinusOne = (offObj & ~(KUPTR)0xfff) + KPRF_ALIGN(cb, 0x1000) - 1;
1089 if ((fFlags & PAG_BASE) && cb <= 0x1000) /* don't quite remember if PAG_BASE returns one page or not */
1090 {
1091 cb = ~0UL;
1092 fFlags = ~0UL;
1093 rc = DosQueryMem((PVOID)(uAddress + 0x1000), &cb, &fFlags);
1094 if (!rc & !(fFlags & (PAG_BASE | PAG_FREE)))
1095 *pcbSegmentMinusOne += KPRF_ALIGN(cb, 0x1000);
1096 }
1097 }
1098 return 0;
1099 }
1100
1101#endif
1102 /* The common fallback */
1103 *pszPath = '\0';
1104 *piSegment = 0;
1105 *puBasePtr = 0;
1106 *pcbSegmentMinusOne = ~(KPRF_TYPE(,UPTR))0;
1107 return -1;
1108}
1109#define KPRF_GET_MODSEG(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) \
1110 kPrfGetModSeg(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne)
1111
1112
1113
1114
1115/*
1116 * Instantiate the implementation
1117 */
1118#include "prfcorepre.cpp.h"
1119
1120#include "prfcoremodseg.cpp.h"
1121#include "prfcorefunction.cpp.h"
1122#include "prfcore.cpp.h"
1123#include "prfcoreinit.cpp.h"
1124#include "prfcoreterm.cpp.h"
1125
1126#include "prfcorepost.cpp.h"
1127
1128
1129
1130
1131
1132/**
1133 * Registers an unknown thread.
1134 *
1135 * @returns Pointer to the registered thread.
1136 */
1137static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void)
1138{
1139 KUPTR uStackBasePtr;
1140
1141#if 0
1142 /** @todo I'm sure Win32 has a way of obtaining the top and bottom of the stack, OS/2 did...
1143 * Some limit stuff in posix / ansi also comes to mind... */
1144
1145#elif K_OS == K_OS_OS2
1146 PTIB pTib;
1147 PPIB pPib;
1148 DosGetInfoBlocks(&pTib, &pPib); /* never fails except if you give it bad input, thus 'Get' not 'Query'. */
1149 /* I never recall which of these is the right one... */
1150 uStackBasePtr = (KUPTR)pTib->tib_pstack < (KUPTR)pTib->tib_pstack_limit
1151 ? (KUPTR)pTib->tib_pstack
1152 : (KUPTR)pTib->tib_pstack_limit;
1153
1154#else
1155 /* the default is top of the current stack page (assuming a page to be 4KB) */
1156 uStackBasePtr = (KUPTR)&uStackBasePtr;
1157 uStackBasePtr = (uStackBasePtr + 0xfff) & ~(KUPTR)0xfff;
1158#endif
1159
1160 return KPRF_NAME(RegisterThread)(uStackBasePtr, "");
1161}
1162
1163
1164/**
1165 * Get a env.var. variable.
1166 *
1167 * @returns pszValue.
1168 * @param pszVar The variable name.
1169 * @param pszValue Where to store the value.
1170 * @param cchValue The size of the value buffer.
1171 * @param pszDefault The default value.
1172 */
1173static char *kPrfGetEnvString(const char *pszVar, char *pszValue, KU32 cchValue, const char *pszDefault)
1174{
1175#if K_OS == K_OS_WINDOWS
1176 if (GetEnvironmentVariable(pszVar, pszValue, cchValue))
1177 return pszValue;
1178
1179#elif K_OS == K_OS_OS2
1180 PSZ pszValue;
1181 if ( !DosScanEnv((PCSZ)pszVar, &pszValue)
1182 && !*pszValue)
1183 pszDefault = pszValue;
1184
1185#else
1186 const char *pszTmp = getenv(pszVar);
1187 if (pszTmp)
1188 pszDefault = pszTmp;
1189
1190#endif
1191
1192 /*
1193 * Copy the result into the buffer.
1194 */
1195 char *psz = pszValue;
1196 while (*pszDefault && cchValue-- > 1)
1197 *psz++ = *pszDefault++;
1198 *psz = '\0';
1199
1200 return pszValue;
1201}
1202
1203
1204/**
1205 * The the value of an env.var.
1206 *
1207 * @returns The value of the env.var.
1208 * @returns The default if the value was not found.
1209 * @param pszVar The variable name.
1210 * @param uDefault The default value.
1211 */
1212static KU32 kPrfGetEnvValue(const char *pszVar, KU32 uDefault)
1213{
1214#if K_OS == K_OS_WINDOWS
1215 char szBuf[128];
1216 const char *pszValue = szBuf;
1217 if (!GetEnvironmentVariable(pszVar, szBuf, sizeof(szBuf)))
1218 pszValue = NULL;
1219
1220#elif K_OS == K_OS_OS2
1221 PSZ pszValue;
1222 if (DosScanEnv((PCSZ)pszVar, &pszValue))
1223 pszValue = NULL;
1224
1225#else
1226 const char *pszValue = getenv(pszVar);
1227
1228#endif
1229
1230 /*
1231 * Discard the obvious stuff.
1232 */
1233 if (!pszValue)
1234 return uDefault;
1235 while (*pszValue == ' ' || *pszValue == '\t')
1236 pszValue++;
1237 if (!*pszValue)
1238 return uDefault;
1239
1240 /*
1241 * Interpret the value.
1242 */
1243 unsigned uBase = 10;
1244 KU32 uValue = 0;
1245 const char *psz = pszValue;
1246
1247 /* prefix - only hex */
1248 if (*psz == '0' && (psz[1] == 'x' || psz[1] == 'X'))
1249 {
1250 uBase = 16;
1251 psz += 2;
1252 }
1253
1254 /* read the value */
1255 while (*psz)
1256 {
1257 unsigned char ch = (unsigned char)*psz;
1258 if (ch >= '0' && ch <= '9')
1259 ch -= '0';
1260 else if ( uBase > 10
1261 && ch >= 'a' && ch <= 'f')
1262 ch -= 'a' + 10;
1263 else if ( uBase > 10
1264 && ch >= 'a' && ch <= 'F')
1265 ch -= 'a' + 10;
1266 else
1267 break;
1268 uValue *= uBase;
1269 uValue += ch;
1270 psz++;
1271 }
1272
1273 /* postfixes */
1274 switch (*psz)
1275 {
1276 case 'm':
1277 case 'M':
1278 uValue *= 1024*1024;
1279 break;
1280
1281 case 'k':
1282 case 'K':
1283 uValue *= 1024;
1284 break;
1285 }
1286
1287 /*
1288 * If the value is still 0, we return the default.
1289 */
1290 return uValue ? uValue : uDefault;
1291}
1292
1293
1294/**
1295 * Allocates memory.
1296 *
1297 * @returns Pointer to the allocated memory.
1298 * @returns NULL on failure.
1299 * @param cb The amount of memory (in bytes) to allocate.
1300 */
1301static void *kPrfAllocMem(KU32 cb)
1302{
1303#if K_OS == K_OS_WINDOWS
1304 void *pv = VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1305
1306#elif defined(KPRF_USE_MMAN)
1307 void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1308
1309#elif K_OS == K_OS_OS2
1310 void *pv;
1311# ifdef INCL_DOSEXAPIS
1312 if (DosAllocMemEx(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_FORK))s
1313# else
1314 if (DosAllocMem(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT))
1315# endif
1316 pvBuf = NULL;
1317
1318#else
1319# error not implemented
1320#endif
1321 return pv;
1322}
1323
1324
1325/**
1326 * Frees memory.
1327 *
1328 * @param pv The memory to free.
1329 */
1330static void kPrfFreeMem(void *pv)
1331{
1332#if K_OS == K_OS_WINDOWS
1333 VirtualFree(pv, 0, MEM_RELEASE);
1334
1335#elif defined(KPRF_USE_MMAN)
1336 munmap(pv, 0); /** @todo check if 0 is allowed here.. */
1337
1338#elif K_OS == K_OS_OS2
1339# ifdef INCL_DOSEXAPIS
1340 DosFreeMemEx(&pv);
1341# else
1342 DosFreeMem(&pv);
1343# endif
1344
1345#else
1346# error not implemented
1347#endif
1348}
1349
1350
1351/**
1352 * Writes a data buffer to a new file.
1353 *
1354 * Any existing file will be overwritten.
1355 *
1356 *
1357 * @returns 0 on success.
1358 * @returns -1 on failure.
1359 *
1360 * @param pszName The name of the file.
1361 * @param pvData The data to write.
1362 * @param cbData The amount of data to write.
1363 */
1364static int kPrfWriteFile(const char *pszName, const void *pvData, KU32 cbData)
1365{
1366#if K_OS == K_OS_WINDOWS
1367 int rc = -1;
1368 HANDLE hFile = CreateFile(pszName,GENERIC_WRITE, FILE_SHARE_READ, NULL,
1369 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
1370 if (hFile != INVALID_HANDLE_VALUE)
1371 {
1372 DWORD dwWritten;
1373 if ( WriteFile(hFile, pvData, cbData, &dwWritten, NULL)
1374 && dwWritten == cbData)
1375 rc = 0;
1376 CloseHandle(hFile);
1377 }
1378 return rc;
1379
1380#elif K_OS == K_OS_OS2
1381 HFILE hFile;
1382 ULONG ulAction = 0;
1383 APIRET rc = DosOpen(pszName, &hFile, &ulAction, cbData, FILE_NORMAL,
1384 OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
1385 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_SEQUENTIAL,
1386 NULL);
1387 if (!rc)
1388 {
1389 ULONG cbWritten;
1390 rc = DosWrite(hFile, pvData, cbData, &cbWritten);
1391 if (!rc && cbWritten != cbData)
1392 rc = -1;
1393 DosClose(hFile);
1394 }
1395 return rc ? -1 : 0;
1396
1397#else
1398 int rc = -1;
1399 int fd = open(pszName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, 0666);
1400 if (fd >= 0)
1401 {
1402 if (write(fd, pvData, cbData) == cbData)
1403 rc = 0;
1404 close(fd);
1405 }
1406 return rc;
1407
1408#endif
1409}
1410
1411
1412
1413/**
1414 * Initializes and start the profiling.
1415 *
1416 * This should typically be called from some kind of module init
1417 * function, so we can start profiling upon/before entering main().
1418 *
1419 * @returns 0 on success
1420 * @returns -1 on failure.
1421 *
1422 */
1423int kPrfInitialize(void)
1424{
1425 /*
1426 * Only initialize once.
1427 */
1428 if (KPRF_GET_HDR())
1429 return 0;
1430
1431 /*
1432 * Initial suggestions.
1433 */
1434 KU32 cbModSegs = kPrfGetEnvValue("KPRF2_CBMODSEGS", 128*1024);
1435 KU32 cFunctions = kPrfGetEnvValue("KPRF2_CFUNCTIONS", 8192);
1436 KU32 cThreads = kPrfGetEnvValue("KPRF2_CTHREADS", 256);
1437 KU32 cStacks = kPrfGetEnvValue("KPRF2_CSTACKS", 48);
1438 KU32 cFrames = kPrfGetEnvValue("KPRF2_CFRAMES", 448);
1439 KU32 fAffinity = kPrfGetEnvValue("KPRF2_AFFINITY", 0);
1440
1441 KU32 cb = KPRF_NAME(CalcSize)(cFunctions, cbModSegs, cThreads, cStacks, cFrames);
1442
1443 /*
1444 * Allocate and initialize the data set.
1445 */
1446 void *pvBuf = kPrfAllocMem(cb);
1447 if (!pvBuf)
1448 return -1;
1449
1450 KPRF_TYPE(P,HDR) pHdr = KPRF_NAME(Init)(pvBuf, cb, cFunctions, cbModSegs, cThreads, cStacks, cFrames);
1451 if (pHdr)
1452 {
1453 /*
1454 * Initialize semaphores.
1455 */
1456 if (!kPrfMutexInit(&g_ThreadsMutex))
1457 {
1458 if (!kPrfMutexInit(&g_ModSegsMutex))
1459 {
1460 if (!kPrfRWLockInit(&g_FunctionsRWLock))
1461 {
1462 /*
1463 * Allocate the TLS entry.
1464 */
1465#if K_OS == K_OS_WINDOWS
1466 g_dwThreadTLS = TlsAlloc();
1467 if (g_dwThreadTLS != TLS_OUT_OF_INDEXES)
1468
1469#elif defined(KPRF_USE_PTHREAD)
1470 int rc = pthread_key_create(&g_ThreadKey, kPrfPThreadKeyDtor);
1471 if (!rc)
1472
1473#elif K_OS == K_OS_OS2
1474 int rc = DosAllocThreadLocalMemory(sizeof(void *), (PULONG*)&g_ppThread); /** @todo check if this is a count or a size. */
1475 if (!rc)
1476
1477#endif
1478 {
1479 /*
1480 * Apply the affinity mask, if specified.
1481 */
1482 if (fAffinity)
1483 {
1484#if K_OS == K_OS_WINDOWS
1485 SetProcessAffinityMask(GetCurrentProcess(), fAffinity);
1486#endif
1487 }
1488
1489 g_pHdr = pHdr;
1490 g_fEnabled = true;
1491 return 0;
1492 }
1493 kPrfRWLockDelete(&g_FunctionsRWLock);
1494 }
1495 kPrfMutexDelete(&g_ModSegsMutex);
1496 }
1497 kPrfMutexDelete(&g_ThreadsMutex);
1498 }
1499 }
1500 kPrfFreeMem(pvBuf);
1501 return -1;
1502}
1503
1504
1505/**
1506 * Stops, dumps, and terminates the profiling.
1507 *
1508 * This should typically be called from some kind of module destruction
1509 * function, so we can profile parts of the termination sequence too.
1510 *
1511 * @returns 0 on success
1512 * @returns -1 on failure.
1513 *
1514 */
1515int kPrfTerminate(void)
1516{
1517 /*
1518 * Stop the profiling.
1519 * As a safety precaution, sleep a little bit to allow threads
1520 * still at large inside profiler code some time to get out.
1521 */
1522 g_fEnabled = false;
1523 KPRF_TYPE(P,HDR) pHdr = g_pHdr;
1524 g_pHdr = NULL;
1525 if (!pHdr)
1526 return -1;
1527
1528#if K_OS == K_OS_WINDOWS
1529 Sleep(10);
1530#elif K_OS == K_OS_OS2
1531 DosSleep(10);
1532#else
1533 usleep(10000);
1534#endif
1535
1536 /*
1537 * Unwind all active threads and so forth.
1538 */
1539 KPRF_NAME(TerminateAll)(pHdr);
1540
1541 /*
1542 * Use the stack space to fill in process details.
1543 */
1544#if K_OS == K_OS_WINDOWS
1545 /* all is one single string */
1546 const char *pszCommandLine = GetCommandLine();
1547 if (pszCommandLine)
1548 KPRF_NAME(SetCommandLine)(pHdr, 1, &pszCommandLine);
1549
1550#elif K_OS == K_OS_OS2 || K_OS == K_OS_OS2
1551 PTIB pTib;
1552 PPIB pPib;
1553 DosGetInfoBlocks(&pTib, &pPib);
1554 if (pPib->pib_pchcmd)
1555 {
1556 /* Tradition say that the commandline is made up of two zero terminate strings
1557 * - first the executable name, then the arguments. Similar to what unix does,
1558 * only completely mocked up because of the CMD.EXE tradition.
1559 */
1560 const char *apszArgs[2];
1561 apszArgs[0] = pPib->pib_pchcmd;
1562 apszArgs[1] = pPib->pib_pchcmd;
1563 while (apszArgs[1][0])
1564 apszArgs[1]++;
1565 apszArgs[1]++;
1566 KPRF_NAME(SetCommandLine)(pHdr, 2, apszArgs);
1567 }
1568
1569#else
1570 /* linux can read /proc/self/something I guess. Don't know about the rest... */
1571
1572#endif
1573
1574 /*
1575 * Write the file to disk.
1576 */
1577 char szName[260 + 16];
1578 kPrfGetEnvString("KPRF2_FILE", szName, sizeof(szName) - 16, "kPrf2-");
1579
1580 /* append the process id */
1581 KUPTR pid = kPrfGetProcessId();
1582 char *psz = szName;
1583 while (*psz)
1584 psz++;
1585
1586 static char s_szDigits[0x11] = "0123456789abcdef";
1587 KU32 uShift = KPRF_BITS - 4;
1588 while ( uShift > 0
1589 && !(pid & (0xf << uShift)))
1590 uShift -= 4;
1591 *psz++ = s_szDigits[(pid >> uShift) & 0xf];
1592 while (uShift > 0)
1593 {
1594 uShift -= 4;
1595 *psz++ = s_szDigits[(pid >> uShift) & 0xf];
1596 }
1597
1598 /* .kPrf2 */
1599 *psz++ = '.';
1600 *psz++ = 'k';
1601 *psz++ = 'P';
1602 *psz++ = 'r';
1603 *psz++ = 'f';
1604 *psz++ = '2';
1605 *psz++ = '\0';
1606
1607 /* write the file. */
1608 int rc = kPrfWriteFile(szName, pHdr, pHdr->cb);
1609
1610 /*
1611 * Free resources.
1612 */
1613 kPrfFreeMem(pHdr);
1614#if K_OS == K_OS_WINDOWS
1615 TlsFree(g_dwThreadTLS);
1616 g_dwThreadTLS = TLS_OUT_OF_INDEXES;
1617
1618#elif defined(KPRF_USE_PTHREAD)
1619 pthread_key_delete(g_ThreadKey);
1620 g_ThreadKey = (pthread_key_t)-1;
1621
1622#elif K_OS == K_OS_OS2
1623 DosFreeThreadLocalMemory((PULONG)g_ppThread);
1624 g_ppThread = NULL;
1625
1626#else
1627# error "port me!"
1628#endif
1629
1630 kPrfMutexDelete(&g_ThreadsMutex);
1631 kPrfMutexDelete(&g_ModSegsMutex);
1632 kPrfRWLockDelete(&g_FunctionsRWLock);
1633
1634 return rc;
1635}
1636
1637
1638/**
1639 * Terminate the current thread.
1640 */
1641void kPrfTerminateThread(void)
1642{
1643 KPRF_NAME(DeregisterThread)();
1644}
1645
1646
1647#ifdef KPRF_USE_PTHREAD
1648/**
1649 * TLS destructor.
1650 */
1651static void kPrfPThreadKeyDtor(void *pvThread)
1652{
1653 KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR();
1654 if (pHdr)
1655 {
1656 KPRF_TYPE(P,THREAD) pThread = (KPRF_TYPE(P,THREAD))pvThread;
1657 pthread_setspecific(g_ThreadKey, pvThread);
1658 KPRF_NAME(TerminateThread)(pHdr, pThread, KPRF_NOW());
1659 pthread_setspecific(g_ThreadKey, NULL);
1660 }
1661}
1662#endif
1663
Note: See TracBrowser for help on using the repository browser.

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