P4 to Git Change 1188177 by kebai@kebai-lnx1 on 2015/09/04 15:51:30

ECR #304775 - Fix build failure on windows

Affected files ...

... //depot/stg/opencl/drivers/opencl/compiler/lib/backends/common/cache.cpp#6 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/backends/common/cache.hpp#7 delete
... //depot/stg/opencl/drivers/opencl/compiler/tools/caching/cache.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/compiler/tools/caching/cache.hpp#2 edit


[ROCm/clr commit: 1fc05cc76a]
This commit is contained in:
foreman
2015-09-04 16:02:20 -04:00
parent 870c12b6fd
commit 9c201a5947
2 changed files with 0 additions and 1163 deletions
@@ -1,995 +0,0 @@
#include "cache.hpp"
// Use srcdata and buildOpts to generate a cache entry
//
// In:
// isCacheReady - Indicate whether cache file strucutre is set up
// srcData - Source data
// buildOpts - Build options
// dstData - Destination data
//
// Out:
// none
//
// Returns:
// true if entry created; false otherwise, check errorMsg for errors
//
bool StringCache::makeCacheEntry(bool isCacheReady, const StringCacheData *srcData,
const std::string &buildOpts, const std::string &dstData)
{
if (!isCacheReady) {
errorMsg = "makeCacheEntry() failed because cache file structure is not set up successfully";
appendLogToFile();
return false;
}
errorMsg.clear();
std::string fileName;
makeFileName(srcData, buildOpts, fileName);
/* Write all info to cache file */
const size_t buildOptsSize = buildOpts.size();
const size_t dstDataSize = dstData.size();
#if _WIN32
HANDLE cacheFile = CreateFile(fileName.c_str(), GENERIC_WRITE | WRITE_OWNER | READ_CONTROL,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (cacheFile == INVALID_HANDLE_VALUE) {
errorMsg = "Error opening file for writing: " + getLastErrorMsg();
return false;
}
#else
int cacheFile = open(fileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (cacheFile == -1) {
errorMsg = "Error opening file for writing: " + getLastErrorMsg();
return false;
}
// Exclusive write lock for cache file
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0};
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error setting file write lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
// Write cache file header, build options, source data size, source data
// and destination data to cache file
StringCacheFileHeader H = { {'A', 'M', 'D', '\0'}, buildOptsSize, dstDataSize };
if (!writeFile(cacheFile, &H, sizeof(StringCacheFileHeader)) ||
!writeFile(cacheFile, buildOpts.c_str(), buildOptsSize) ||
!writeFile(cacheFile, &(srcData->dataSize), sizeof(srcData->dataSize)) ||
!writeFile(cacheFile, srcData->data, srcData->dataSize) ||
!writeFile(cacheFile, dstData.c_str(), dstDataSize)) {
removePartiallyWrittenFile(fileName);
return false;
}
#if __linux__
// Unlock the file
fl.l_type = F_UNLCK;
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error unlock file write lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
CloseFile(cacheFile);
// Set file to only owner accessible
if (!setAccessPermission(fileName, true)) {
return false;
}
// Update cache info
unsigned int cacheFileSize = sizeof(StringCacheFileHeader) + buildOptsSize
+ sizeof(srcData->dataSize) + srcData->dataSize
+ dstDataSize;
if (!setCacheInfo(version, cacheSize + cacheFileSize)) {
errorMsg = "Cache version and size is not updated successfully";
return false;
}
return true;
}
// Use srcData and buildOpts to find the corresponding cache entry, if it exists
//
// In:
// deviceName - Chip name
// isCachingOn - A flag indicates whether caching functionality is turned on/off
// srcData - Source data
// buildOpts - Build options
// Msg - Message that need to passed for internal cache testing
//
// Out:
// isCacheReady - Indicate whether cache file strucutre is set up
// dstData - Destination data
//
// Returns:
// true if entry found; false otherwise, check errorMsg for errors
//
bool StringCache::getCacheEntry(bool &isCacheReady, const std::string &deviceName, bool isCachingOn,
const StringCacheData *srcData, const std::string &buildOpts,
std::string &dstData, const std::string &msg)
{
if (!isCachingOn) {
return false;
}
dstData.clear();
errorMsg.clear();
bool stringCached = false;
isCacheReady = cacheInit(deviceName);
if (!isCacheReady) {
appendLogToFile();
} else {
stringCached = getCacheEntry_helper(srcData, buildOpts, dstData);
// For internal cache test only
if (internalCacheTestSwitch()) {
std::string cacheMsg = msg;
if (stringCached) {
cacheMsg += " is cached!\n";
} else {
cacheMsg += " is not cached!\n";
}
fprintf(stdout, cacheMsg.c_str());
fflush(stdout);
}
}
if (!errorMsg.empty()) {
appendLogToFile();
}
return stringCached;
}
// Use srcData and buildOpts to find the corresponding cache entry, if it exists
//
// In:
// srcData - Source data
// buildOpts - Build options
//
// Out:
// dstData - Destination data
//
// Returns:
// true if entry found; false otherwise, check errorMsg for errors
//
bool StringCache::getCacheEntry_helper(const StringCacheData *srcData, const std::string &buildOpts,
std::string &dstData)
{
std::string fileName;
makeFileName(srcData, buildOpts, fileName);
#if _WIN32
HANDLE cacheFile = CreateFile(fileName.c_str(), GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (cacheFile == INVALID_HANDLE_VALUE) {
return false;
}
#else
int cacheFile = open(fileName.c_str(), O_RDONLY);
if (cacheFile == -1) {
return false;
}
// Read lock for cache file
struct flock fl = {F_RDLCK, SEEK_SET, 0, 0};
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error setting file read lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
// Read cache file header
StringCacheFileHeader H;
if (!readFile(cacheFile, &H, sizeof(StringCacheFileHeader))) {
return false;
}
// Compare cache file header
if (!verifyStringCacheFileHeader(H, buildOpts)) {
CloseFile(cacheFile);
return false;
}
// Read build options
char *fileBuildOpts = (char *)alloca(H.buildOptSize);
if (!readFile(cacheFile, fileBuildOpts, H.buildOptSize)) {
return false;
}
// Compare build options
if (buildOpts.compare(0, H.buildOptSize, fileBuildOpts, H.buildOptSize)) {
logErrorCloseFile("Cache collision: Build options do not match", cacheFile);
return false;
}
// Get source data size
size_t fileSrcDataSize = 0;
if (!readFile(cacheFile, &fileSrcDataSize, sizeof(size_t))) {
return false;
}
// Compare source data size
if (fileSrcDataSize != srcData->dataSize) {
logErrorCloseFile("Cache collision: Data size does not match", cacheFile);
return false;
}
// Get source data
std::unique_ptr<char> fileSrcData(new char [fileSrcDataSize]);
if (!fileSrcData) {
logErrorCloseFile("Out of memory: " + getLastErrorMsg(), cacheFile);
return false;
}
if (!readFile(cacheFile, fileSrcData.get(), fileSrcDataSize)) {
return false;
}
// Compare source data
if (memcmp(fileSrcData.get(), srcData->data, fileSrcDataSize)) {
logErrorCloseFile("Cache collision: Size matches, contents do not", cacheFile);
return false;
}
// Get cached content
std::unique_ptr<char> data(new char [H.dstSize]);
if (!data) {
logErrorCloseFile("Out of memory: " + getLastErrorMsg(), cacheFile);
return false;
}
if (!readFile(cacheFile, data.get(), H.dstSize)) {
return false;
}
dstData.assign(data.get(), H.dstSize);
#if __linux__
// Unlock the file
fl.l_type = F_UNLCK;
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error unlock file read lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
CloseFile(cacheFile);
return true;
}
#if _WIN32
// Get Sid of account
//
// In:
// userName - accont name
//
// Out:
// none
//
// Return:
// Sid of account if SID is obtained; NULL otherwise
//
std::unique_ptr<SID> StringCache::getSid(TCHAR *username)
{
if (username == NULL) {
errorMsg = "Invalid user name in getSid mehtod";
return NULL;
}
// If a buffer is too small, the count parameter will be set to the size needed.
const DWORD initialSize = 32;
SID_NAME_USE sidNameUse;
DWORD cbSid = initialSize, cchDomainName = initialSize;
// Create buffers for the SID and the domain name
std::unique_ptr<SID> sid = std::unique_ptr<SID>((SID*) new BYTE[initialSize]);
if (!sid) {
errorMsg = "Failed to allocate space for SID: " + getLastErrorMsg();
return NULL;
}
std::unique_ptr<TCHAR> wszDomainName(new TCHAR[initialSize]);
if (!wszDomainName) {
errorMsg = "Failed to allocate space for domain name: " + getLastErrorMsg();
return NULL;
}
// Obtain the SID for the account name passed
if (LookupAccountName(NULL, username, sid.get(), &cbSid, wszDomainName.get(), &cchDomainName, &sidNameUse)) {
if (IsValidSid(sid.get()) == FALSE) {
errorMsg = "The SID for the account is invalid: " + getLastErrorMsg();
return NULL;
}
return sid;
}
DWORD dwErrorCode = GetLastError();
if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER) {
if (cbSid > initialSize) {
// Reallocate memory for the SID buffer
sid = std::unique_ptr<SID>((SID*)new BYTE[cbSid]);
if (!sid) {
errorMsg = "Failed to allocate space for SID: " + getLastErrorMsg();
return NULL;
}
}
if (cchDomainName > initialSize) {
// Reallocate memory for the domain name buffer
wszDomainName = std::unique_ptr<TCHAR>(new TCHAR[cchDomainName]);
if (!wszDomainName) {
errorMsg = "Failed to allocate space for domain name: " + getLastErrorMsg();
return NULL;
}
}
// Obtain the SID for the account name passed again
if (LookupAccountName(NULL, username, sid.get(), &cbSid, wszDomainName.get(), &cchDomainName, &sidNameUse)) {
if (IsValidSid(sid.get()) == FALSE) {
errorMsg = "The SID for the account is invalid: " + getLastErrorMsg();
return NULL;
}
return sid;
}
} else {
errorMsg = "Failed to get user security identifier for the account: " + getLastErrorMsg();
return NULL;
}
return sid;
}
#endif
#if defined(__linux__)
inline bool path_is_directory(const std::string &path)
{
struct stat s_buf;
if (stat(path.c_str(), &s_buf))
return false;
return S_ISDIR(s_buf.st_mode);
}
// Remove all files and subfolders in a dir
//
// In:
// directory_name - folder name
//
// Out:
// none
//
// Returns:
// The number of files that are removed
//
static unsigned long fileCnt = 0;
unsigned long remove_all(const char* directory_name)
{
DIR *dp;
struct dirent *ep;
char p_buf[PATH_MAX] = {0};
dp = opendir(directory_name);
while ((ep = readdir(dp)) != NULL) {
if (strcmp(ep->d_name, "..") && strcmp(ep->d_name, ".")) {
snprintf(p_buf, PATH_MAX, "%s/%s", directory_name, ep->d_name);
if (path_is_directory(p_buf)) {
if (remove_all(p_buf) < 0) {
return LONG_MIN;
}
} else {
if (unlink(p_buf) != 0) {
return LONG_MIN;
} else {
fileCnt++;
}
}
}
}
closedir(dp);
return (rmdir(directory_name) == 0) ? fileCnt : LONG_MIN;
}
#endif
// Wipe the cache folder structure
//
// In:
// none
//
// Out:
// none
//
// Returns:
// true if folder wipe is ok; false otherwise
//
bool StringCache::wipeCacheFolders()
{
for (int i = 0; i < 16; ++i) {
std::string dir = rootPath;
std::stringstream ss;
ss << fileSeparator() << std::hex << i;
dir += ss.str();
if (pathExists(dir)) {
#if _WIN32
std::tr2::sys::path mDir(dir);
if (remove_all(mDir) < 0) {
#else
if (remove_all(dir.c_str()) < 0) {
#endif
errorMsg = "Error deleting cache directory";
return false;
}
}
}
return true;
}
// Setup cache tree structure
//
// In:
// none
//
// Out:
// none
//
// Returns:
// true if folders setup is ok; false otherwise
//
bool StringCache::setUpCacheFolders()
{
// Directory structure is distributed as 16 * 16 in order to keep the file count per directory low
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 16; ++j) {
std::string dir = rootPath;
std::stringstream ss;
ss << fileSeparator() << std::hex << i << fileSeparator() << j;
dir += ss.str();
if (false == createPath(dir)) {
errorMsg = "Error creating directory in cache";
return false;
}
// Set folder to only owner accessible
if (!setAccessPermission(rootPath)) {
return false;
}
}
}
return true;
}
// Return detailed error message as string
//
// In:
// None
//
// Out:
// None
//
// Return:
// Error message in string format. Otherwise, an empty string if there is no error
//
std::string StringCache::getLastErrorMsg()
{
#if _WIN32
// Get the error message, if any.
DWORD errorMessageID = GetLastError();
if (errorMessageID == 0) {
return std::string(); //No error message has been recorded
}
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return message;
#else
return std::string(strerror(errno));
#endif
}
// Set file to only owner accessible
//
// In:
// fileName - Path to file
// isFile - True if fileName is a file, false if it is a path; false by default
//
// Out:
// none
//
// Returns:
// true if access permission is under control; false otherwise
//
bool StringCache::setAccessPermission(const std::string &fileName, bool isFile)
{
#if _WIN32
TCHAR username[UNLEN + 1];
DWORD username_len = UNLEN + 1;
if (!GetUserName(username, &username_len)) {
errorMsg = "Failed to get user name for the account: " + getLastErrorMsg();
return false;
}
std::unique_ptr<SID> sid = getSid(username);
if (!sid) {
return false;
}
if (SetNamedSecurityInfo((LPTSTR)(fileName.c_str()), SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION,
sid.get(), NULL, NULL, NULL) != ERROR_SUCCESS ) {
errorMsg = "Failed to set user access permission: " + getLastErrorMsg();
return false;
}
#else
if (!isFile) {
int ret = chmod(fileName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
if (ret < 0) {
errorMsg = "Failed to set user access permission: " + getLastErrorMsg();
return false;
}
}
#endif
return true;
}
// Set the cache's root path
//
// In:
// chipName - Chip name
//
// Out:
// none
//
// Returns:
// true if root path of cache is set successfully; false otherwise
//
bool StringCache::setRootPath(const std::string &chipName)
{
rootPath.clear();
#if _WIN32
// Set root path to <USER>\AppData\Local\AMD\CLCache
TCHAR userLocalAppDir[_MAX_PATH];
// Get path for user specific and non-roaming data
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, userLocalAppDir))) {
rootPath = userLocalAppDir;
} else {
errorMsg = "User's local app dir is not found: " + getLastErrorMsg();
return false;
}
rootPath += "\\AMD\\CLCache";
#else
// Set root path to <HOME>/.AMD/CLCache
struct passwd *pwd = getpwuid(getuid());
if (pwd == NULL) {
errorMsg = getLastErrorMsg();
return false;
}
const char *homedir = pwd->pw_dir;
if (homedir == NULL) {
errorMsg = "Failed to get HOME directory: " + getLastErrorMsg();
return false;
}
rootPath = homedir;
// Verify the path exists
if (!pathExists(rootPath)) {
errorMsg = "User's home directory is not created: " + getLastErrorMsg();
return false;
}
rootPath += "/.AMD/CLCache";
#endif
rootPath += fileSeparator() + chipName;
if (!createPath(rootPath)) {
errorMsg = "Failed to create cache root directory";
return false;
}
// Set folder to only owner accessible
return setAccessPermission(rootPath);
}
// Set the cache version and size
//
// In:
// newVersion - New version for the cache
// newSize - New size for the cache
//
// Out:
// none
//
// Returns:
// true if successful; false otherwise
//
bool StringCache::setCacheInfo(unsigned int newVersion, unsigned int newSize)
{
unsigned int fileData[2];
fileData[0] = newVersion;
fileData[1] = newSize;
if (!writeFile(indexName, fileData, sizeof(fileData), false)) {
removePartiallyWrittenFile(indexName);
return false;
}
version = newVersion;
cacheSize = newSize;
return true;
}
// Get the version and size of the cache
//
// In:
// none
//
// Out:
// none
//
// Returns:
// true if successful; false otherwise
//
bool StringCache::getCacheInfo()
{
indexName = rootPath;
indexName += fileSeparator();
indexName += "cacheDir";
#if _WIN32
HANDLE cacheFile = CreateFile(indexName.c_str(), GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (cacheFile == INVALID_HANDLE_VALUE) {
return setCacheInfo(-1, 0);
}
#else
int cacheFile = open(indexName.c_str(), O_RDONLY);
if (cacheFile == -1) {
return setCacheInfo(-1, 0);
}
// Read lock for cache file
struct flock fl = {F_RDLCK, SEEK_SET, 0, 0};
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error setting file read lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
if (!readFile(cacheFile, &version, sizeof(unsigned int))) {
return false;
}
if (!readFile(cacheFile, &cacheSize, sizeof(unsigned int))) {
return false;
}
#if __linux__
// Unlock the file
fl.l_type = F_UNLCK;
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error unlock file read lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
CloseFile(cacheFile);
return true;
}
// Initialize the cache
//
// In:
// chipName - Chip name
//
// Out:
// none
//
// Returns:
// true if successful; false otherwise
//
bool StringCache::cacheInit(const std::string &chipName)
{
if (!setRootPath(chipName)) {
return false;
}
if (!getCacheInfo()) {
return false;
}
// Limit cache size to default cache size, and wipe out all cache files when it's exceed
// TODO: need to implement cache eviction policy
if (version != cacheVersion || cacheSize > DEFAULT_CACHE_SIZE) {
if (!wipeCacheFolders() || !setCacheInfo(cacheVersion, 0) || !setUpCacheFolders()) {
return false;
}
}
return true;
}
// Compute the hash value for a buffer of data along with the buildOpts
//
// In:
// data - Data to hash
// buildOpts - Build options
//
// Out:
// none
//
// Returns:
// Hash value computed from the inputs
//
unsigned int StringCache::computeHash(const StringCacheData *data, const std::string &buildOpts)
{
HashType v = { std::string(data->data, data->dataSize), buildOpts };
std::hash<HashType> hash_fn;
return hash_fn(v);
}
// Control cache test
//
// In:
// none
//
// Out:
// none
//
// Returns:
// true if cache test is on; false otherwise
//
bool StringCache::internalCacheTestSwitch() {
return false;
}
// Generate file path from a hash value
//
// In:
// hashVal - A hash value
//
// Out:
// pathToFile - Path to the file
//
// Returns:
// none
//
void StringCache::getFilePathFromHash(const unsigned int hashVal, std::string &pathToFile)
{
char textHash[9];
sprintf(textHash, "%08x", hashVal);
std::string fileName = textHash;
pathToFile = rootPath;
pathToFile += fileSeparator();
// First char determines first dir level
pathToFile += fileName[0];
pathToFile += fileSeparator();
// Second char determines second dir level
pathToFile += fileName[1];
pathToFile += fileSeparator();
// Rest of file name determines name
pathToFile += fileName.c_str() + 2;
}
// Use data and buildOpts to generate a file name
//
// In:
// data - Pointer to data
// buildOpts - Build options
//
// Out:
// pathToFile - Path to the file
//
// Returns:
// none
//
void StringCache::makeFileName(const StringCacheData *data, const std::string &buildOpts, std::string &pathToFile)
{
unsigned int hashVal = computeHash(data, buildOpts);
getFilePathFromHash(hashVal, pathToFile);
}
// Verify whether the file includes the right cache file header
//
// In:
// H - String cache file header
// buildOpts - Build options
//
// Out:
// None
//
// Returns:
// true if the file is the one matched our requirement; false othereise
//
bool StringCache::verifyStringCacheFileHeader(StringCacheFileHeader &H, const std::string &buildOpts)
{
const char AMD[4] = {'A', 'M', 'D', '\0'};
if (memcmp(H.AMD, AMD, 4)) {
errorMsg = "Not a valid cache file";
return false;
}
if (H.buildOptSize != buildOpts.size()) {
errorMsg = "Cache collision: Build option lengths do not match";
return false;
}
return true;
}
// Read contents in cacheFile
//
// In:
// cacheFile - cache file to be read
// sizeToRead - total bytes to be read
//
// Out:
// buffer - contains file content
//
// Returns:
// true if file reads succeed; false otherwise
//
bool StringCache::readFile(FileHandle cacheFile, void *buffer, ssize_t sizeToRead)
{
// Read content to the buffer
#if _WIN32
DWORD bytesRead = 0;
if (FALSE == ReadFile(cacheFile, buffer, sizeToRead, &bytesRead, NULL)) {
logErrorCloseFile("Unable to read cache file: " + getLastErrorMsg(), cacheFile);
return false;
}
#else
ssize_t bytesRead = read(cacheFile, buffer, sizeToRead);
#endif
// Check if there is any error in file reading
if (bytesRead != sizeToRead) {
logErrorCloseFile("Error reading cache file: " + getLastErrorMsg(), cacheFile);
return false;
}
return true;
}
// Write contents to cacheFile
//
// In:
// cacheFile - cache file to be written
// buffer - contains content to be written
// sizeToWriten - total bytes to be written
//
// Out:
// none
//
// Returns:
// true if file writes succeed; false otherwise
//
bool StringCache::writeFile(FileHandle cacheFile, const void *buffer, ssize_t sizeToWritten)
{
#if _WIN32
DWORD bytesWritten = 0;
if (FALSE == WriteFile(cacheFile, buffer, sizeToWritten, &bytesWritten, NULL)) {
logErrorCloseFile("Unable to write to file: " + getLastErrorMsg(), cacheFile);
return false;
}
#else
ssize_t bytesWritten = write(cacheFile, buffer, sizeToWritten);
#endif
// Check if there is any error in file reading
if (bytesWritten != sizeToWritten) {
logErrorCloseFile("Error writing cache file: " + getLastErrorMsg(), cacheFile);
return false;
}
return true;
}
// Open a file and write its contents
//
// In:
// fileName - Path to file
// data - Pointer to file contents
// size - Data size
//
// Out:
// none
//
// Returns:
// true if the file is written to file successfully; false otherwise
//
bool StringCache::writeFile(const std::string &fileName, const void *data, size_t size, bool appendable)
{
#if _WIN32
DWORD appendAccess = 0;
if (appendable) {
appendAccess = FILE_APPEND_DATA;
}
HANDLE cacheFile = CreateFile(fileName.c_str(), GENERIC_WRITE | WRITE_OWNER | READ_CONTROL | appendAccess,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (cacheFile == INVALID_HANDLE_VALUE) {
errorMsg = "Error opening file for writing: " + getLastErrorMsg();
return false;
}
#else
int cacheFile = -1;
if (appendable) {
cacheFile = open(fileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
} else {
cacheFile = open(fileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
}
if (cacheFile == -1) {
errorMsg = "Error opening file for writing: " + getLastErrorMsg();
return false;
}
// Exclusive write lock for cache file
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0};
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error setting file write lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
// Write data to file
if (!writeFile(cacheFile, data, size)) {
removePartiallyWrittenFile(fileName);
return false;
}
#if __linux__
// Unlock the file
fl.l_type = F_UNLCK;
if (fcntl(cacheFile, F_SETLK, &fl) == -1) {
logErrorCloseFile("Error unlock file write lock: " + getLastErrorMsg(), cacheFile);
return false;
}
#endif
CloseFile(cacheFile);
// Set file to only owner accessible
return setAccessPermission(fileName, true);
}
// Remove file
//
// In:
// fileName - Path to file
//
// Out:
// none
//
// Returns:
// none
//
void StringCache::removePartiallyWrittenFile(const std::string &fileName)
{
errorMsg = getLastErrorMsg();
#if _WIN32
if (!DeleteFile(fileName.c_str())) {
#else
if (remove(fileName.c_str())) {
#endif
errorMsg += ", Unable to delete partially written cache file: " + getLastErrorMsg();
}
}
// Log caching error messages for debugging the cache and/or detecting collisions
//
// In:
// extraMsg - Extra message
//
// Out:
// none
//
// Returns:
// none
//
void StringCache::appendLogToFile(std::string extraMsg) {
if (pathExists(rootPath)) {
std::string fileName = rootPath + fileSeparator() + "cacheError.log";
errorMsg += extraMsg;
if ('\n' != errorMsg[errorMsg.size()-1]) {
errorMsg.append("\n");
}
writeFile(fileName, errorMsg.c_str(), errorMsg.length(), true);
}
}
// Log error message and close the file
//
// In:
// errorMsg - Error message
// file - file handle
//
// Out:
// none
//
// Returns:
// none
//
void StringCache::logErrorCloseFile(const std::string &errorMsg, const FileHandle file)
{
appendLogToFile(errorMsg);
CloseFile(file);
}
char StringCache::fileSeparator() {
#if _WIN32
return '\\';
#else
return '/';
#endif
}
bool StringCache::pathExists(const std::string& path)
{
#if _WIN32
DWORD fid = GetFileAttributes(path.c_str());
return (fid != INVALID_FILE_ATTRIBUTES) && ((fid & FILE_ATTRIBUTE_DIRECTORY) != 0);
#else
struct stat st;
if (stat(path.c_str(), &st) != 0)
return false;
return S_ISDIR(st.st_mode);
#endif
}
bool StringCache::createPath(const std::string& path)
{
#if __linux__
mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
#endif
size_t pos = 0;
while (true) {
pos = path.find(fileSeparator(), pos);
const std::string currPath = path.substr(0, pos);
if (!currPath.empty() && !pathExists(currPath)) {
#if _WIN32
if (!CreateDirectory(currPath.c_str(), NULL)) return false;
#else
if (mkdir(currPath.c_str(), mode) == -1) return false;
#endif
}
if (pos == std::string::npos) break;
++pos;
}
return true;
}
@@ -1,168 +0,0 @@
#ifndef AMD_CACHE_H_
#define AMD_CACHE_H_
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <cstdio>
#ifdef __linux__
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <alloca.h>
#else
#include <windows.h>
#include <shlobj.h>
#include <Lmcons.h>
#include <aclapi.h>
#include <filesystem>
#include <BaseTsd.h>
#endif
#if _WIN32
#define CloseFile CloseHandle
#define FileHandle HANDLE
typedef SSIZE_T ssize_t;
#else
#define CloseFile close
#define FileHandle int
#endif
typedef struct _StringCacheData {
char *data;
size_t dataSize;
} StringCacheData;
// Specialize std::hash
struct HashType {
std::string data;
std::string buildOption;
};
namespace std {
template<>
struct hash<HashType> {
public:
size_t operator()(const HashType &v) const
{
size_t h1 = std::hash<std::string>()(v.data);
size_t h2 = std::hash<std::string>()(v.buildOption);
return h1 ^ ( h2 << 1 );
}
};
}
typedef struct _StringCacheFileHeader {
char AMD[4]; // 'AMD\0'
size_t buildOptSize;
size_t dstSize;
} StringCacheFileHeader;
/* String Cache File Contents (listed in order) */
// BUild options in text format
// Src data size
// Src data
// Dest data
class StringCache {
private:
// TODO: the default cache size (512MB) might be changed later
static const unsigned int DEFAULT_CACHE_SIZE = 512 * 1024 * 1024;
unsigned int version;
unsigned int cacheVersion;
unsigned int cacheSize;
std::string rootPath;
std::string indexName;
std::string errorMsg;
// Helper functions
char fileSeparator();
bool pathExists(const std::string &path);
bool createPath(const std::string &path);
// Set the root path for the cache
bool setRootPath(const std::string &chipName);
// Wipe the cache folder structure
bool wipeCacheFolders();
// Setup cache tree structure
bool setUpCacheFolders();
// Get the cache version and size from the index file
bool getCacheInfo();
// Set the cache version and size in the index file
bool setCacheInfo(unsigned int newVersion, unsigned int newSize);
// Compute hash value for chunks of data
unsigned int computeHash(const StringCacheData *data, const std::string &buildOpts);
// Computes hash and file name from given data
void makeFileName(const StringCacheData *data, const std::string &buildOpts, std::string &pathToFile);
// Finds path to a file from a given hash value
void getFilePathFromHash(unsigned int hash, std::string &pathToFile);
#if _WIN32
// Get Sid of account
std::unique_ptr<SID> getSid(TCHAR *userName);
#endif
// Return detailed error message as string
std::string getLastErrorMsg();
// Read contents in cacheFile
bool readFile(FileHandle cacheFile, void *buffer, ssize_t size);
// Write data to a file
bool writeFile(FileHandle cacheFile, const void *buffer, ssize_t sizeToWriten);
bool writeFile(const std::string &fileName, const void *data, size_t size, bool appendable);
// Set file to only owner accessible
bool setAccessPermission(const std::string &fileName, bool isFile = false);
// Set up cache file structure
bool cacheInit(const std::string &chipName);
// Get cache entry corresponding to srcData, if it exists
bool getCacheEntry_helper(const StringCacheData *srcData, const std::string &buildOpts,
std::string &dstData);
// Control cache test
bool internalCacheTestSwitch();
// Verify whether the file includes the right cache file header
bool verifyStringCacheFileHeader(StringCacheFileHeader &H, const std::string &buildOpts);
// Remove partially written file
void removePartiallyWrittenFile(const std::string &fileName);
// Log error message and close the file
void logErrorCloseFile(const std::string &errorMsg, const FileHandle file);
public:
StringCache(unsigned int cacheVer) : version(0), cacheVersion(cacheVer), cacheSize(0) {
rootPath.clear();
indexName.clear();
errorMsg.clear();
}
// Make cache entry corresponding to srcData, dstData, buildOpts
bool makeCacheEntry(bool isCacheReady, const StringCacheData *srcData,
const std::string &buildOpts, const std::string &dstData);
// Wrapper function for getCacheEntry
bool getCacheEntry(bool &isCacheReady, const std::string &deviceName, bool isCachingOn,
const StringCacheData *srcData, const std::string &buildOpts,
std::string &dstData, const std::string &msg);
// Log caching error messages for debugging the cache and/or detecting collisions
void appendLogToFile(std::string extraMsg = "");
};
#endif // AMD_CACHE_H_