Introduce InputFile/OutputFile and FileMutex.
FileHandle is replaced with InputFile/OutputFile and FileMutex.
Use InputFile when you want to open a file in read-only.
USe OutputFile when you open a file for writing.
Both of them provide a reliable way to access the files and perform
the I/O operations.
Given a name "foo", FileMutex creates a file named "foo.lock" and
tries to acquire an advisory lock (flock) on this file.
FileHandle, which uses the file it's openning for locking, may corrupt
the file contents when two or more processes are trying to gain the
lock for reading/writing. For example:
Process #2 creates foo
Process #1 opens foo
Process #2 opens foo
Process #2 locks foo (exclusively) (success)
Process #1 locks foo (failed, retry #1)
Process #2 starts writing foo
Process #1 opens and truncates foo (note there’s O_TRUNC in the flag)
Process #2 writes foo continually (foo is corrupted from now on ...)
Process #1 locks foo (failed, retry #2)
...
Process #1 locks foo (reach the max retries and return)
Process #2 gets done on writing foo (foo is corrupted ...)
Process #2 unlocks and closes foo (foo is corrupted)
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index e26be60..ae6352c 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -26,11 +26,13 @@
BCCContext.cpp \
BCCContextImpl.cpp \
Compiler.cpp \
- FileHandle.cpp \
+ FileBase.cpp \
GDBJIT.cpp \
GDBJITRegistrar.cpp \
+ InputFile.cpp \
MCCacheWriter.cpp \
MCCacheReader.cpp \
+ OutputFile.cpp \
RSScript.cpp \
Runtime.c \
RuntimeStub.c \
diff --git a/lib/ExecutionEngine/Compiler.cpp b/lib/ExecutionEngine/Compiler.cpp
index 100f54b..a56c11c 100644
--- a/lib/ExecutionEngine/Compiler.cpp
+++ b/lib/ExecutionEngine/Compiler.cpp
@@ -24,7 +24,6 @@
#endif
#include "DebugHelper.h"
-#include "FileHandle.h"
#include "Runtime.h"
#include "ScriptCompiled.h"
#include "Sha1Helper.h"
diff --git a/lib/ExecutionEngine/File.h b/lib/ExecutionEngine/File.h
new file mode 100644
index 0000000..4b7ad4d
--- /dev/null
+++ b/lib/ExecutionEngine/File.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_EXECUTION_ENGINE_FILE_H
+#define BCC_EXECUTION_ENGINE_FILE_H
+
+#include "FileBase.h"
+
+namespace bcc {
+
+template<enum FileBase::OpenModeEnum OpenMode>
+struct FileAttribute {
+ // The flags to the 2nd argument in ::open().
+ enum { kOpenFlags };
+
+ // Default value of LockMode.
+ enum { kDefaultLockMode };
+};
+
+// FileAttribute for accessing read-only file
+template<>
+struct FileAttribute<FileBase::kReadMode> {
+ enum { kOpenFlags = O_RDONLY };
+ enum { kDefaultLockMode = FileBase::kReadLock };
+};
+
+// FileAttribute for accessing writable file
+template<>
+struct FileAttribute<FileBase::kWriteMode> {
+ enum { kOpenFlags = O_RDWR | O_CREAT | O_TRUNC };
+ enum { kDefaultLockMode = FileBase::kWriteLock };
+};
+
+template<enum FileBase::OpenModeEnum OpenMode>
+class File : public FileBase {
+public:
+ File(const std::string &pFilename, unsigned pFlags)
+ : FileBase(pFilename, FileAttribute<OpenMode>::kOpenFlags, pFlags) { }
+
+ inline bool lock(enum LockModeEnum pMode = static_cast<enum LockModeEnum>(
+ FileAttribute<OpenMode>::kDefaultLockMode),
+ bool pNonblocking = true,
+ unsigned pMaxRetry = FileBase::kDefaultMaxRetryLock,
+ useconds_t pRetryInterval =
+ FileBase::kDefaultRetryLockInterval) {
+ return FileBase::lock(pMode, pNonblocking, pMaxRetry, pRetryInterval);
+ }
+
+ inline android::FileMap *createMap(off_t pOffset, size_t pLength,
+ bool pIsReadOnly =
+ (OpenMode == FileBase::kReadMode)) {
+ return FileBase::createMap(pOffset, pLength, pIsReadOnly);
+ }
+};
+
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_FILE_H
diff --git a/lib/ExecutionEngine/FileBase.cpp b/lib/ExecutionEngine/FileBase.cpp
new file mode 100644
index 0000000..379406d
--- /dev/null
+++ b/lib/ExecutionEngine/FileBase.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FileBase.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <new>
+
+#include <utils/FileMap.h>
+
+using namespace bcc;
+
+FileBase::FileBase(const std::string &pFilename,
+ unsigned pOpenFlags,
+ unsigned pFlags)
+ : mFD(-1),
+ mError(),
+ mName(pFilename), mOpenFlags(pOpenFlags),
+ mShouldUnlock(false) {
+ // Process pFlags
+#ifdef O_BINARY
+ if (pFlags & kBinary) {
+ mOpenFlags |= O_BINARY;
+ }
+#endif
+
+ // Open the file.
+ open();
+
+ return;
+}
+
+FileBase::~FileBase() {
+ close();
+}
+
+bool FileBase::open() {
+ do {
+ // FIXME: Hard-coded permissions (0644) for newly created file should be
+ // removed and provide a way to let the user configure the value.
+ mFD = ::open(mName.c_str(), mOpenFlags, 0644);
+ if (mFD > 0) {
+ return true;
+ }
+
+ // Some errors occurred ...
+ if (errno != EINTR) {
+ detectError();
+ return false;
+ }
+ } while (true);
+ // unreachable
+}
+
+
+bool FileBase::checkFileIntegrity() {
+ // Check the file integrity by examine whether the inode referred to the mFD
+ // and to the file mName are the same.
+ struct stat fd_stat, file_stat;
+
+ // Get the file status of file descriptor mFD.
+ do {
+ if (::fstat(mFD, &fd_stat) == 0) {
+ break;
+ } else if (errno != EINTR) {
+ detectError();
+ return false;
+ }
+ } while (true);
+
+ // Get the file status of file mName.
+ do {
+ if (::stat(mName.c_str(), &file_stat) == 0) {
+ break;
+ } else if (errno != EINTR) {
+ detectError();
+ return false;
+ }
+ } while (true);
+
+ return ((fd_stat.st_dev == file_stat.st_dev) &&
+ (fd_stat.st_ino == file_stat.st_ino));
+}
+
+void FileBase::detectError() {
+ // Read error from errno.
+ mError.assign(errno, llvm::posix_category());
+}
+
+bool FileBase::lock(enum LockModeEnum pMode,
+ bool pNonblocking,
+ unsigned pMaxRetry,
+ useconds_t pRetryInterval) {
+ int lock_operation;
+ unsigned retry = 0;
+
+ // Check the state.
+ if ((mFD < 0) || hasError()) {
+ return false;
+ }
+
+ // Return immediately if it's already locked.
+ if (mShouldUnlock) {
+ return true;
+ }
+
+ // Determine the lock operation (2nd argument) to the flock().
+ if (pMode == kReadLock) {
+ lock_operation = LOCK_SH;
+ } else if (pMode == kWriteLock) {
+ lock_operation = LOCK_EX;
+ } else {
+ mError.assign(llvm::errc::invalid_argument, llvm::posix_category());
+ return false;
+ }
+
+ if (pNonblocking) {
+ lock_operation |= LOCK_NB;
+ }
+
+ do {
+ if (::flock(mFD, lock_operation) == 0) {
+ mShouldUnlock = true;
+ // Here we got a lock but we need to check whether the mFD still
+ // "represents" the filename (mName) we opened in the contructor. This
+ // check may failed when another process deleted the original file mFD
+ // mapped when we were trying to obtain the lock on the file.
+ if (!checkFileIntegrity()) {
+ if (hasError() || !reopen()) {
+ // Error occurred when check the file integrity or re-open the file.
+ return false;
+ } else {
+ // Wait a while before the next try.
+ ::usleep(pRetryInterval);
+ retry++;
+ continue;
+ }
+ }
+
+ return true;
+ }
+
+ // flock() was not performed successfully. Check the errno to see whether
+ // it's retry-able.
+ if (errno == EINTR) {
+ // flock() was interrupted by delivery of a signal. Restart without
+ // decrement the retry counter.
+ continue;
+ } else if (errno == EWOULDBLOCK) {
+ // The file descriptor was locked by others, wait for a while before next
+ // retry.
+ retry++;
+ ::usleep(pRetryInterval);
+ } else {
+ // There's a fatal error occurs when perform flock(). Return immediately
+ // without further retry.
+ detectError();
+ return false;
+ }
+ } while (retry <= pMaxRetry);
+
+ return false;
+}
+
+void FileBase::unlock() {
+ if (mFD < 0) {
+ return;
+ }
+
+ do {
+ if (::flock(mFD, LOCK_UN) == 0) {
+ mShouldUnlock = false;
+ return;
+ }
+ } while (errno == EINTR);
+
+ detectError();
+ return;
+}
+
+android::FileMap *FileBase::createMap(off_t pOffset, size_t pLength,
+ bool pIsReadOnly) {
+ if (mFD < 0 || hasError()) {
+ return NULL;
+ }
+
+ android::FileMap *map = new (std::nothrow) android::FileMap();
+ if (map == NULL) {
+ mError.assign(llvm::errc::not_enough_memory, llvm::system_category());
+ return NULL;
+ }
+
+ if (!map->create(NULL, mFD, pOffset, pLength, pIsReadOnly)) {
+ detectError();
+ map->release();
+ return NULL;
+ }
+
+ return map;
+}
+
+size_t FileBase::getSize() {
+ if (mFD < 0 || hasError()) {
+ return static_cast<size_t>(-1);
+ }
+
+ struct stat file_stat;
+ do {
+ if (::fstat(mFD, &file_stat) == 0) {
+ break;
+ } else if (errno != EINTR) {
+ detectError();
+ return static_cast<size_t>(-1);
+ }
+ } while (true);
+
+ return file_stat.st_size;
+}
+
+off_t FileBase::seek(off_t pOffset) {
+ if ((mFD < 0) || hasError()) {
+ return static_cast<off_t>(-1);
+ }
+
+ do {
+ off_t result = ::lseek(mFD, pOffset, SEEK_SET);
+ if (result == pOffset) {
+ return result;
+ }
+ } while (errno == EINTR);
+
+ detectError();
+ return static_cast<off_t>(-1);
+}
+
+off_t FileBase::tell() {
+ if ((mFD < 0) || hasError()) {
+ return static_cast<off_t>(-1);
+ }
+
+ do {
+ off_t result = ::lseek(mFD, 0, SEEK_CUR);
+ if (result != static_cast<off_t>(-1)) {
+ return result;
+ }
+ } while (errno == EINTR);
+
+ detectError();
+ return static_cast<off_t>(-1);
+}
+
+void FileBase::close() {
+ if (mShouldUnlock) {
+ unlock();
+ mShouldUnlock = false;
+ }
+ if (mFD > 0) {
+ ::close(mFD);
+ mFD = -1;
+ }
+ return;
+}
diff --git a/lib/ExecutionEngine/FileBase.h b/lib/ExecutionEngine/FileBase.h
new file mode 100644
index 0000000..62d6504
--- /dev/null
+++ b/lib/ExecutionEngine/FileBase.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_EXECUTION_ENGINE_FILE_BASE_H
+#define BCC_EXECUTION_ENGINE_FILE_BASE_H
+
+#include <fcntl.h>
+
+#include <string>
+
+#include <llvm/Support/system_error.h>
+
+namespace android {
+ class FileMap;
+}
+
+namespace bcc {
+
+class FileBase {
+public:
+ enum OpenModeEnum {
+ kReadMode = 1 << 0,
+ kWriteMode = 1 << 1,
+ kReadWriteMode = (kReadMode | kWriteMode),
+ };
+
+ enum FlagEnum {
+ // The openning file is a binary file.
+ kBinary = 1 << 0,
+ };
+
+ enum LockModeEnum {
+ // The shared resource behind the Stream locked in ReadLock mode can be
+ // locked by other processes at the same time.
+ kReadLock,
+
+ // The shared resource behind the Stream locked in WriteLock mode can only
+ // be locked by one process. It's exclusive. That is, the shared resource
+ // cannot have both ReadLock and WriteLock simultaneously.
+ kWriteLock
+ };
+
+ // Default configuration to the lock().
+ enum {
+ kDefaultMaxRetryLock = 4,
+ kDefaultRetryLockInterval = 200000UL,
+ };
+
+protected:
+ // Grant direct access of the internal file descriptor to the sub-class and
+ // error message such that they can implement their own I/O functionality.
+ int mFD;
+
+ llvm::error_code mError;
+
+private:
+ std::string mName;
+
+ // The 2nd argument to the POSIX open().
+ unsigned mOpenFlags;
+
+ // True true if we should call unlock() in destructor.
+ bool mShouldUnlock;
+
+ // Open mName with flag mOpenFlags (using POSIX open().)
+ bool open();
+
+ // Return true if mFD is the corresponded file descriptor to the file named
+ // mName on the filesystem. This check may returns failed, for example,
+ // someone re-create the file with the same name after we openning the file.
+ bool checkFileIntegrity();
+
+ inline bool reopen() {
+ // Don't need to check the object state since this is a private method.
+ close();
+ return open();
+ }
+
+private:
+ FileBase(FileBase &); // Do not implement.
+ void operator=(const FileBase &); // Do not implement.
+
+protected:
+ // pOpenFlags is the 2nd argument to the POSIX open(). pFlags are the flags to
+ // FileBase. It's a bit set composed by the value defined in
+ // FileBase::FlagEnum.
+ FileBase(const std::string &pFilename, unsigned pOpenFlags, unsigned pFlags);
+
+ void detectError();
+
+public:
+ // Lock the file descriptor in given pMode. If pNonblocking is true, the lock
+ // request issued will return immediately when the shared resource is locked.
+ // In this case, it retries pMaxRetry times, each wait pRetryInterval (in
+ // usecs) before the previous retry getting done.
+ //
+ // Only file is allowed to use this API.
+ bool lock(enum LockModeEnum pMode, bool pNonblocking = true,
+ unsigned pMaxRetry = kDefaultMaxRetryLock,
+ useconds_t pRetryInterval = kDefaultRetryLockInterval);
+
+ void unlock();
+
+ // Map the file content to the memory.
+ //
+ // One who gets non-null android::FileMap returned from this API is resposible
+ // for destroying it after the use.
+ android::FileMap *createMap(off_t pOffset, size_t pLength, bool pIsReadOnly);
+
+ size_t getSize();
+
+ off_t seek(off_t pOffset);
+ off_t tell();
+
+ inline bool hasError() const
+ { return (mError.value() != llvm::errc::success); }
+
+ inline const llvm::error_code &getError() const
+ { return mError; }
+
+ // The return value of llvm::error_code::message() is obtained upon the call
+ // and is passed by value (that is, it's not a member of llvm::error_code.)
+ inline std::string getErrorMessage() const
+ { return mError.message(); }
+
+ inline const std::string &getName() const
+ { return mName; }
+
+ void close();
+
+ virtual ~FileBase();
+};
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_FILE_BASE_H
diff --git a/lib/ExecutionEngine/FileHandle.cpp b/lib/ExecutionEngine/FileHandle.cpp
deleted file mode 100644
index c659fb5..0000000
--- a/lib/ExecutionEngine/FileHandle.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "FileHandle.h"
-
-#include "DebugHelper.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string.h>
-
-namespace bcc {
-
-int FileHandle::open(char const *filename, OpenMode::ModeType mode) {
- static int const open_flags[2] = {
- O_RDONLY,
- O_RDWR | O_CREAT | O_TRUNC,
- };
-
- static int const lock_flags[2] = { LOCK_SH, LOCK_EX };
-
- static char const *const open_mode_str[2] = { "read", "write" };
-
- static size_t const RETRY_MAX = 4;
-
- static useconds_t const RETRY_USEC = 200000UL;
-
- for (size_t i = 0; i < RETRY_MAX; ++i) {
- // Try to open the file
- mFD = ::open(filename, open_flags[mode], 0644);
-
- if (mFD < 0) {
- if (errno == EINTR) {
- // Interrupt occurs while opening the file. Retry.
- continue;
- }
-
- ALOGW("Unable to open %s in %s mode. (reason: %s)\n",
- filename, open_mode_str[mode], strerror(errno));
-
- return -1;
- }
-
- // Try to lock the file
- if (flock(mFD, lock_flags[mode] | LOCK_NB) < 0) {
- ALOGW("Unable to acquire the lock immediately, block and wait now ...\n");
-
- if (flock(mFD, lock_flags[mode]) < 0) {
- ALOGE("Unable to acquire the lock. Retry ...\n");
-
- ::close(mFD);
- mFD = -1;
-
- usleep(RETRY_USEC);
- continue;
- }
- }
-
- // Note: From now on, the object is correctly initialized. We have to
- // use this->close() to close the file now.
-
- // Check rather we have locked the correct file or not
- struct stat sfd, sfname;
-
- if (fstat(mFD, &sfd) == -1 || stat(filename, &sfname) == -1 ||
- sfd.st_dev != sfname.st_dev || sfd.st_ino != sfname.st_ino) {
- // The file we locked is different from the given path. This may
- // occur when someone changes the file node before we lock the file.
- // Just close the file, and retry after sleeping.
-
- this->close();
- usleep(RETRY_USEC);
- continue;
- }
-
- // Good, we have open and lock the file correctly.
- ALOGV("File opened. fd=%d\n", mFD);
- return mFD;
- }
-
- ALOGW("Unable to open %s in %s mode.\n", filename, open_mode_str[mode]);
- return -1;
-}
-
-
-void FileHandle::close() {
- if (mFD >= 0) {
- flock(mFD, LOCK_UN);
- ::close(mFD);
- ALOGV("File closed. fd=%d\n", mFD);
- mFD = -1;
- }
-}
-
-
-ssize_t FileHandle::read(char *buf, size_t count) {
- if (mFD < 0) {
- return -1;
- }
-
- while (true) {
- ssize_t nread = ::read(mFD, static_cast<void *>(buf), count);
-
- if (nread >= 0) {
- return nread;
- }
-
- if (errno != EAGAIN && errno != EINTR) {
- // If the errno is EAGAIN or EINTR, then we try to read again.
- // Otherwise, consider this is a failure. And returns zero.
- return -1;
- }
- }
-
- // Unreachable
- return -1;
-}
-
-
-ssize_t FileHandle::write(char const *buf, size_t count) {
- if (mFD < 0) {
- return -1;
- }
-
- ssize_t written = 0;
-
- while (count > 0) {
- ssize_t nwrite = ::write(mFD, static_cast<void const *>(buf), count);
-
- if (nwrite < 0) {
- if (errno != EAGAIN && errno != EINTR) {
- return written;
- }
-
- continue;
- }
-
- written += nwrite;
- count -= (size_t)nwrite;
- buf += (size_t)nwrite;
- }
-
- return written;
-}
-
-
-off_t FileHandle::seek(off_t offset, int whence) {
- return (mFD < 0) ? -1 : lseek(mFD, offset, whence);
-}
-
-
-void FileHandle::truncate() {
- if (mFD >= 0) {
- if (ftruncate(mFD, 0) != 0) {
- ALOGE("Unable to truncate the file.\n");
- }
- }
-}
-
-
-} // namespace bcc
diff --git a/lib/ExecutionEngine/FileHandle.h b/lib/ExecutionEngine/FileHandle.h
deleted file mode 100644
index 02dbe31..0000000
--- a/lib/ExecutionEngine/FileHandle.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef BCC_FILEHANDLE_H
-#define BCC_FILEHANDLE_H
-
-#include <sys/types.h>
-
-#include <stddef.h>
-#include <stdint.h>
-
-namespace bcc {
- namespace OpenMode {
- enum ModeType {
- Read = 0,
- Write = 1,
- };
- }
-
- class FileHandle {
- private:
- int mFD;
-
- public:
- FileHandle() : mFD(-1) {
- }
-
- ~FileHandle() {
- if (mFD >= 0) {
- close();
- }
- }
-
- int open(char const *filename, OpenMode::ModeType mode);
-
- void close();
-
- int getFD() {
- // Note: This function is designed not being qualified by const.
- // Because once the file descriptor is given, the user can do every
- // thing on file descriptor.
-
- return mFD;
- }
-
- off_t seek(off_t offset, int whence);
-
- ssize_t read(char *buf, size_t count);
-
- ssize_t write(char const *buf, size_t count);
-
- void truncate();
-
- };
-
-} // namespace bcc
-
-#endif // BCC_FILEHANDLE_H
diff --git a/lib/ExecutionEngine/FileMutex.h b/lib/ExecutionEngine/FileMutex.h
new file mode 100644
index 0000000..85c0e84
--- /dev/null
+++ b/lib/ExecutionEngine/FileMutex.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_EXECUTION_ENGINE_FILE_MUTEX_H
+#define BCC_EXECUTION_ENGINE_FILE_MUTEX_H
+
+#include <string>
+
+#include "FileBase.h"
+
+namespace bcc {
+
+template<enum FileBase::LockModeEnum LockMode>
+class FileMutex : public FileBase {
+public:
+ FileMutex(const std::string &pFileToLock)
+ : FileBase(pFileToLock + ".lock", O_RDONLY | O_CREAT, 0) { }
+
+ // Provide a lock() interface filled with default configuration.
+ inline bool lock(bool pNonblocking = true,
+ unsigned pMaxRetry = FileBase::kDefaultMaxRetryLock,
+ useconds_t pRetryInterval =
+ FileBase::kDefaultRetryLockInterval) {
+ return FileBase::lock(LockMode, pNonblocking, pMaxRetry, pRetryInterval);
+ }
+};
+
+} // namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_FILE_MUTEX_H
diff --git a/lib/ExecutionEngine/InputFile.cpp b/lib/ExecutionEngine/InputFile.cpp
new file mode 100644
index 0000000..6a60998
--- /dev/null
+++ b/lib/ExecutionEngine/InputFile.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputFile.h"
+
+#include "DebugHelper.h"
+
+using namespace bcc;
+
+InputFile::InputFile(const std::string &pFilename, unsigned pFlags)
+ : super(pFilename, pFlags) { }
+
+ssize_t InputFile::read(void *pBuf, size_t count) {
+ if ((mFD < 0) || hasError()) {
+ return -1;
+ }
+
+ if ((count <= 0) || (pBuf == NULL)) {
+ // Keep safe and issue a warning.
+ ALOGW("InputFile::read: count = %u, buffer = %p", count, pBuf);
+ return 0;
+ }
+
+ while (count > 0) {
+ ssize_t read_size = ::read(mFD, pBuf, count);
+
+ if (read_size >= 0) {
+ return read_size;
+ } else if ((errno == EAGAIN) || (errno == EINTR)) {
+ // If the errno is EAGAIN or EINTR, then we try to read again.
+ //
+ // Fall-through
+ } else {
+ detectError();
+ return -1;
+ }
+ }
+ // unreachable
+ return 0;
+}
diff --git a/lib/ExecutionEngine/InputFile.h b/lib/ExecutionEngine/InputFile.h
new file mode 100644
index 0000000..a7c22d2
--- /dev/null
+++ b/lib/ExecutionEngine/InputFile.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_EXECUTION_ENGINE_INPUT_FILE_H
+#define BCC_EXECUTION_ENGINE_INPUT_FILE_H
+
+#include "File.h"
+#include "FileBase.h"
+
+namespace bcc {
+
+class InputFile : public File<FileBase::kReadMode> {
+ typedef File<FileBase::kReadMode> super;
+public:
+ InputFile(const std::string &pFilename, unsigned pFlags = 0);
+
+ ssize_t read(void *pBuf, size_t count);
+};
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_INPUT_FILE_H
diff --git a/lib/ExecutionEngine/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
index bf4fe47..0a70ff6 100644
--- a/lib/ExecutionEngine/MCCacheReader.cpp
+++ b/lib/ExecutionEngine/MCCacheReader.cpp
@@ -17,7 +17,7 @@
#include "MCCacheReader.h"
#include "DebugHelper.h"
-#include "FileHandle.h"
+#include "InputFile.h"
#include "ScriptCached.h"
#include "Runtime.h"
@@ -49,8 +49,8 @@
if (mpFuncNameList) { free(mpFuncNameList); }
}
-ScriptCached *MCCacheReader::readCacheFile(FileHandle *objFile,
- FileHandle *infoFile,
+ScriptCached *MCCacheReader::readCacheFile(InputFile &objFile,
+ InputFile &infoFile,
Script *S) {
bool result = checkCacheFile(objFile, infoFile, S)
&& readPragmaList()
@@ -65,16 +65,16 @@
return result ? mpResult.take() : NULL;
}
-bool MCCacheReader::checkCacheFile(FileHandle *objFile,
- FileHandle *infoFile,
- Script *S) {
+bool MCCacheReader::checkCacheFile(InputFile &objFile,
+ InputFile &infoFile,
+ Script *S) {
// Check file handle
- if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
+ if (objFile.hasError() || infoFile.hasError()) {
return false;
}
- mObjFile = objFile;
- mInfoFile = infoFile;
+ mObjFile = &objFile;
+ mInfoFile = &infoFile;
// Allocate ScriptCached object
mpResult.reset(new (nothrow) ScriptCached(S));
@@ -101,7 +101,7 @@
bool MCCacheReader::checkFileSize() {
struct stat stfile;
- if (fstat(mInfoFile->getFD(), &stfile) < 0) {
+ if (::stat(mInfoFile->getName().c_str(), &stfile) < 0) {
ALOGE("Unable to stat cache file.\n");
return false;
}
@@ -118,7 +118,7 @@
bool MCCacheReader::readHeader() {
- if (mInfoFile->seek(0, SEEK_SET) != 0) {
+ if (mInfoFile->seek(0) != 0) {
ALOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
return false;
}
@@ -226,7 +226,7 @@
/* We have to ensure that some one will deallocate NAME##_raw */ \
AUTO_MANAGED_HOLDER = NAME##_raw; \
\
- if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \
+ if (mInfoFile->seek(mpHeader->NAME##_offset) == -1) { \
ALOGE("Unable to seek to " #NAME " section\n"); \
return false; \
} \
diff --git a/lib/ExecutionEngine/MCCacheReader.h b/lib/ExecutionEngine/MCCacheReader.h
index df4aca3..972f0c8 100644
--- a/lib/ExecutionEngine/MCCacheReader.h
+++ b/lib/ExecutionEngine/MCCacheReader.h
@@ -31,12 +31,12 @@
struct MCO_Header;
namespace bcc {
- class FileHandle;
class Script;
+ class InputFile;
class MCCacheReader {
private:
- FileHandle *mObjFile, *mInfoFile;
+ InputFile *mObjFile, *mInfoFile;
off_t mInfoFileSize;
MCO_Header *mpHeader;
@@ -75,8 +75,8 @@
std::make_pair((uint32_t)resType, sha1)));
}
- ScriptCached *readCacheFile(FileHandle *objFile, FileHandle *infoFile, Script *s);
- bool checkCacheFile(FileHandle *objFile, FileHandle *infoFile, Script *S);
+ ScriptCached *readCacheFile(InputFile &objFile, InputFile &infoFile, Script *s);
+ bool checkCacheFile(InputFile &objFile, InputFile &infoFile, Script *S);
bool isContextSlotNotAvail() const {
return mIsContextSlotNotAvail;
diff --git a/lib/ExecutionEngine/MCCacheWriter.cpp b/lib/ExecutionEngine/MCCacheWriter.cpp
index b113ad9..7809234 100644
--- a/lib/ExecutionEngine/MCCacheWriter.cpp
+++ b/lib/ExecutionEngine/MCCacheWriter.cpp
@@ -17,7 +17,7 @@
#include "MCCacheWriter.h"
#include "DebugHelper.h"
-#include "FileHandle.h"
+#include "OutputFile.h"
#include "RSScript.h"
#include <map>
@@ -47,14 +47,14 @@
#undef CHECK_AND_FREE
}
-bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
+bool MCCacheWriter::writeCacheFile(OutputFile &objFile, OutputFile &infoFile,
RSScript *S, uint32_t libRS_threadable) {
- if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
+ if (objFile.hasError() || infoFile.hasError()) {
return false;
}
- mObjFile = objFile;
- mInfoFile = infoFile;
+ mObjFile = &objFile;
+ mInfoFile = &infoFile;
mpOwner = S;
bool result = prepareHeader(libRS_threadable)
@@ -343,14 +343,14 @@
bool MCCacheWriter::writeAll() {
#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
do { \
- if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) { \
- ALOGE("Unable to seek to " #NAME " section for writing.\n"); \
+ if (mInfoFile->seek(OFFSET) == -1) { \
+ ALOGE("Unable to seek to " #NAME " section for writing.\n"); \
return false; \
} \
\
if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
static_cast<ssize_t>(SIZE)) { \
- ALOGE("Unable to write " #NAME " section to cache file.\n"); \
+ ALOGE("Unable to write " #NAME " section to cache file.\n"); \
return false; \
} \
} while (0)
diff --git a/lib/ExecutionEngine/MCCacheWriter.h b/lib/ExecutionEngine/MCCacheWriter.h
index 7fa5cf5..1f462b3 100644
--- a/lib/ExecutionEngine/MCCacheWriter.h
+++ b/lib/ExecutionEngine/MCCacheWriter.h
@@ -19,21 +19,20 @@
#include <bcc/bcc_mccache.h>
-#include "FileHandle.h"
-
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace bcc {
+ class OutputFile;
class RSScript;
class MCCacheWriter {
private:
RSScript *mpOwner;
- FileHandle *mObjFile, *mInfoFile;
+ OutputFile *mObjFile, *mInfoFile;
std::vector<std::pair<char const *, size_t> > mStringPool;
@@ -63,7 +62,7 @@
~MCCacheWriter();
- bool writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
+ bool writeCacheFile(OutputFile &objFile, OutputFile &infoFile,
RSScript *S, uint32_t libRS_threadable);
void addDependency(MCO_ResourceType resType,
diff --git a/lib/ExecutionEngine/OutputFile.cpp b/lib/ExecutionEngine/OutputFile.cpp
new file mode 100644
index 0000000..167b7a0
--- /dev/null
+++ b/lib/ExecutionEngine/OutputFile.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OutputFile.h"
+
+#include <cstdlib>
+
+#include <llvm/Support/raw_ostream.h>
+
+#include "DebugHelper.h"
+
+using namespace bcc;
+
+OutputFile *OutputFile::CreateTemporary(const std::string &pFileTemplate,
+ unsigned pFlags) {
+ char *tmp_filename = NULL;
+ int tmp_fd;
+ OutputFile *result = NULL;
+
+ // Allocate memory to hold the generated unique temporary filename.
+ tmp_filename =
+ new (std::nothrow) char [ pFileTemplate.length() + /* .XXXXXX */7 + 1 ];
+ if (tmp_filename == NULL) {
+ ALOGE("Out of memory when allocates memory for filename %s in "
+ "OutputFile::CreateTemporary()!", pFileTemplate.c_str());
+ return NULL;
+ }
+
+ // Construct filename template for mkstemp().
+ if (pFileTemplate.length() > 0)
+ ::memcpy(tmp_filename, pFileTemplate.c_str(), pFileTemplate.length());
+ ::strncpy(tmp_filename + pFileTemplate.length(), ".XXXXXX", 7);
+
+ // POSIX mkstemp() never returns EINTR.
+ tmp_fd = ::mkstemp(tmp_filename);
+ if (tmp_fd < 0) {
+ llvm::error_code err(errno, llvm::posix_category());
+ ALOGE("Failed to create temporary file using mkstemp() for %s! (%s)",
+ tmp_filename, err.message().c_str());
+ delete [] tmp_filename;
+ return NULL;
+ }
+
+ // Create result OutputFile.
+ result = new (std::nothrow) OutputFile(tmp_filename, pFlags);
+ if (result == NULL) {
+ ALOGE("Out of memory when creates OutputFile for %s!", tmp_filename);
+ // Fall through to the clean-up codes.
+ } else {
+ if (result->hasError()) {
+ ALOGE("Failed to open temporary output file %s! (%s)",
+ result->getName().c_str(), result->getErrorMessage().c_str());
+ delete result;
+ result = NULL;
+ // Fall through to the clean-up codes.
+ }
+ }
+
+ // Clean up.
+ delete [] tmp_filename;
+ ::close(tmp_fd);
+
+ return result;
+}
+
+OutputFile::OutputFile(const std::string &pFilename, unsigned pFlags)
+ : super(pFilename, pFlags) { }
+
+ssize_t OutputFile::write(const void *pBuf, size_t count) {
+ if ((mFD < 0) || hasError()) {
+ return -1;
+ }
+
+ if ((count <= 0) || (pBuf == NULL)) {
+ // Keep safe and issue a warning.
+ ALOGW("OutputFile::write: count = %u, buffer = %p", count, pBuf);
+ return 0;
+ }
+
+ while (count > 0) {
+ ssize_t write_size = ::write(mFD, pBuf, count);
+
+ if (write_size > 0) {
+ return write_size;
+ } else if ((errno == EAGAIN) || (errno == EINTR)) {
+ // If the errno is EAGAIN or EINTR, then we try to write again.
+ //
+ // Fall-through
+ } else {
+ detectError();
+ return -1;
+ }
+ }
+ // unreachable
+ return 0;
+}
+
+void OutputFile::truncate() {
+ if (mFD < 0) {
+ return;
+ }
+
+ do {
+ if (::ftruncate(mFD, 0) == 0) {
+ return;
+ }
+ } while (errno == EINTR);
+ detectError();
+
+ return;
+}
+
+llvm::raw_fd_ostream *OutputFile::dup() {
+ int newfd;
+
+ do {
+ newfd = ::dup(mFD);
+ if (newfd < 0) {
+ if (errno != EINTR) {
+ detectError();
+ return NULL;
+ }
+ // EINTR
+ continue;
+ }
+ // dup() returns ok.
+ break;
+ } while (true);
+
+ llvm::raw_fd_ostream *result =
+ new (std::nothrow) llvm::raw_fd_ostream(newfd, /* shouldClose */true);
+
+ if (result == NULL) {
+ mError.assign(llvm::errc::not_enough_memory, llvm::system_category());
+ }
+
+ return result;
+}
diff --git a/lib/ExecutionEngine/OutputFile.h b/lib/ExecutionEngine/OutputFile.h
new file mode 100644
index 0000000..4de8863
--- /dev/null
+++ b/lib/ExecutionEngine/OutputFile.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_EXECUTION_ENGINE_OUTPUT_FILE_H
+#define BCC_EXECUTION_ENGINE_OUTPUT_FILE_H
+
+#include "File.h"
+#include "FileBase.h"
+
+namespace llvm {
+ class raw_fd_ostream;
+}
+
+namespace bcc {
+
+class OutputFile : public File<FileBase::kWriteMode> {
+ typedef File<FileBase::kWriteMode> super;
+public:
+ // Generate a unique temporary filename from pFileTemplate and open it in
+ // an OutputFile returned. The filename will be pFileTemplate with
+ // a dot ('.') plus six random characters appended. Return NULL on error.
+ static OutputFile *CreateTemporary(const std::string &pFileTemplate,
+ unsigned pFlags);
+
+ OutputFile(const std::string &pFilename, unsigned pFlags = 0);
+
+ ssize_t write(const void *pBuf, size_t count);
+
+ void truncate();
+
+ // This is similar to the system call dup(). It creates a copy of the file
+ // descriptor it contains and wrap it in llvm::raw_fd_ostream object. It
+ // returns a non-NULL object if everything goes well and user should later
+ // use delete operator to destroy it by itself.
+ llvm::raw_fd_ostream *dup();
+};
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_OUTPUT_FILE_H
diff --git a/lib/ExecutionEngine/RSScript.cpp b/lib/ExecutionEngine/RSScript.cpp
index af37ab6..d223eee 100644
--- a/lib/ExecutionEngine/RSScript.cpp
+++ b/lib/ExecutionEngine/RSScript.cpp
@@ -35,8 +35,10 @@
#include "CompilerOption.h"
#include "DebugHelper.h"
-#include "FileHandle.h"
+#include "FileMutex.h"
#include "GDBJITRegistrar.h"
+#include "InputFile.h"
+#include "OutputFile.h"
#include "ScriptCompiled.h"
#include "ScriptCached.h"
#include "Sha1Helper.h"
@@ -99,7 +101,6 @@
return;
}
-
bool RSScript::doReset() {
resetState();
return true;
@@ -133,9 +134,10 @@
return status;
}
- FileHandle objFile;
- if (objFile.open(objPath, OpenMode::Write) < 1) {
- ALOGE("Failed to open %s for write.\n", objPath);
+ OutputFile objFile(objPath);
+ if (objFile.hasError()) {
+ ALOGE("Failed to open %s for write. (%s)", objPath,
+ objFile.getErrorMessage().c_str());
return 1;
}
@@ -218,15 +220,37 @@
std::string objPath = getCachedObjectPath();
std::string infoPath = getCacheInfoPath();
- FileHandle objFile;
- if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
- // Unable to open the executable file in read mode.
+ // Locks for reading object file and info file.
+ FileMutex<FileBase::kReadLock> objFileMutex(objPath);
+ FileMutex<FileBase::kReadLock> infoFileMutex(infoPath);
+
+ // Aquire read lock for object file.
+ if (objFileMutex.hasError() || !objFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
+ objFileMutex.getErrorMessage().c_str());
return 1;
}
- FileHandle infoFile;
- if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) {
- // Unable to open the metadata information file in read mode.
+ // Aquire read lock for info file.
+ if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
+ infoFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
+
+ // Open the object file and info file
+ InputFile objFile(objPath);
+ InputFile infoFile(infoPath);
+
+ if (objFile.hasError()) {
+ ALOGE("Unable to open %s for reading! (%s)", objPath.c_str(),
+ objFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ if (infoFile.hasError()) {
+ ALOGE("Unable to open %s for reading! (%s)", infoPath.c_str(),
+ infoFile.getErrorMessage().c_str());
return 1;
}
@@ -250,10 +274,10 @@
}
if (checkOnly)
- return !reader.checkCacheFile(&objFile, &infoFile, this);
+ return !reader.checkCacheFile(objFile, infoFile, this);
// Read cache file
- ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this);
+ ScriptCached *cached = reader.readCacheFile(objFile, infoFile, this);
if (!cached) {
mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
@@ -318,72 +342,92 @@
// we don't have to cache it.
if (isCacheable()) {
-
std::string objPath = getCachedObjectPath();
std::string infoPath = getCacheInfoPath();
- // Remove the file if it already exists before writing the new file.
- // The old file may still be mapped elsewhere in memory and we do not want
- // to modify its contents. (The same script may be running concurrently in
- // the same process or a different process!)
- ::unlink(objPath.c_str());
- ::unlink(infoPath.c_str());
+ // Locks for writing object file and info file.
+ FileMutex<FileBase::kWriteLock> objFileMutex(objPath);
+ FileMutex<FileBase::kWriteLock> infoFileMutex(infoPath);
- FileHandle objFile;
- FileHandle infoFile;
+ // Aquire write lock for object file.
+ if (objFileMutex.hasError() || !objFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
+ objFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
- if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
- infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
+ // Aquire write lock for info file.
+ if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
+ infoFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
- MCCacheWriter writer;
+ // Open the object file and info file
+ OutputFile objFile(objPath);
+ OutputFile infoFile(infoPath);
+
+ if (objFile.hasError()) {
+ ALOGE("Unable to open %s for writing! (%s)", objPath.c_str(),
+ objFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ if (infoFile.hasError()) {
+ ALOGE("Unable to open %s for writing! (%s)", infoPath.c_str(),
+ infoFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ MCCacheWriter writer;
#ifdef TARGET_BUILD
- // Dependencies
- writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
- writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
+ // Dependencies
+ writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
+ writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
#endif
- for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
- const SourceDependency *source_dep = mSourceDependencies[i];
- writer.addDependency(source_dep->getSourceType(),
- source_dep->getSourceName(),
- source_dep->getSHA1Checksum());
+ for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
+ const SourceDependency *source_dep = mSourceDependencies[i];
+ writer.addDependency(source_dep->getSourceType(),
+ source_dep->getSourceName(),
+ source_dep->getSHA1Checksum());
+ }
+
+
+ // libRS is threadable dirty hack
+ // TODO: This should be removed in the future
+ uint32_t libRS_threadable = 0;
+ if (mpExtSymbolLookupFn) {
+ libRS_threadable =
+ (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
+ "__isThreadable");
+ }
+
+ if (!writer.writeCacheFile(objFile, infoFile, this, libRS_threadable)) {
+ // Erase the file contents.
+ objFile.truncate();
+ infoFile.truncate();
+
+ // Close the file such that we can removed it from the filesystem.
+ objFile.close();
+ infoFile.close();
+
+ if (::unlink(objPath.c_str()) != 0) {
+ ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+ objPath.c_str(), ::strerror(errno));
}
-
- // libRS is threadable dirty hack
- // TODO: This should be removed in the future
- uint32_t libRS_threadable = 0;
- if (mpExtSymbolLookupFn) {
- libRS_threadable =
- (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
- "__isThreadable");
- }
-
- if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
- objFile.truncate();
- objFile.close();
-
- if (unlink(objPath.c_str()) != 0) {
- ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
- objPath.c_str(), strerror(errno));
- }
-
- infoFile.truncate();
- infoFile.close();
-
- if (unlink(infoPath.c_str()) != 0) {
- ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
- infoPath.c_str(), strerror(errno));
- }
+ if (::unlink(infoPath.c_str()) != 0) {
+ ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+ infoPath.c_str(), ::strerror(errno));
}
}
- }
+ } // isCacheable()
return 0;
}
-
char const *RSScript::getCompilerErrorMessage() {
if (mStatus != ScriptStatus::Compiled) {
mErrorCode = BCC_INVALID_OPERATION;
diff --git a/lib/ExecutionEngine/Sha1Helper.cpp b/lib/ExecutionEngine/Sha1Helper.cpp
index 0acd6b8..07a995f 100644
--- a/lib/ExecutionEngine/Sha1Helper.cpp
+++ b/lib/ExecutionEngine/Sha1Helper.cpp
@@ -19,7 +19,7 @@
#include "Config.h"
#include "DebugHelper.h"
-#include "FileHandle.h"
+#include "InputFile.h"
#include <string.h>
@@ -50,10 +50,11 @@
void calcFileSHA1(unsigned char *result, char const *filename) {
android::StopWatch calcFileSHA1Timer("calcFileSHA1 time");
- FileHandle file;
+ InputFile file(filename);
- if (file.open(filename, OpenMode::Read) < 0) {
- ALOGE("Unable to calculate the sha1 checksum of %s\n", filename);
+ if (file.hasError()) {
+ ALOGE("Unable to open the file %s before SHA-1 checksum "
+ "calculation! (%s)", filename, file.getErrorMessage().c_str());
memset(result, '\0', 20);
return;
}
@@ -83,9 +84,10 @@
}
void readSHA1(unsigned char *result, int result_size, char const *filename) {
- FileHandle file;
- if (file.open(filename, OpenMode::Read) < 0) {
- ALOGE("Unable to read binary sha1 file %s\n", filename);
+ InputFile file(filename);
+ if (file.hasError()) {
+ ALOGE("Unable to open the binary sha1 file %s! (%s)", filename,
+ file.getErrorMessage().c_str());
memset(result, '\0', result_size);
return;
}