diff options
-rw-r--r-- | includes/rts/OSThreads.h | 27 | ||||
-rw-r--r-- | rts/Task.c | 5 | ||||
-rw-r--r-- | rts/Task.h | 39 | ||||
-rw-r--r-- | rts/posix/OSThreads.c | 26 | ||||
-rw-r--r-- | rts/win32/OSThreads.c | 8 |
5 files changed, 100 insertions, 5 deletions
diff --git a/includes/rts/OSThreads.h b/includes/rts/OSThreads.h index cf72e1de69..260aac15a8 100644 --- a/includes/rts/OSThreads.h +++ b/includes/rts/OSThreads.h @@ -15,7 +15,7 @@ #ifndef RTS_OSTHREADS_H #define RTS_OSTHREADS_H -#if defined(THREADED_RTS) /* to the end */ +#if defined(THREADED_RTS) /* to near the end */ #if defined(HAVE_PTHREAD_H) && !defined(mingw32_HOST_OS) @@ -222,6 +222,29 @@ int forkOS_createThread ( HsStablePtr entry ); // Returns the number of processor cores in the machine // nat getNumberOfProcessors (void); -#endif + +// +// Support for getting at the kernel thread Id for tracing/profiling. +// +// This stuff is optional and only used for tracing/profiling purposes, to +// match up thread ids recorded by other tools. For example, on Linux and OSX +// the pthread_t type is not the same as the kernel thread id, and system +// profiling tools like Linux perf, and OSX's DTrace use the kernel thread Id. +// So if we want to match up RTS tasks with kernel threads recorded by these +// tools then we need to know the kernel thread Id, and this must be a separate +// type from the OSThreadId. +// +// If the feature cannot be supported on an OS, it is OK to always return 0. +// In particular it would almost certaily be meaningless on systems not using +// a 1:1 threading model. + +// We use a common serialisable representation on all OSs +// This is ok for Windows, OSX and Linux. +typedef StgWord64 KernelThreadId; + +// Get the current kernel thread id +KernelThreadId kernelThreadId (void); + +#endif /* CMINUSMINUS */ #endif /* RTS_OSTHREADS_H */ diff --git a/rts/Task.c b/rts/Task.c index 125000b914..b6092e5e41 100644 --- a/rts/Task.c +++ b/rts/Task.c @@ -389,7 +389,10 @@ workerTaskStop (Task *task) #endif #ifdef DEBUG - +// We don't replace this function with serialisableTaskId, +// because debug prints as pointers are more readable than random +// 64-bit intergers (especially on 32-bit architectures) +// and because we want to use this function also for non-treaded RTS. static void *taskId(Task *task) { #ifdef THREADED_RTS diff --git a/rts/Task.h b/rts/Task.h index ab47a07fc3..7c9c86e40b 100644 --- a/rts/Task.h +++ b/rts/Task.h @@ -159,7 +159,6 @@ isBoundTask (Task *task) return (task->incall->tso != NULL); } - // Linked list of all tasks. // extern Task *all_tasks; @@ -275,6 +274,44 @@ setMyTask (Task *task) #endif } +// Tasks are identified by their OS thread ID, which can be serialised +// to StgWord64, as defined below. +typedef StgWord64 TaskId; + +// Get a unique serialisable representation for a task id. +// +// It's only unique within the process. For example if they are emitted in a +// log file then it is suitable to work out which log entries are releated. +// +// This is needed because OSThreadId is an opaque type +// and in practice on some platforms it is a pointer type. +// +#if defined(THREADED_RTS) +INLINE_HEADER TaskId serialiseTaskId (OSThreadId taskID) { +#if defined(freebsd_HOST_OS) || defined(darwin_HOST_OS) + // Here OSThreadId is a pthread_t and pthread_t is a pointer, but within + // the process we can still use that pointer value as a unique id. + return (TaskId) taskID +#else + // On Windows, Linux and others it's an integral type to start with. + return taskID; +#endif +} +#endif + +// +// Get a serialisable Id for the Task's OS thread +// Needed mainly for logging since the OSThreadId is an opaque type +INLINE_HEADER TaskId +serialisableTaskId (Task *task STG_UNUSED) +{ +#if defined(THREADED_RTS) + return serialiseTaskId(task->id); +#else + return 1; +#endif +} + #include "EndPrivate.h" #endif /* TASK_H */ diff --git a/rts/posix/OSThreads.c b/rts/posix/OSThreads.c index c29454809f..5fd09982de 100644 --- a/rts/posix/OSThreads.c +++ b/rts/posix/OSThreads.c @@ -23,6 +23,12 @@ #include "Rts.h" +#if defined(linux_HOST_OS) +#include <unistd.h> +#include <sys/types.h> +#include <sys/syscall.h> +#endif + #if defined(THREADED_RTS) #include "RtsUtils.h" #include "Task.h" @@ -312,4 +318,24 @@ nat getNumberOfProcessors (void) return 1; } +#endif /* defined(THREADED_RTS) */ + +KernelThreadId kernelThreadId (void) +{ +#if defined(linux_HOST_OS) + pid_t tid = syscall(SYS_gettid); // no really, see man gettid + return tid; + +#elif defined(freebsd_HOST_OS) + return pthread_getthreadid_np(); + +#elif defined(darwin_HOST_OS) + uint64_t ktid; + pthread_threadid_np(NULL, &ktid); + return ktid; + +#else + // unsupported + return 0; #endif +} diff --git a/rts/win32/OSThreads.c b/rts/win32/OSThreads.c index 818f97b879..d0d97b3c4d 100644 --- a/rts/win32/OSThreads.c +++ b/rts/win32/OSThreads.c @@ -10,9 +10,9 @@ #define _WIN32_WINNT 0x0500 #include "Rts.h" +#include <windows.h> #if defined(THREADED_RTS) #include "RtsUtils.h" -#include <windows.h> /* For reasons not yet clear, the entire contents of process.h is protected * by __STRICT_ANSI__ not being defined. @@ -314,3 +314,9 @@ nat getNumberOfProcessors (void) } #endif /* !defined(THREADED_RTS) */ + +KernelThreadId kernelThreadId (void) +{ + DWORD tid = GetCurrentThreadId(); + return tid; +} |