source: trunk/kProfile/kProfileR3.cpp@ 3524

Last change on this file since 3524 was 3524, checked in by bird, 18 years ago

kProfile Mark II. Some early/old code.

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