diff --git a/configure.ac b/configure.ac
index 48687872a33..3cb8833c09b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -546,7 +546,7 @@ dnl Define kernel version
dnl
-gap_kernel_major_version=5
+gap_kernel_major_version=6
gap_kernel_minor_version=0
AC_SUBST([gap_kernel_major_version])
AC_SUBST([gap_kernel_minor_version])
diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml
index d604b5567c4..21fb4909cbc 100644
--- a/doc/ref/debug.xml
+++ b/doc/ref/debug.xml
@@ -791,6 +791,11 @@ limitations which users should be aware of:
is most obvious when looking at code coverage examples, which will appear
to miss lines of code in files not in a function.
+ -
+ If the current GAP is forked, using the IO_fork function in the IO package,
+ a new profile output file will be created for the new child process, with
+ the process ID of the child attached to the end of the filename.
+
Profiles are transformed into a human-readable form with
diff --git a/src/profile.c b/src/profile.c
index 198be4b8046..d9b22115ff5 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -22,11 +22,14 @@
#include "modules.h"
#include "plist.h"
#include "stringobj.h"
+#include "sysfiles.h"
#include "vars.h"
#include "hpc/thread.h"
#include // for gettimeofday
+#include
+#include
#ifdef HAVE_SYS_RESOURCE_H
#include // definition of 'struct rusage'
#endif
@@ -114,6 +117,8 @@ struct ProfileState
{
// C steam we are writing to
FILE* Stream;
+ // Filename we are writing to
+ char filename[GAP_PATH_MAX];
// Did we use 'popen' to open the stream (matters when closing)
int StreamWasPopened;
// Are we currently outputting repeats (false=code coverage)
@@ -337,6 +342,26 @@ static void fcloseMaybeCompressed(struct ProfileState* ps)
ps->Stream = 0;
}
+// When a child is forked off, we force profile information to be stored
+// in a new file for the child, to avoid corruption
+void InformProfilingThatThisIsAForkedGAP(void)
+{
+ HashLock(&profileState);
+ if (profileState_Active) {
+ char filenamecpy[GAP_PATH_MAX + 20];
+ if (endsWithgz(profileState.filename)) {
+ snprintf(filenamecpy, sizeof(filenamecpy), "%s.%d.gz",
+ profileState.filename, getpid());
+ }
+ else {
+ snprintf(filenamecpy, sizeof(filenamecpy), "%s.%d",
+ profileState.filename, getpid());
+ }
+ fcloseMaybeCompressed(&profileState);
+ fopenMaybeCompressed(filenamecpy, &profileState);
+ }
+}
+
static inline Int8 CPUmicroseconds(void)
{
#ifdef HAVE_GETRUSAGE
@@ -576,6 +601,8 @@ void enableAtStartup(char * filename, Int repeats, TickMethod tickMethod)
exit(1);
}
+ strlcpy(profileState.filename, filename, GAP_PATH_MAX);
+
ActivateHooks(&profileHooks);
profileState_Active = 1;
@@ -706,6 +733,8 @@ Obj FuncACTIVATE_PROFILING(Obj self,
fopenMaybeCompressed(CONST_CSTR_STRING(filename), &profileState);
+ strlcpy(profileState.filename, CONST_CSTR_STRING(filename), GAP_PATH_MAX);
+
if(profileState.Stream == 0) {
HashUnlock(&profileState);
return Fail;
diff --git a/src/profile.h b/src/profile.h
index ddfd79ba66b..908938be204 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -19,6 +19,11 @@
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/
+// When a child is forked off, we force profile information to be stored
+// in a new file for the child, to avoid corruption.
+// This function is for use by the IO package
+void InformProfilingThatThisIsAForkedGAP(void);
+
/****************************************************************************
**