source: trunk/kProfile/kProfileR3.cpp@ 3526

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

made it build again.

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