Refactored lamexp_temp_folder2() function. This also fixes a potential deadlock at application when %TMP% points to an invalid folder. Now using separate locks for lamexp_temp_folder2() and lamexp_known_folder().

This commit is contained in:
LoRd_MuldeR 2013-06-29 18:06:21 +02:00
parent 03c2a9fccc
commit a8348b01e8
5 changed files with 117 additions and 89 deletions

View File

@ -21,6 +21,7 @@ a:visited { color: #0000EE; }
<li>Updated Qt runtime libraries to v4.8.5 (2013-05-31), compiled with MSVC 11.0
<li>Updated FLAC encoder/decoder to v1.3.0 (2013-05-27), compiled with ICL 13.0
<li>Updated Opus encoder/decoder libraries to v1.1.x and Opus-Tools to v0.1.6 (2013-06-17)
<li>Fixed a potential deadlock during startup when %TMP% points to an invalid folder
<li>Fixed a superfluous "beep" sound that appeared on application startup
</ul><br>

View File

@ -34,7 +34,7 @@
#define VER_LAMEXP_MINOR_LO 8
#define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 3
#define VER_LAMEXP_BUILD 1298
#define VER_LAMEXP_BUILD 1301
#define VER_LAMEXP_CONFG 1288
///////////////////////////////////////////////////////////////////////////////

View File

@ -144,12 +144,14 @@ void SplashScreen::showSplash(QThread *thread)
//Loop while thread is still running
if(bool bIsRunning = THREAD_RUNNING(thread))
{
int deadlockCounter = 0;
while(bIsRunning)
{
loop->exec();
if(bIsRunning = THREAD_RUNNING(thread))
{
qWarning("Potential deadlock in initialization thread!");
if(++deadlockCounter >= 10) qFatal("Deadlock in initialization thread!");
}
}
}

View File

@ -228,11 +228,18 @@ static const unsigned int g_lamexp_toolver_coreaudio = VER_LAMEXP_TOOL_COREAUDIO
//Special folders
static struct
{
QString *temp;
QMap<size_t, QString> *knownFolders;
QReadWriteLock lock;
}
g_lamexp_folder;
g_lamexp_known_folder;
//%TEMP% folder
static struct
{
QString *path;
QReadWriteLock lock;
}
g_lamexp_temp_folder;
//Tools
static struct
@ -1487,102 +1494,103 @@ QString lamexp_rand_str(void)
throw "The RegExp didn't match on the UUID string. This shouldn't happen ;-)";
}
/*
* Try to initialize the folder (with *write* access)
*/
static QString lamexp_try_init_folder(const QString &folderPath)
{
bool success = false;
const QFileInfo folderInfo(folderPath);
const QDir folderDir(folderInfo.absoluteFilePath());
//Create folder, if it does *not* exist yet
if(!folderDir.exists())
{
folderDir.mkpath(".");
}
//Make sure folder exists now *and* is writable
if(folderDir.exists())
{
QFile testFile(folderDir.absoluteFilePath(QString("~%1.tmp").arg(lamexp_rand_str())));
if(testFile.open(QIODevice::ReadWrite))
{
const QByteArray testData = QByteArray("Lorem ipsum dolor sit amet, consectetur, adipisci velit!");
if(testFile.write(testData) >= strlen(testData))
{
success = true;
testFile.remove();
}
testFile.close();
}
}
return (success ? folderDir.canonicalPath() : QString());
}
/*
* Get LameXP temp folder
*/
const QString &lamexp_temp_folder2(void)
{
QReadLocker readLock(&g_lamexp_folder.lock);
QReadLocker readLock(&g_lamexp_temp_folder.lock);
//Already initialized?
if(g_lamexp_folder.temp)
if(g_lamexp_temp_folder.path && (!g_lamexp_temp_folder.path->isEmpty()))
{
if(!g_lamexp_folder.temp->isEmpty())
if(QDir(*g_lamexp_temp_folder.path).exists())
{
if(QDir(*g_lamexp_folder.temp).exists())
{
return *g_lamexp_folder.temp;
}
return *g_lamexp_temp_folder.path;
}
}
//Obtain the write lock to initilaize
readLock.unlock();
QWriteLocker writeLock(&g_lamexp_folder.lock);
QWriteLocker writeLock(&g_lamexp_temp_folder.lock);
if(!g_lamexp_folder.temp)
//Still uninitilaized?
if(g_lamexp_temp_folder.path && (!g_lamexp_temp_folder.path->isEmpty()))
{
g_lamexp_folder.temp = new QString();
if(QDir(*g_lamexp_temp_folder.path).exists())
{
return *g_lamexp_temp_folder.path;
}
}
g_lamexp_folder.temp->clear();
//Create the string, if not done yet
if(!g_lamexp_temp_folder.path)
{
g_lamexp_temp_folder.path = new QString();
}
static const char *TEMP_STR = "Temp";
const QString WRITE_TEST_DATA = lamexp_rand_str();
const QString SUB_FOLDER = lamexp_rand_str();
g_lamexp_temp_folder.path->clear();
//Try the %TMP% or %TEMP% directory first
QDir temp = QDir::temp();
if(temp.exists())
QString tempPath = lamexp_try_init_folder(QDir::temp().absolutePath());
if(!tempPath.isEmpty())
{
temp.mkdir(SUB_FOLDER);
if(temp.cd(SUB_FOLDER) && temp.exists())
(*g_lamexp_temp_folder.path) = lamexp_try_init_folder(QString("%1/%2").arg(tempPath, lamexp_rand_str()));
}
//Otherwise create TEMP folder in %LOCALAPPDATA%
if(g_lamexp_temp_folder.path->isEmpty())
{
tempPath = lamexp_try_init_folder(QString("%1/Temp").arg(lamexp_known_folder(lamexp_folder_localappdata)));
if(!tempPath.isEmpty())
{
QFile testFile(QString("%1/~%2.tmp").arg(temp.canonicalPath(), lamexp_rand_str()));
if(testFile.open(QIODevice::ReadWrite))
{
if(testFile.write(WRITE_TEST_DATA.toLatin1().constData()) >= strlen(WRITE_TEST_DATA.toLatin1().constData()))
{
(*g_lamexp_folder.temp) = temp.canonicalPath();
}
testFile.remove();
}
}
if(!g_lamexp_folder.temp->isEmpty())
{
return *g_lamexp_folder.temp;
(*g_lamexp_temp_folder.path) = lamexp_try_init_folder(QString("%1/%2").arg(tempPath, lamexp_rand_str()));
}
}
//Create TEMP folder in %LOCALAPPDATA%
QDir localAppData = QDir(lamexp_known_folder(lamexp_folder_localappdata));
if(!localAppData.path().isEmpty())
//Failed to create TEMP folder?
if(g_lamexp_temp_folder.path->isEmpty())
{
if(!localAppData.exists())
{
localAppData.mkpath(".");
}
if(localAppData.exists())
{
if(!localAppData.entryList(QDir::AllDirs).contains(TEMP_STR, Qt::CaseInsensitive))
{
localAppData.mkdir(TEMP_STR);
}
if(localAppData.cd(TEMP_STR) && localAppData.exists())
{
localAppData.mkdir(SUB_FOLDER);
if(localAppData.cd(SUB_FOLDER) && localAppData.exists())
{
QFile testFile(QString("%1/~%2.tmp").arg(localAppData.canonicalPath(), lamexp_rand_str()));
if(testFile.open(QIODevice::ReadWrite))
{
if(testFile.write(WRITE_TEST_DATA.toLatin1().constData()) >= strlen(WRITE_TEST_DATA.toLatin1().constData()))
{
(*g_lamexp_folder.temp) = localAppData.canonicalPath();
}
testFile.remove();
}
}
}
}
if(!g_lamexp_folder.temp->isEmpty())
{
return *g_lamexp_folder.temp;
}
qFatal("Temporary directory could not be initialized !!!");
}
//Failed to create TEMP folder!
qFatal("Temporary directory could not be initialized!\n\nFirst attempt:\n%s\n\nSecond attempt:\n%s", temp.canonicalPath().toUtf8().constData(), localAppData.canonicalPath().toUtf8().constData());
return *g_lamexp_folder.temp;
return *g_lamexp_temp_folder.path;
}
/*
@ -1908,7 +1916,7 @@ const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
static const GUID GUID_PROGRAM_FILES = {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}};
static const GUID GUID_SYSTEM_FOLDER = {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}};
QReadLocker readLock(&g_lamexp_folder.lock);
QReadLocker readLock(&g_lamexp_known_folder.lock);
int folderCSIDL = -1;
GUID folderGUID = {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
@ -1938,20 +1946,31 @@ const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
}
//Already in cache?
if(g_lamexp_folder.knownFolders)
if(g_lamexp_known_folder.knownFolders)
{
if(g_lamexp_folder.knownFolders->contains(folderCacheId))
if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
{
return (*g_lamexp_folder.knownFolders)[folderCacheId];
return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
}
}
//Obtain write lock to initialize
readLock.unlock();
QWriteLocker writeLock(&g_lamexp_folder.lock);
QWriteLocker writeLock(&g_lamexp_known_folder.lock);
//Still not in cache?
if(g_lamexp_known_folder.knownFolders)
{
if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
{
return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
}
}
static SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL;
static SHGetFolderPathFun SHGetFolderPathPtr = NULL;
//Lookup functions
if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr))
{
QLibrary kernel32Lib("shell32.dll");
@ -1964,6 +1983,7 @@ const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
QString folder;
//Now try to get the folder path!
if(SHGetKnownFolderPathPtr)
{
WCHAR *path = NULL;
@ -2002,14 +2022,14 @@ const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
}
//Create cache
if(!g_lamexp_folder.knownFolders)
if(!g_lamexp_known_folder.knownFolders)
{
g_lamexp_folder.knownFolders = new QMap<size_t, QString>();
g_lamexp_known_folder.knownFolders = new QMap<size_t, QString>();
}
//Update cache
g_lamexp_folder.knownFolders->insert(folderCacheId, folder);
return (*g_lamexp_folder.knownFolders)[folderCacheId];
g_lamexp_known_folder.knownFolders->insert(folderCacheId, folder);
return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
}
/*
@ -2434,7 +2454,8 @@ extern "C"
LAMEXP_ZERO_MEMORY(g_lamexp_tools);
LAMEXP_ZERO_MEMORY(g_lamexp_currentTranslator);
LAMEXP_ZERO_MEMORY(g_lamexp_translation);
LAMEXP_ZERO_MEMORY(g_lamexp_folder);
LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
LAMEXP_ZERO_MEMORY(g_lamexp_temp_folder);
LAMEXP_ZERO_MEMORY(g_lamexp_ipc_ptr);
LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
@ -2501,24 +2522,24 @@ void lamexp_finalization(void)
}
//Delete temporary files
if(g_lamexp_folder.temp)
if(g_lamexp_temp_folder.path)
{
if(!g_lamexp_folder.temp->isEmpty())
if(!g_lamexp_temp_folder.path->isEmpty())
{
for(int i = 0; i < 100; i++)
{
if(lamexp_clean_folder(*g_lamexp_folder.temp))
if(lamexp_clean_folder(*g_lamexp_temp_folder.path))
{
break;
}
Sleep(125);
}
}
LAMEXP_DELETE(g_lamexp_folder.temp);
LAMEXP_DELETE(g_lamexp_temp_folder.path);
}
//Clear folder cache
LAMEXP_DELETE(g_lamexp_folder.knownFolders);
LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
//Clear languages
if(g_lamexp_currentTranslator.instance)

View File

@ -297,6 +297,10 @@ void InitializationThread::run()
qWarning("Extracting tools took %.3f seconds -> probably slow realtime virus scanner.", delayExtract);
qWarning("Please report performance problems to your anti-virus developer !!!\n");
}
else
{
qDebug("Extracting the tools took %.3f seconds (OK).\n", delayExtract);
}
//Register all translations
initTranslations();