source: trunk/kProfiler2/kProfileR3.cpp@ 4

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

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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