summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/rts/OSThreads.h27
-rw-r--r--rts/Task.c5
-rw-r--r--rts/Task.h39
-rw-r--r--rts/posix/OSThreads.c26
-rw-r--r--rts/win32/OSThreads.c8
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;
+}