diff --git a/docs/Manual_Quickstart/Manual_Setup.md b/docs/Manual_Quickstart/Manual_Setup.md
index 1df1b02cd..bce40ec37 100644
--- a/docs/Manual_Quickstart/Manual_Setup.md
+++ b/docs/Manual_Quickstart/Manual_Setup.md
@@ -44,6 +44,8 @@ If you have installed LLVM using the package manager, specifying this var
Note: In case you want to use a specific Version of LLVM, it is possible to specify the `-DUSE_LLVM_VERSION=` flag.
+Note: In case your application uses PThreads, please specify `-DDP_PTHREAD_COMPATIBILITY_MODE=1`. Note, however, that this can influence the runtime of the profiling.
+
Once the configuration process is successfully finished, compile the DiscoPoP libraries using `make`. All created shared objects will be stored in the build directory and can be found inside a folder named `libi/`.
make
diff --git a/rtlib/CMakeLists.txt b/rtlib/CMakeLists.txt
index 4baeee671..ad5737dcc 100644
--- a/rtlib/CMakeLists.txt
+++ b/rtlib/CMakeLists.txt
@@ -26,6 +26,15 @@ set(CMAKE_CXX_FLAGS
add_library(DiscoPoP_RT STATIC
${DiscoPoP_SOURCES})
+
+# forward compiler flags
+if(DEFINED DP_PTHREAD_COMPATIBILITY_MODE)
+ if(NOT ${DP_PTHREAD_COMPATIBILITY_MODE} EQUAL 0)
+ target_compile_definitions(DiscoPoP_RT PUBLIC DP_PTHREAD_COMPATIBILITY_MODE=${DP_PTHREAD_COMPATIBILITY_MODE})
+ endif()
+
+endif()
+
install(TARGETS DiscoPoP_RT ARCHIVE DESTINATION lib)
# compile simple-alias-detection
diff --git a/rtlib/iFunctions.cpp b/rtlib/iFunctions.cpp
index b7dce63a7..d3e7661ad 100755
--- a/rtlib/iFunctions.cpp
+++ b/rtlib/iFunctions.cpp
@@ -32,6 +32,11 @@ using namespace dputil;
#define unpackLIDMetadata_getLoopIteration_1(lid) ((lid >> 40) & 0xFF)
#define unpackLIDMetadata_getLoopIteration_2(lid) ((lid >> 32) & 0xFF)
+// issue a warning if DP_PTHREAD_COMPATIBILITY_MODE is enabled
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
+# warning "DP_PTHREAD_COMPATIBILITY_MODE enabled! This may have negative implications on the profiling time."
+#endif
+
bool DP_DEBUG = false; // debug flag
bool USE_PERFECT = true;
@@ -664,7 +669,11 @@ namespace __dp {
#else
void __dp_read(LID lid, ADDR addr, char *var) {
#endif
+
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
+
if (targetTerminated) {
if (DP_DEBUG) {
cout << "__dp_read() is not executed since target program has returned from main()." << endl;
@@ -736,7 +745,10 @@ namespace __dp {
#else
void __dp_write(LID lid, ADDR addr, char *var) {
#endif
+
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (targetTerminated) {
if (DP_DEBUG) {
cout << "__dp_write() is not executed since target program has returned from main()." << endl;
@@ -808,7 +820,10 @@ namespace __dp {
#else
void __dp_decl(LID lid, ADDR addr, char *var) {
#endif
+
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (targetTerminated) {
if (DP_DEBUG) {
cout << "__dp_write() is not executed since target program has returned from main()." << endl;
@@ -876,7 +891,9 @@ namespace __dp {
}
void __dp_alloca(LID lid, char *var, ADDR startAddr, ADDR endAddr, int64_t numBytes, int64_t numElements) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
int64_t buffer = nextFreeMemoryRegionId;
string allocId = to_string(buffer);
nextFreeMemoryRegionId++;
@@ -898,7 +915,9 @@ namespace __dp {
}
void __dp_new(LID lid, ADDR startAddr, ADDR endAddr, int64_t numBytes){
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
// instrumentation function for new and malloc
int64_t buffer = nextFreeMemoryRegionId;
string allocId = to_string(buffer);
@@ -928,7 +947,9 @@ namespace __dp {
}
void __dp_delete(LID lid, ADDR startAddr){
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
// DO NOT DELETE MEMORY REGIONS AS THEY ARE STILL REQUIRED FOR LOGGING
// TODO more efficient implementation
@@ -948,35 +969,47 @@ namespace __dp {
}
void __dp_report_bb(int32_t bbIndex) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
bbList->insert(bbIndex);
}
void __dp_report_bb_pair(int32_t semaphore, int32_t bbIndex) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (semaphore)
bbList->insert(bbIndex);
}
void __dp_finalize(LID lid) {
- pthread_compatibility_mutex.lock();
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
+ pthread_compatibility_mutex.lock();
+#endif
if (targetTerminated) {
if (DP_DEBUG) {
cout << "__dp_finalize() has been called before. Doing nothing this time to avoid double free." << endl;
}
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
pthread_compatibility_mutex.unlock();
+#endif
return;
}
// release mutex so it can be re-aquired in the called __dp_func_exit
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
pthread_compatibility_mutex.unlock();
+#endif
while (FuncStackLevel >= 0) {
__dp_func_exit(lid, 1);
}
// use lock_guard here, since no other mutex-aquiring function is called
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
// Returning from main or exit from somewhere, clear up everything.
assert(FuncStackLevel == -1 && "Program terminates without clearing function stack!");
@@ -1027,7 +1060,9 @@ namespace __dp {
// hybrid analysis
void __dp_add_bb_deps(char *depStringPtr) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
string depString(depStringPtr);
regex r0("[^\\/]+"), r1("[^=]+"), r2("[^,]+"), r3("[0-9]+:[0-9]+"), r4("(INIT|(R|W)A(R|W)).*");
smatch res0, res1, res2, res3;
@@ -1064,12 +1099,16 @@ namespace __dp {
// End HA
void __dp_call(LID lid) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
lastCallOrInvoke = lid;
}
void __dp_func_entry(LID lid, int32_t isStart) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (!dpInited) {
// This part should be executed only once.
readRuntimeInfo();
@@ -1158,7 +1197,9 @@ namespace __dp {
}
void __dp_func_exit(LID lid, int32_t isExit) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (targetTerminated) {
if (DP_DEBUG) {
cout << "Exiting function LID " << std::dec << decodeLID(lid);
@@ -1215,7 +1256,9 @@ namespace __dp {
}
void __dp_loop_entry(LID lid, int32_t loopID) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (targetTerminated) {
if (DP_DEBUG) {
cout << "__dp_loop_entry() is not executed since target program has returned from main()." << endl;
@@ -1264,7 +1307,9 @@ namespace __dp {
}
void __dp_loop_exit(LID lid, int32_t loopID) {
+#ifdef DP_PTHREAD_COMPATIBILITY_MODE
std::lock_guard guard(pthread_compatibility_mutex);
+#endif
if (targetTerminated) {
if (DP_DEBUG) {
cout << "__dp_loop_exit() is not executed since target program has returned from main()." << endl;