diff --git a/src/profile.c b/src/profile.c index 1c0e80bf8..40a0ece63 100644 --- a/src/profile.c +++ b/src/profile.c @@ -22,6 +22,12 @@ #include #include +#ifdef HL_LINUX +#include +#include +#include +#endif + #define MAX_STACK_SIZE (8 << 20) #define MAX_STACK_COUNT 2048 @@ -73,6 +79,25 @@ static struct { profile_data *first_record; } data = {0}; +#ifdef HL_LINUX +static struct +{ + sem_t msg2; + sem_t msg3; + sem_t msg4; + ucontext_t context; +} shared_context; + +static void sigprof_handler(int sig, siginfo_t *info, void *ucontext) +{ + ucontext_t *ctx = ucontext; + shared_context.context = *ctx; + sem_post(&shared_context.msg2); + sem_wait(&shared_context.msg3); + sem_post(&shared_context.msg4); +} +#endif + static void *get_thread_stackptr( thread_handle *t, void **eip ) { #ifdef HL_WIN_DESKTOP CONTEXT c; @@ -85,6 +110,14 @@ static void *get_thread_stackptr( thread_handle *t, void **eip ) { *eip = (void*)c.Eip; return (void*)c.Esp; # endif +#elif defined(HL_LINUX) +# ifdef HL_64 + *eip = (void*)shared_context.context.uc_mcontext.gregs[REG_RIP]; + return (void*)shared_context.context.uc_mcontext.gregs[REG_RSP]; +# else + *eip = (void*)shared_context.context.uc_mcontext.gregs[REG_EIP]; + return (void*)shared_context.context.uc_mcontext.gregs[REG_ESP]; +# endif #else return NULL; #endif @@ -110,6 +143,14 @@ static bool pause_thread( thread_handle *t, bool b ) { ResumeThread(t->h); return true; } +#elif defined(HL_LINUX) + if( b ) { + tgkill(getpid(), t->tid, SIGPROF); + return sem_wait(&shared_context.msg2) == 0; + } else { + sem_post(&shared_context.msg3); + return sem_wait(&shared_context.msg4) == 0; + } #else return false; #endif @@ -144,6 +185,10 @@ static void read_thread_data( thread_handle *t ) { return; } +#ifdef HL_LINUX + int count = hl_module_capture_stack_range(t->inf->stack_top, stack, data.stackOut, MAX_STACK_COUNT); + pause_thread(t, false); +#else int size = (int)((unsigned char*)t->inf->stack_top - (unsigned char*)stack); if( size > MAX_STACK_SIZE-32 ) size = MAX_STACK_SIZE-32; memcpy(data.tmpMemory + 2,stack,size); @@ -153,6 +198,7 @@ static void read_thread_data( thread_handle *t ) { size += sizeof(void*) * 2; int count = hl_module_capture_stack_range((char*)data.tmpMemory+size, (void**)data.tmpMemory, data.stackOut, MAX_STACK_COUNT); +#endif int eventId = count | 0x80000000; double time = hl_sys_time(); record_data(&time,sizeof(double)); @@ -211,7 +257,7 @@ static void hl_profile_loop( void *_ ) { static void profile_event( int code, vbyte *data, int dataLen ); void hl_profile_setup( int sample_count ) { -# if defined(HL_THREADS) && defined(HL_WIN_DESKTOP) +# if defined(HL_THREADS) && (defined(HL_WIN_DESKTOP) || defined(HL_LINUX)) hl_setup_profiler(profile_event,hl_profile_end); if( data.sample_count ) return; if( sample_count < 0 ) { @@ -220,6 +266,15 @@ void hl_profile_setup( int sample_count ) { return; } data.sample_count = sample_count; +# ifdef HL_LINUX + sem_init(&shared_context.msg2, 0, 0); + sem_init(&shared_context.msg3, 0, 0); + sem_init(&shared_context.msg4, 0, 0); + struct sigaction action = {0}; + action.sa_sigaction = sigprof_handler; + action.sa_flags = SA_SIGINFO; + sigaction(SIGPROF, &action, NULL); +# endif hl_thread_start(hl_profile_loop,NULL,false); # endif }