Use different .so names in a debug context
Bug: 37670543
Bug: 36006390
Bug: 37679566
Bug: 37636434
In debug context, a script is forced to be recompiled every time it
is initialized.
To avoid the same .so file being written to by another thread,
while it is being loaded and used by one thread, do not save the .so
file. Delete it right after loading it.
Test: RefocusTest and RSTest (including ScriptGroup2 tests) with
debug.rs.debug set to 1 and CTS on Angler
Change-Id: If63e3d21e3d9abd007a66e0ec79c9e6f1c9f13a0
diff --git a/cpu_ref/rsCpuExecutable.cpp b/cpu_ref/rsCpuExecutable.cpp
index a79f671..83ef757 100644
--- a/cpu_ref/rsCpuExecutable.cpp
+++ b/cpu_ref/rsCpuExecutable.cpp
@@ -60,7 +60,8 @@
}
static std::string findSharedObjectName(const char *cacheDir,
- const char *resName) {
+ const char *resName,
+ const bool reuse = true) {
std::string scriptSOName(cacheDir);
#if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__)
size_t cutPos = scriptSOName.rfind("cache");
@@ -74,6 +75,20 @@
scriptSOName.append("/librs.");
#endif // RS_COMPATIBILITY_LIB
scriptSOName.append(resName);
+ if (!reuse) {
+ // If the generated shared library is not reused, e.g., with a debug
+ // context or forced by a system property, multiple threads may read
+ // and write the shared library at the same time. To avoid the race
+ // on the generated shared library, delete it before finishing script
+ // initialization. To avoid deleting a file generated by a regular
+ // context, use a special suffix here.
+ // Because the script initialization is guarded by a lock from the Java
+ // API, it is safe to name this file with a consistent name and suffix
+ // and delete it after loading. The same lock has also prevented write-
+ // write races on the .so during script initialization even if reuse is
+ // true.
+ scriptSOName.append("#delete_after_load");
+ }
scriptSOName.append(".so");
return scriptSOName;
@@ -88,8 +103,13 @@
bool SharedLibraryUtils::createSharedLibrary(const char *driverName,
const char *cacheDir,
- const char *resName) {
- std::string sharedLibName = findSharedObjectName(cacheDir, resName);
+ const char *resName,
+ const bool reuse,
+ std::string *fullPath) {
+ std::string sharedLibName = findSharedObjectName(cacheDir, resName, reuse);
+ if (fullPath) {
+ *fullPath = sharedLibName;
+ }
std::string objFileName = cacheDir;
objFileName.append("/");
objFileName.append(resName);
@@ -125,6 +145,21 @@
const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
+void* SharedLibraryUtils::loadAndDeleteSharedLibrary(const char *fullPath) {
+ void *loaded = dlopen(fullPath, RTLD_NOW | RTLD_LOCAL);
+ if (loaded == nullptr) {
+ ALOGE("Unable to open shared library (%s): %s", fullPath, dlerror());
+ return nullptr;
+ }
+
+ int r = unlink(fullPath);
+ if (r != 0) {
+ ALOGE("Could not unlink copy %s", fullPath);
+ return nullptr;
+ }
+ return loaded;
+}
+
void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir,
const char *resName,
const char *nativeLibDir,
diff --git a/cpu_ref/rsCpuExecutable.h b/cpu_ref/rsCpuExecutable.h
index ee58e37..82cf774 100644
--- a/cpu_ref/rsCpuExecutable.h
+++ b/cpu_ref/rsCpuExecutable.h
@@ -31,9 +31,14 @@
class SharedLibraryUtils {
public:
#ifndef RS_COMPATIBILITY_LIB
+ // Creates a shared library in cacheDir for the bitcode named resName.
+ // If reuse is false and SOPath is not nullptr, saves the filename
+ // used for the shared library in SOPath.
static bool createSharedLibrary(const char* driverName,
const char* cacheDir,
- const char* resName);
+ const char* resName,
+ const bool reuse = true,
+ std::string *SOPath = nullptr);
#endif
// Load the shared library referred to by cacheDir and resName. If we have
@@ -48,6 +53,13 @@
const char *nativeLibDir = nullptr,
bool *alreadyLoaded = nullptr);
+ // Load the shared library referred to by fullPath, and delete it right
+ // after loading it. Files loaded by this function are only used once, e.g.,
+ // shared libraries generated for scripts in a debug context. Deleting them
+ // is OK in this case since the shared libraries have already been dlopened.
+ // Deletion is also required because such files are not intended for reuse.
+ static void* loadAndDeleteSharedLibrary(const char *fullPath);
+
// Create a len length string containing random characters from [A-Za-z0-9].
static std::string getRandomString(size_t len);
diff --git a/cpu_ref/rsCpuScript.cpp b/cpu_ref/rsCpuScript.cpp
index 545e92f..dec9ab2 100644
--- a/cpu_ref/rsCpuScript.cpp
+++ b/cpu_ref/rsCpuScript.cpp
@@ -57,24 +57,6 @@
#ifndef RS_COMPATIBILITY_LIB
-static bool is_force_recompile() {
- char buf[PROP_VALUE_MAX];
-
- // Re-compile if floating point precision has been overridden.
- android::renderscript::property_get("debug.rs.precision", buf, "");
- if (buf[0] != '\0') {
- return true;
- }
-
- // Re-compile if debug.rs.forcerecompile is set.
- android::renderscript::property_get("debug.rs.forcerecompile", buf, "0");
- if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
- return true;
- } else {
- return false;
- }
-}
-
static void setCompileArguments(std::vector<const char*>* args,
const std::string& bcFileName,
const char* cacheDir, const char* resName,
@@ -381,7 +363,8 @@
compileArguments.push_back(checksumStr.c_str());
compileArguments.push_back(nullptr);
- if (!is_force_recompile() && !useRSDebugContext) {
+ const bool reuse = !is_force_recompile() && !useRSDebugContext;
+ if (reuse) {
mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
// Read RS info from the shared object to detect checksum mismatch
@@ -391,8 +374,8 @@
}
}
- // If we can't, it's either not there or out of date. We compile the bit code and try loading
- // again.
+ // If reuse is desired and we can't, it's either not there or out of date.
+ // We compile the bit code and try loading again.
if (mScriptSO == nullptr) {
if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize,
compileArguments))
@@ -402,14 +385,21 @@
return false;
}
- if (!SharedLibraryUtils::createSharedLibrary(mCtx->getContext()->getDriverName(),
- cacheDir, resName)) {
+ std::string SOPath;
+
+ if (!SharedLibraryUtils::createSharedLibrary(
+ mCtx->getContext()->getDriverName(), cacheDir, resName, reuse,
+ &SOPath)) {
ALOGE("Linker: Failed to link object file '%s'", resName);
mCtx->unlockMutex();
return false;
}
- mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
+ if (reuse) {
+ mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
+ } else {
+ mScriptSO = SharedLibraryUtils::loadAndDeleteSharedLibrary(SOPath.c_str());
+ }
if (mScriptSO == nullptr) {
ALOGE("Unable to load '%s'", resName);
mCtx->unlockMutex();
diff --git a/cpu_ref/rsCpuScript.h b/cpu_ref/rsCpuScript.h
index 1814d5f..dc96f8b 100644
--- a/cpu_ref/rsCpuScript.h
+++ b/cpu_ref/rsCpuScript.h
@@ -171,4 +171,26 @@
} // namespace android
+namespace {
+
+inline bool is_force_recompile() {
+ char buf[PROP_VALUE_MAX];
+
+ // Re-compile if floating point precision has been overridden.
+ android::renderscript::property_get("debug.rs.precision", buf, "");
+ if (buf[0] != '\0') {
+ return true;
+ }
+
+ // Re-compile if debug.rs.forcerecompile is set.
+ android::renderscript::property_get("debug.rs.forcerecompile", buf, "0");
+ if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+} // anonymous namespace
+
#endif // RSD_CPU_SCRIPT_H
diff --git a/cpu_ref/rsCpuScriptGroup2.cpp b/cpu_ref/rsCpuScriptGroup2.cpp
index 11393ff..d624e62 100644
--- a/cpu_ref/rsCpuScriptGroup2.cpp
+++ b/cpu_ref/rsCpuScriptGroup2.cpp
@@ -473,8 +473,13 @@
bool alreadyLoaded = false;
std::string cloneName;
- mScriptObj = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName, nullptr,
- &alreadyLoaded);
+ const bool useRSDebugContext =
+ (mCpuRefImpl->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG);
+ const bool reuse = !is_force_recompile() && !useRSDebugContext;
+ if (reuse) {
+ mScriptObj = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName, nullptr,
+ &alreadyLoaded);
+ }
if (mScriptObj != nullptr) {
// A shared library named resName is found in code cache directory
// cacheDir, and loaded with the handle stored in mScriptObj.
@@ -528,8 +533,11 @@
// Create and load the shared lib
//===--------------------------------------------------------------------===//
+ std::string SOPath;
+
if (!SharedLibraryUtils::createSharedLibrary(
- getCpuRefImpl()->getContext()->getDriverName(), cacheDir, resName)) {
+ getCpuRefImpl()->getContext()->getDriverName(), cacheDir, resName,
+ reuse, &SOPath)) {
ALOGE("Failed to link object file '%s'", resName);
unlink(objFilePath.c_str());
return;
@@ -537,7 +545,11 @@
unlink(objFilePath.c_str());
- mScriptObj = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
+ if (reuse) {
+ mScriptObj = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);
+ } else {
+ mScriptObj = SharedLibraryUtils::loadAndDeleteSharedLibrary(SOPath.c_str());
+ }
if (mScriptObj == nullptr) {
ALOGE("Unable to load '%s'", resName);
return;