summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
Diffstat (limited to 'rts')
-rw-r--r--rts/GetEnv.h23
-rw-r--r--rts/RtsStartup.c3
-rw-r--r--rts/Trace.c49
-rw-r--r--rts/Trace.h10
-rw-r--r--rts/eventlog/EventLog.c86
-rw-r--r--rts/eventlog/EventLog.h15
-rw-r--r--rts/ghc.mk1
-rw-r--r--rts/posix/GetEnv.c44
-rw-r--r--rts/win32/GetEnv.c61
9 files changed, 291 insertions, 1 deletions
diff --git a/rts/GetEnv.h b/rts/GetEnv.h
new file mode 100644
index 0000000000..5e3d0cf184
--- /dev/null
+++ b/rts/GetEnv.h
@@ -0,0 +1,23 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team 2011
+ *
+ * OS-independent interface to the process environment variables
+ *
+ * ---------------------------------------------------------------------------*/
+
+#ifndef GETENV_H
+#define GETENV_H
+
+#include "BeginPrivate.h"
+
+/* Get the process environment vector (same style interface as argc/argv)
+ */
+void getProgEnvv (int *out_envc, char **out_envv[]);
+void freeProgEnvv (int envc, char *envv[]);
+
+/* calls to getProgEnvv must have a corresponding freeProgEnvv */
+
+#include "EndPrivate.h"
+
+#endif /* GETENV_H */
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
index 0dacd61984..c115701d6c 100644
--- a/rts/RtsStartup.c
+++ b/rts/RtsStartup.c
@@ -153,6 +153,9 @@ hs_init(int *argc, char **argv[])
*/
initScheduler();
+ /* Trace some basic information about the process */
+ traceOSProcessInfo();
+
/* initialize the storage manager */
initStorage();
diff --git a/rts/Trace.c b/rts/Trace.c
index faa54d7741..e472c5ade7 100644
--- a/rts/Trace.c
+++ b/rts/Trace.c
@@ -15,11 +15,16 @@
#ifdef TRACING
#include "GetTime.h"
+#include "GetEnv.h"
#include "Stats.h"
#include "eventlog/EventLog.h"
#include "Threads.h"
#include "Printer.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#ifdef DEBUG
// debugging flags, set with +RTS -D<something>
int DEBUG_sched;
@@ -284,6 +289,50 @@ void traceCapsetModify_ (EventTypeNum tag,
}
}
+void traceOSProcessInfo_(void) {
+ if (eventlog_enabled) {
+ postCapsetModifyEvent(EVENT_OSPROCESS_PID,
+ CAPSET_OSPROCESS_DEFAULT,
+ getpid());
+
+#if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS)
+/* Windows has no strong concept of process heirarchy, so no getppid().
+ * In any case, this trace event is mainly useful for tracing programs
+ * that use 'forkProcess' which Windows doesn't support anyway.
+ */
+ postCapsetModifyEvent(EVENT_OSPROCESS_PPID,
+ CAPSET_OSPROCESS_DEFAULT,
+ getppid());
+#endif
+ {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "GHC-%s %s", ProjectVersion, RtsWay);
+ postCapsetStrEvent(EVENT_RTS_IDENTIFIER,
+ CAPSET_OSPROCESS_DEFAULT,
+ buf);
+ }
+ {
+ int argc = 0; char **argv;
+ getFullProgArgv(&argc, &argv);
+ if (argc != 0) {
+ postCapsetVecEvent(EVENT_PROGRAM_ARGS,
+ CAPSET_OSPROCESS_DEFAULT,
+ argc, argv);
+ }
+ }
+ {
+ int envc = 0; char **envv;
+ getProgEnvv(&envc, &envv);
+ if (envc != 0) {
+ postCapsetVecEvent(EVENT_PROGRAM_ENV,
+ CAPSET_OSPROCESS_DEFAULT,
+ envc, envv);
+ }
+ freeProgEnvv(envc, envv);
+ }
+ }
+}
+
void traceEvent_ (Capability *cap, EventTypeNum tag)
{
#ifdef DEBUG
diff --git a/rts/Trace.h b/rts/Trace.h
index f253280b26..1544971077 100644
--- a/rts/Trace.h
+++ b/rts/Trace.h
@@ -182,6 +182,8 @@ void traceCapsetModify_ (EventTypeNum tag,
CapsetID capset,
StgWord32 other);
+void traceOSProcessInfo_ (void);
+
#else /* !TRACING */
#define traceSchedEvent(cap, tag, tso, other) /* nothing */
@@ -194,6 +196,7 @@ void traceCapsetModify_ (EventTypeNum tag,
#define traceThreadStatus(class, tso) /* nothing */
#define traceEventStartup_(n_caps) /* nothing */
#define traceCapsetModify_(tag, capset, other) /* nothing */
+#define traceOSProcessInfo_() /* nothing */
#endif /* TRACING */
@@ -469,6 +472,13 @@ INLINE_HEADER void traceCapsetRemoveCap(CapsetID capset STG_UNUSED,
dtraceCapsetRemoveCap(capset, capno);
}
+INLINE_HEADER void traceOSProcessInfo(void)
+{
+ traceOSProcessInfo_();
+ /* Note: no DTrace equivalent because all this OS process info
+ * is available to DTrace directly */
+}
+
#include "EndPrivate.h"
#endif /* TRACE_H */
diff --git a/rts/eventlog/EventLog.c b/rts/eventlog/EventLog.c
index b5c2ef63bb..abfb4eb4d9 100644
--- a/rts/eventlog/EventLog.c
+++ b/rts/eventlog/EventLog.c
@@ -79,7 +79,12 @@ char *EventDesc[] = {
[EVENT_CAPSET_CREATE] = "Create capability set",
[EVENT_CAPSET_DELETE] = "Delete capability set",
[EVENT_CAPSET_ASSIGN_CAP] = "Add capability to capability set",
- [EVENT_CAPSET_REMOVE_CAP] = "Remove capability from capability set"
+ [EVENT_CAPSET_REMOVE_CAP] = "Remove capability from capability set",
+ [EVENT_RTS_IDENTIFIER] = "RTS name and version",
+ [EVENT_PROGRAM_ARGS] = "Program arguments",
+ [EVENT_PROGRAM_ENV] = "Program environment variables",
+ [EVENT_OSPROCESS_PID] = "Process ID",
+ [EVENT_OSPROCESS_PPID] = "Parent process ID"
};
// Event type.
@@ -284,6 +289,12 @@ initEventLogging(void)
sizeof(EventCapsetID) + sizeof(EventCapNo);
break;
+ case EVENT_OSPROCESS_PID: // (cap, pid)
+ case EVENT_OSPROCESS_PPID:
+ eventTypes[t].size =
+ sizeof(EventCapsetID) + sizeof(StgWord32);
+ break;
+
case EVENT_SHUTDOWN: // (cap)
case EVENT_REQUEST_SEQ_GC: // (cap)
case EVENT_REQUEST_PAR_GC: // (cap)
@@ -297,6 +308,9 @@ initEventLogging(void)
case EVENT_LOG_MSG: // (msg)
case EVENT_USER_MSG: // (msg)
+ case EVENT_RTS_IDENTIFIER: // (capset, str)
+ case EVENT_PROGRAM_ARGS: // (capset, strvec)
+ case EVENT_PROGRAM_ENV: // (capset, strvec)
eventTypes[t].size = 0xffff;
break;
@@ -496,6 +510,12 @@ void postCapsetModifyEvent (EventTypeNum tag,
postCapNo(&eventBuf, other /* capno */);
break;
}
+ case EVENT_OSPROCESS_PID: // (capset, pid)
+ case EVENT_OSPROCESS_PPID: // (capset, parent_pid)
+ {
+ postWord32(&eventBuf, other);
+ break;
+ }
default:
barf("postCapsetModifyEvent: unknown event tag %d", tag);
}
@@ -503,6 +523,70 @@ void postCapsetModifyEvent (EventTypeNum tag,
RELEASE_LOCK(&eventBufMutex);
}
+void postCapsetStrEvent (EventTypeNum tag,
+ EventCapsetID capset,
+ char *msg)
+{
+ int strsize = strlen(msg);
+ int size = strsize + sizeof(EventCapsetID)
+
+ ACQUIRE_LOCK(&eventBufMutex);
+
+ if (!hasRoomForVariableEvent(&eventBuf, size)){
+ printAndClearEventBuf(&eventBuf);
+
+ if (!hasRoomForVariableEvent(&eventBuf, size)){
+ // Event size exceeds buffer size, bail out:
+ RELEASE_LOCK(&eventBufMutex);
+ return;
+ }
+ }
+
+ postEventHeader(&eventBuf, tag);
+ postPayloadSize(&eventBuf, size);
+ postCapsetID(&eventBuf, capset);
+
+ postBuf(&eventBuf, (StgWord8*) msg, strsize);
+
+ RELEASE_LOCK(&eventBufMutex);
+}
+
+void postCapsetVecEvent (EventTypeNum tag,
+ EventCapsetID capset,
+ int argc,
+ char *argv[])
+{
+ int i, size = sizeof(EventCapsetID);
+
+ for (i = 0; i < argc; i++) {
+ // 1 + strlen to account for the trailing \0, used as separator
+ size += 1 + strlen(argv[i]);
+ }
+
+ ACQUIRE_LOCK(&eventBufMutex);
+
+ if (!hasRoomForVariableEvent(&eventBuf, size)){
+ printAndClearEventBuf(&eventBuf);
+
+ if(!hasRoomForVariableEvent(&eventBuf, size)){
+ // Event size exceeds buffer size, bail out:
+ RELEASE_LOCK(&eventBufMutex);
+ return;
+ }
+ }
+
+ postEventHeader(&eventBuf, tag);
+ postPayloadSize(&eventBuf, size);
+ postCapsetID(&eventBuf, capset);
+
+ for( i = 0; i < argc; i++ ) {
+ // again, 1 + to account for \0
+ postBuf(&eventBuf, (StgWord8*) argv[i], 1 + strlen(argv[i]));
+ }
+
+ RELEASE_LOCK(&eventBufMutex);
+}
+
void
postEvent (Capability *cap, EventTypeNum tag)
{
diff --git a/rts/eventlog/EventLog.h b/rts/eventlog/EventLog.h
index 116b532c1f..602ac2c87b 100644
--- a/rts/eventlog/EventLog.h
+++ b/rts/eventlog/EventLog.h
@@ -54,6 +54,21 @@ void postCapsetModifyEvent (EventTypeNum tag,
EventCapsetID capset,
StgWord32 other);
+/*
+ * Post a capability set event with a string payload
+ */
+void postCapsetStrEvent (EventTypeNum tag,
+ EventCapsetID capset,
+ char *msg);
+
+/*
+ * Post a capability set event with several strings payload
+ */
+void postCapsetVecEvent (EventTypeNum tag,
+ EventCapsetID capset,
+ int argc,
+ char *msg[]);
+
#else /* !TRACING */
INLINE_HEADER void postSchedEvent (Capability *cap STG_UNUSED,
diff --git a/rts/ghc.mk b/rts/ghc.mk
index a2369452b7..38ddbc0d46 100644
--- a/rts/ghc.mk
+++ b/rts/ghc.mk
@@ -295,6 +295,7 @@ rts/RtsMain_HC_OPTS += -optc-O0
rts/RtsMessages_CC_OPTS += -DProjectVersion=\"$(ProjectVersion)\"
rts/RtsUtils_CC_OPTS += -DProjectVersion=\"$(ProjectVersion)\"
+rts/Trace_CC_OPTS += -DProjectVersion=\"$(ProjectVersion)\"
#
rts/RtsUtils_CC_OPTS += -DHostPlatform=\"$(HOSTPLATFORM)\"
rts/RtsUtils_CC_OPTS += -DHostArch=\"$(HostArch_CPP)\"
diff --git a/rts/posix/GetEnv.c b/rts/posix/GetEnv.c
new file mode 100644
index 0000000000..4d5c7e248e
--- /dev/null
+++ b/rts/posix/GetEnv.c
@@ -0,0 +1,44 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team 2011
+ *
+ * Access to the process environment variables
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Rts.h"
+#include "GetEnv.h"
+
+#if defined(darwin_HOST_OS)
+
+/* While the "extern char** environ" var does exist on OSX, it is not
+ * available to shared libs. See ghc ticket #2458 and
+ * http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man7/environ.7.html
+ */
+#include <crt_externs.h>
+
+static char** get_environ(void) { return *(_NSGetEnviron()); }
+
+#else
+
+/* On proper unix systems the environ is just a global var.
+ */
+extern char** environ;
+static char** get_environ(void) { return environ; }
+
+#endif
+
+
+void getProgEnvv(int *out_envc, char **out_envv[]) {
+ int envc;
+ char **environ = get_environ();
+
+ for (envc = 0; environ[envc] != NULL; envc++) {};
+
+ *out_envc = envc;
+ *out_envv = environ;
+}
+
+void freeProgEnvv(int envc STG_UNUSED, char *envv[] STG_UNUSED) {
+ /* nothing */
+}
diff --git a/rts/win32/GetEnv.c b/rts/win32/GetEnv.c
new file mode 100644
index 0000000000..b8a43951a9
--- /dev/null
+++ b/rts/win32/GetEnv.c
@@ -0,0 +1,61 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team 2011
+ *
+ * Access to the process environment variables
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Rts.h"
+#include "GetEnv.h"
+
+#include <windows.h>
+
+/* Windows does it differently, though arguably the most sanely.
+ * GetEnvironmentStrings() returns a pointer to a block of
+ * environment vars with a double null terminator:
+ * Var1=Value1\0
+ * Var2=Value2\0
+ * ...
+ * VarN=ValueN\0\0
+ * But because everyone else (ie POSIX) uses a vector of strings, we convert
+ * to that format. Fortunately this is just a matter of making an array of
+ * offsets into the environment block.
+ *
+ * Note that we have to call FreeEnvironmentStrings() at the end.
+ *
+ */
+void getProgEnvv(int *out_envc, char **out_envv[]) {
+ int envc, i;
+ char *env;
+ char *envp;
+ char **envv;
+
+ /* For now, use the 'A'nsi not 'W'ide variant.
+ Note: corresponding Free below must use the same 'A'/'W' variant. */
+ env = GetEnvironmentStringsA();
+
+ envc = 0;
+ for (envp = env; *envp != 0; envp += strlen(envp) + 1) {
+ envc++;
+ }
+
+ envv = stgMallocBytes(sizeof(char*) * (envc+1));
+
+ i = 0;
+ for (envp = env; *envp != NULL; envp += strlen(envp) + 1) {
+ envv[i] = envp;
+ i++;
+ }
+ /* stash whole env in last+1 entry */
+ envv[envc] = env;
+
+ *out_envc = envc;
+ *out_envv = envv;
+}
+
+void freeProgEnvv(int envc, char *envv[]) {
+ /* we stashed the win32 env block in the last+1 entry */
+ FreeEnvironmentStringsA(envv[envc]);
+ stgFree(envv);
+}