VirtualBox

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

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

Finally got around execute the switch to the MIT license.

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

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