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 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 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>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 <li>Fixed a superfluous "beep" sound that appeared on application startup
</ul><br> </ul><br>

View File

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

View File

@ -144,12 +144,14 @@ void SplashScreen::showSplash(QThread *thread)
//Loop while thread is still running //Loop while thread is still running
if(bool bIsRunning = THREAD_RUNNING(thread)) if(bool bIsRunning = THREAD_RUNNING(thread))
{ {
int deadlockCounter = 0;
while(bIsRunning) while(bIsRunning)
{ {
loop->exec(); loop->exec();
if(bIsRunning = THREAD_RUNNING(thread)) if(bIsRunning = THREAD_RUNNING(thread))
{ {
qWarning("Potential deadlock in initialization 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 //Special folders
static struct static struct
{ {
QString *temp;
QMap<size_t, QString> *knownFolders; QMap<size_t, QString> *knownFolders;
QReadWriteLock lock; QReadWriteLock lock;
} }
g_lamexp_folder; g_lamexp_known_folder;
//%TEMP% folder
static struct
{
QString *path;
QReadWriteLock lock;
}
g_lamexp_temp_folder;
//Tools //Tools
static struct 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 ;-)"; 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 * Get LameXP temp folder
*/ */
const QString &lamexp_temp_folder2(void) const QString &lamexp_temp_folder2(void)
{ {
QReadLocker readLock(&g_lamexp_folder.lock); QReadLocker readLock(&g_lamexp_temp_folder.lock);
//Already initialized? //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_temp_folder.path;
{
return *g_lamexp_folder.temp;
}
} }
} }
//Obtain the write lock to initilaize
readLock.unlock(); 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;
}
}
//Create the string, if not done yet
if(!g_lamexp_temp_folder.path)
{
g_lamexp_temp_folder.path = new QString();
} }
g_lamexp_folder.temp->clear(); g_lamexp_temp_folder.path->clear();
static const char *TEMP_STR = "Temp";
const QString WRITE_TEST_DATA = lamexp_rand_str();
const QString SUB_FOLDER = lamexp_rand_str();
//Try the %TMP% or %TEMP% directory first //Try the %TMP% or %TEMP% directory first
QDir temp = QDir::temp(); QString tempPath = lamexp_try_init_folder(QDir::temp().absolutePath());
if(temp.exists()) if(!tempPath.isEmpty())
{ {
temp.mkdir(SUB_FOLDER); (*g_lamexp_temp_folder.path) = lamexp_try_init_folder(QString("%1/%2").arg(tempPath, lamexp_rand_str()));
if(temp.cd(SUB_FOLDER) && temp.exists()) }
//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())); (*g_lamexp_temp_folder.path) = lamexp_try_init_folder(QString("%1/%2").arg(tempPath, 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;
} }
} }
//Create TEMP folder in %LOCALAPPDATA% //Failed to create TEMP folder?
QDir localAppData = QDir(lamexp_known_folder(lamexp_folder_localappdata)); if(g_lamexp_temp_folder.path->isEmpty())
if(!localAppData.path().isEmpty())
{ {
if(!localAppData.exists()) qFatal("Temporary directory could not be initialized !!!");
{
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;
}
} }
//Failed to create TEMP folder! return *g_lamexp_temp_folder.path;
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;
} }
/* /*
@ -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_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}}; 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; int folderCSIDL = -1;
GUID folderGUID = {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}; 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? //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(); 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 SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL;
static SHGetFolderPathFun SHGetFolderPathPtr = NULL; static SHGetFolderPathFun SHGetFolderPathPtr = NULL;
//Lookup functions
if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr)) if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr))
{ {
QLibrary kernel32Lib("shell32.dll"); QLibrary kernel32Lib("shell32.dll");
@ -1964,6 +1983,7 @@ const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
QString folder; QString folder;
//Now try to get the folder path!
if(SHGetKnownFolderPathPtr) if(SHGetKnownFolderPathPtr)
{ {
WCHAR *path = NULL; WCHAR *path = NULL;
@ -2002,14 +2022,14 @@ const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
} }
//Create cache //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 //Update cache
g_lamexp_folder.knownFolders->insert(folderCacheId, folder); g_lamexp_known_folder.knownFolders->insert(folderCacheId, folder);
return (*g_lamexp_folder.knownFolders)[folderCacheId]; return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
} }
/* /*
@ -2434,7 +2454,8 @@ extern "C"
LAMEXP_ZERO_MEMORY(g_lamexp_tools); LAMEXP_ZERO_MEMORY(g_lamexp_tools);
LAMEXP_ZERO_MEMORY(g_lamexp_currentTranslator); LAMEXP_ZERO_MEMORY(g_lamexp_currentTranslator);
LAMEXP_ZERO_MEMORY(g_lamexp_translation); 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_ipc_ptr);
LAMEXP_ZERO_MEMORY(g_lamexp_os_version); LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled); LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
@ -2501,24 +2522,24 @@ void lamexp_finalization(void)
} }
//Delete temporary files //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++) 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; break;
} }
Sleep(125); Sleep(125);
} }
} }
LAMEXP_DELETE(g_lamexp_folder.temp); LAMEXP_DELETE(g_lamexp_temp_folder.path);
} }
//Clear folder cache //Clear folder cache
LAMEXP_DELETE(g_lamexp_folder.knownFolders); LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
//Clear languages //Clear languages
if(g_lamexp_currentTranslator.instance) 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("Extracting tools took %.3f seconds -> probably slow realtime virus scanner.", delayExtract);
qWarning("Please report performance problems to your anti-virus developer !!!\n"); 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 //Register all translations
initTranslations(); initTranslations();