changeset 98:604bd4ee3ed4

* Add a method in System.{cpp,h} to try to establish whether a process of a given pid is running or not * Make TempDirectory store its process ID, and clean up any old temporary directories it finds that correspond to non-running processes
author Chris Cannam
date Fri, 05 May 2006 11:28:04 +0000
parents 22494cc28c9f
children 9a44ccae165c
files base/System.cpp base/System.h base/TempDirectory.cpp base/TempDirectory.h
diffstat 4 files changed, 155 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/base/System.cpp	Thu May 04 20:17:28 2006 +0000
+++ b/base/System.cpp	Fri May 05 11:28:04 2006 +0000
@@ -15,6 +15,21 @@
 
 #include "System.h"
 
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#else
+#ifndef _WIN32
+#include <unistd.h>
+#include <cstdio>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif
+#endif
+
+#include <iostream>
+
 #ifdef _WIN32
 
 extern "C" {
@@ -34,3 +49,70 @@
 }
 
 #endif
+
+ProcessStatus
+GetProcessStatus(int pid)
+{
+#ifdef __APPLE__
+
+    // See
+    // http://tuvix.apple.com/documentation/Darwin/Reference/ManPages/man3/sysctl.3.html
+    // http://developer.apple.com/qa/qa2001/qa1123.html
+
+    int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0, 0 };
+    name[3] = pid;
+
+    int err;
+    size_t length = 0;
+
+    if (sysctl(name, 4, 0, &length, 0, 0)) {
+        perror("GetProcessStatus: sysctl failed");
+        return UnknownProcessStatus;
+    }
+
+    if (length > 0) return ProcessRunning;
+    else return ProcessNotRunning;
+
+#elsif _WIN32
+
+    return UnknownProcessStatus;
+
+#else
+
+    char filename[50];
+    struct stat statbuf;
+
+    // Looking up the pid in /proc is worth a try on any POSIX system,
+    // I guess -- it'll always compile and it won't return false
+    // negatives if we do this first check:
+
+    sprintf(filename, "/proc/%d", (int)getpid());
+
+    int err = stat(filename, &statbuf);
+
+    if (err || !S_ISDIR(statbuf.st_mode)) {
+        // If we can't even use it to tell whether we're running or
+        // not, then clearly /proc is no use on this system.
+        return UnknownProcessStatus;
+    }
+
+    sprintf(filename, "/proc/%d", (int)pid);
+
+    err = stat(filename, &statbuf);
+
+    if (!err) {
+        if (S_ISDIR(statbuf.st_mode)) {
+            return ProcessRunning;
+        } else {
+            return UnknownProcessStatus;
+        }
+    } else if (errno == ENOENT) {
+        return ProcessNotRunning;
+    } else {
+        perror("stat failed");
+        return UnknownProcessStatus;
+    }
+
+#endif
+}
+
--- a/base/System.h	Thu May 04 20:17:28 2006 +0000
+++ b/base/System.h	Fri May 05 11:28:04 2006 +0000
@@ -68,6 +68,9 @@
 
 #endif /* ! _WIN32 */
 
+enum ProcessStatus { ProcessRunning, ProcessNotRunning, UnknownProcessStatus };
+extern ProcessStatus GetProcessStatus(int pid);
+
 #endif /* ! _SYSTEM_H_ */
 
 
--- a/base/TempDirectory.cpp	Thu May 04 20:17:28 2006 +0000
+++ b/base/TempDirectory.cpp	Fri May 05 11:28:04 2006 +0000
@@ -14,6 +14,7 @@
 */
 
 #include "TempDirectory.h"
+#include "System.h"
 
 #include <QDir>
 #include <QFile>
@@ -70,8 +71,29 @@
     
     if (m_tmpdir != "") return m_tmpdir;
 
-//!!!    QDir tempDirBase = QDir::temp();
-    QDir tempDirBase = QDir::home();
+    QString svDirBase = ".sv";
+    QString svDir = QDir::home().filePath(svDirBase);
+    if (!QFileInfo(svDir).exists()) {
+        if (!QDir::home().mkdir(svDirBase)) {
+            throw DirectoryCreationFailed(QString("%1 directory in $HOME")
+                                          .arg(svDirBase));
+        }
+    } else if (!QFileInfo(svDir).isDir()) {
+        throw DirectoryCreationFailed(QString("$HOME/%1 is not a directory")
+                                      .arg(svDirBase));
+    }
+
+    cleanupAbandonedDirectories(svDir);
+
+    return createTempDirectoryIn(svDir);
+}
+
+QString
+TempDirectory::createTempDirectoryIn(QString dir)
+{
+    // Entered with mutex held.
+
+    QDir tempDirBase(dir);
 
     // Generate a temporary directory.  Qt4.1 doesn't seem to be able
     // to do this for us, and mkdtemp is not standard.  This method is
@@ -112,6 +134,16 @@
                                       .arg(tempDirBase.canonicalPath()));
     }
 
+    QString pidpath = QDir(m_tmpdir).filePath(QString("%1.pid").arg(getpid()));
+    QFile pidfile(pidpath);
+
+    if (!pidfile.open(QIODevice::WriteOnly)) {
+        throw DirectoryCreationFailed(QString("pid file creation in %1")
+                                      .arg(m_tmpdir));
+    } else {
+        pidfile.close();
+    }
+
     return m_tmpdir;
 }
 
@@ -196,3 +228,35 @@
         m_mutex.unlock();
     }
 }
+
+void
+TempDirectory::cleanupAbandonedDirectories(QString svDir)
+{
+    QDir dir(svDir, "sv_*", QDir::Name, QDir::Dirs);
+
+    for (unsigned int i = 0; i < dir.count(); ++i) {
+        
+        QDir subdir(dir.filePath(dir[i]), "*.pid", QDir::Name, QDir::Files);
+
+        for (unsigned int j = 0; j < subdir.count(); ++j) {
+
+            bool ok = false;
+            int pid = QFileInfo(subdir[j]).baseName().toInt(&ok);
+            if (!ok) continue;
+
+            if (GetProcessStatus(pid) == ProcessNotRunning) {
+                std::cerr << "INFO: Found abandoned temporary directory from "
+                          << "an old Sonic Visualiser process\n(pid=" << pid
+                          << ", directory=\""
+                          << dir.filePath(dir[i]).toStdString()
+                          << "\").  Removing it..." << std::endl;
+                cleanupDirectory(dir.filePath(dir[i]));
+                std::cerr << "...done." << std::endl;
+                break;
+            }
+        }
+    }
+}
+
+
+        
--- a/base/TempDirectory.h	Thu May 04 20:17:28 2006 +0000
+++ b/base/TempDirectory.h	Fri May 05 11:28:04 2006 +0000
@@ -70,7 +70,11 @@
 
 protected:
     TempDirectory();
+
+    QString createTempDirectoryIn(QString inDir);
     void cleanupDirectory(QString tmpDir);
+    void cleanupAbandonedDirectories(QString svDir);
+
     QString m_tmpdir;
     QMutex m_mutex;