mirror of https://github.com/roytam1/kmeleon.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
688 lines
20 KiB
688 lines
20 KiB
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
/* This Source Code Form is subject to the terms of the Mozilla Public |
|
* License, v. 2.0. If a copy of the MPL was not distributed with this |
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
|
|
#ifndef _NONAFX |
|
#include "StdAfx.h" |
|
#else |
|
#include "winEmbed.h" |
|
#endif |
|
#include "nsProfileStringTypes.h" |
|
#include "nsProfileLock.h" |
|
#include "nsCOMPtr.h" |
|
|
|
#if defined(XP_MACOSX) |
|
#include <Carbon/Carbon.h> |
|
#include <CoreFoundation/CoreFoundation.h> |
|
#endif |
|
|
|
#ifdef XP_UNIX |
|
#include <unistd.h> |
|
#include <fcntl.h> |
|
#include <errno.h> |
|
#include <signal.h> |
|
#include <stdlib.h> |
|
#include "prnetdb.h" |
|
#include "prsystem.h" |
|
#include "prprf.h" |
|
#include "prenv.h" |
|
#endif |
|
|
|
#ifdef VMS |
|
#include <rmsdef.h> |
|
#endif |
|
|
|
// ********************************************************************** |
|
// class nsProfileLock |
|
// |
|
// This code was moved from profile/src/nsProfileAccess. |
|
// ********************************************************************** |
|
|
|
#if defined (XP_UNIX) |
|
static bool sDisableSignalHandling = false; |
|
#endif |
|
|
|
nsProfileLock::nsProfileLock() : |
|
mHaveLock(false), |
|
mReplacedLockTime(0) |
|
#if defined (XP_WIN) |
|
,mLockFileHandle(INVALID_HANDLE_VALUE) |
|
#elif defined (XP_OS2) |
|
,mLockFileHandle(-1) |
|
#elif defined (XP_UNIX) |
|
,mPidLockFileName(nullptr) |
|
,mLockFileDesc(-1) |
|
#endif |
|
{ |
|
#if defined (XP_UNIX) |
|
next = prev = this; |
|
sDisableSignalHandling = PR_GetEnv("MOZ_DISABLE_SIG_HANDLER") ? true : false; |
|
#endif |
|
} |
|
|
|
|
|
nsProfileLock::nsProfileLock(nsProfileLock& src) |
|
{ |
|
*this = src; |
|
} |
|
|
|
|
|
nsProfileLock& nsProfileLock::operator=(nsProfileLock& rhs) |
|
{ |
|
Unlock(); |
|
|
|
mHaveLock = rhs.mHaveLock; |
|
rhs.mHaveLock = false; |
|
|
|
#if defined (XP_WIN) |
|
mLockFileHandle = rhs.mLockFileHandle; |
|
rhs.mLockFileHandle = INVALID_HANDLE_VALUE; |
|
#elif defined (XP_OS2) |
|
mLockFileHandle = rhs.mLockFileHandle; |
|
rhs.mLockFileHandle = -1; |
|
#elif defined (XP_UNIX) |
|
mLockFileDesc = rhs.mLockFileDesc; |
|
rhs.mLockFileDesc = -1; |
|
mPidLockFileName = rhs.mPidLockFileName; |
|
rhs.mPidLockFileName = nullptr; |
|
if (mPidLockFileName) |
|
{ |
|
// rhs had a symlink lock, therefore it was on the list. |
|
PR_REMOVE_LINK(&rhs); |
|
PR_APPEND_LINK(this, &mPidLockList); |
|
} |
|
#endif |
|
|
|
return *this; |
|
} |
|
|
|
|
|
nsProfileLock::~nsProfileLock() |
|
{ |
|
Unlock(); |
|
} |
|
|
|
|
|
#if defined (XP_UNIX) |
|
|
|
static int setupPidLockCleanup; |
|
|
|
PRCList nsProfileLock::mPidLockList = |
|
PR_INIT_STATIC_CLIST(&nsProfileLock::mPidLockList); |
|
|
|
void nsProfileLock::RemovePidLockFiles(bool aFatalSignal) |
|
{ |
|
while (!PR_CLIST_IS_EMPTY(&mPidLockList)) |
|
{ |
|
nsProfileLock *lock = static_cast<nsProfileLock*>(mPidLockList.next); |
|
lock->Unlock(aFatalSignal); |
|
} |
|
} |
|
|
|
static struct sigaction SIGHUP_oldact; |
|
static struct sigaction SIGINT_oldact; |
|
static struct sigaction SIGQUIT_oldact; |
|
static struct sigaction SIGILL_oldact; |
|
static struct sigaction SIGABRT_oldact; |
|
static struct sigaction SIGSEGV_oldact; |
|
static struct sigaction SIGTERM_oldact; |
|
|
|
void nsProfileLock::FatalSignalHandler(int signo |
|
#ifdef SA_SIGINFO |
|
, siginfo_t *info, void *context |
|
#endif |
|
) |
|
{ |
|
// Remove any locks still held. |
|
RemovePidLockFiles(true); |
|
|
|
// Chain to the old handler, which may exit. |
|
struct sigaction *oldact = nullptr; |
|
|
|
switch (signo) { |
|
case SIGHUP: |
|
oldact = &SIGHUP_oldact; |
|
break; |
|
case SIGINT: |
|
oldact = &SIGINT_oldact; |
|
break; |
|
case SIGQUIT: |
|
oldact = &SIGQUIT_oldact; |
|
break; |
|
case SIGILL: |
|
oldact = &SIGILL_oldact; |
|
break; |
|
case SIGABRT: |
|
oldact = &SIGABRT_oldact; |
|
break; |
|
case SIGSEGV: |
|
oldact = &SIGSEGV_oldact; |
|
break; |
|
case SIGTERM: |
|
oldact = &SIGTERM_oldact; |
|
break; |
|
default: |
|
NS_NOTREACHED("bad signo"); |
|
break; |
|
} |
|
|
|
if (oldact) { |
|
if (oldact->sa_handler == SIG_DFL) { |
|
// Make sure the default sig handler is executed |
|
// We need it to get Mozilla to dump core. |
|
sigaction(signo,oldact, nullptr); |
|
|
|
// Now that we've restored the default handler, unmask the |
|
// signal and invoke it. |
|
|
|
sigset_t unblock_sigs; |
|
sigemptyset(&unblock_sigs); |
|
sigaddset(&unblock_sigs, signo); |
|
|
|
sigprocmask(SIG_UNBLOCK, &unblock_sigs, nullptr); |
|
|
|
raise(signo); |
|
} |
|
#ifdef SA_SIGINFO |
|
else if (oldact->sa_sigaction && |
|
(oldact->sa_flags & SA_SIGINFO) == SA_SIGINFO) { |
|
oldact->sa_sigaction(signo, info, context); |
|
} |
|
#endif |
|
else if (oldact->sa_handler && oldact->sa_handler != SIG_IGN) |
|
{ |
|
oldact->sa_handler(signo); |
|
} |
|
} |
|
|
|
// Backstop exit call, just in case. |
|
_exit(signo); |
|
} |
|
|
|
nsresult nsProfileLock::LockWithFcntl(nsIFile *aLockFile) |
|
{ |
|
nsresult rv = NS_OK; |
|
|
|
nsAutoCString lockFilePath; |
|
rv = aLockFile->GetNativePath(lockFilePath); |
|
if (NS_FAILED(rv)) { |
|
NS_ERROR("Could not get native path"); |
|
return rv; |
|
} |
|
|
|
aLockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
|
|
mLockFileDesc = open(lockFilePath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0666); |
|
if (mLockFileDesc != -1) |
|
{ |
|
struct flock lock; |
|
lock.l_start = 0; |
|
lock.l_len = 0; // len = 0 means entire file |
|
lock.l_type = F_WRLCK; |
|
lock.l_whence = SEEK_SET; |
|
|
|
// If fcntl(F_GETLK) fails then the server does not support/allow fcntl(), |
|
// return failure rather than access denied in this case so we fallback |
|
// to using a symlink lock, bug 303633. |
|
struct flock testlock = lock; |
|
if (fcntl(mLockFileDesc, F_GETLK, &testlock) == -1) |
|
{ |
|
close(mLockFileDesc); |
|
mLockFileDesc = -1; |
|
rv = NS_ERROR_FAILURE; |
|
} |
|
else if (fcntl(mLockFileDesc, F_SETLK, &lock) == -1) |
|
{ |
|
close(mLockFileDesc); |
|
mLockFileDesc = -1; |
|
|
|
// With OS X, on NFS, errno == ENOTSUP |
|
// XXX Check for that and return specific rv for it? |
|
#ifdef DEBUG |
|
printf("fcntl(F_SETLK) failed. errno = %d\n", errno); |
|
#endif |
|
if (errno == EAGAIN || errno == EACCES) |
|
rv = NS_ERROR_FILE_ACCESS_DENIED; |
|
else |
|
rv = NS_ERROR_FAILURE; |
|
} |
|
else |
|
mHaveLock = true; |
|
} |
|
else |
|
{ |
|
NS_ERROR("Failed to open lock file."); |
|
rv = NS_ERROR_FAILURE; |
|
} |
|
return rv; |
|
} |
|
|
|
static bool IsSymlinkStaleLock(struct in_addr* aAddr, const char* aFileName, |
|
bool aHaveFcntlLock) |
|
{ |
|
// the link exists; see if it's from this machine, and if |
|
// so if the process is still active |
|
char buf[1024]; |
|
int len = readlink(aFileName, buf, sizeof buf - 1); |
|
if (len > 0) |
|
{ |
|
buf[len] = '\0'; |
|
char *colon = strchr(buf, ':'); |
|
if (colon) |
|
{ |
|
*colon++ = '\0'; |
|
unsigned long addr = inet_addr(buf); |
|
if (addr != (unsigned long) -1) |
|
{ |
|
if (colon[0] == '+' && aHaveFcntlLock) { |
|
// This lock was placed by a Firefox build which would have |
|
// taken the fnctl lock, and we've already taken the fcntl lock, |
|
// so the process that created this obsolete lock must be gone |
|
return true; |
|
} |
|
|
|
char *after = nullptr; |
|
pid_t pid = strtol(colon, &after, 0); |
|
if (pid != 0 && *after == '\0') |
|
{ |
|
if (addr != aAddr->s_addr) |
|
{ |
|
// Remote lock: give up even if stuck. |
|
return false; |
|
} |
|
|
|
// kill(pid,0) is a neat trick to check if a |
|
// process exists |
|
if (kill(pid, 0) == 0 || errno != ESRCH) |
|
{ |
|
// Local process appears to be alive, ass-u-me it |
|
// is another Mozilla instance, or a compatible |
|
// derivative, that's currently using the profile. |
|
// XXX need an "are you Mozilla?" protocol |
|
return false; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
nsresult nsProfileLock::LockWithSymlink(nsIFile *aLockFile, bool aHaveFcntlLock) |
|
{ |
|
nsresult rv; |
|
nsAutoCString lockFilePath; |
|
rv = aLockFile->GetNativePath(lockFilePath); |
|
if (NS_FAILED(rv)) { |
|
NS_ERROR("Could not get native path"); |
|
return rv; |
|
} |
|
|
|
// don't replace an existing lock time if fcntl already got one |
|
if (!mReplacedLockTime) |
|
aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime); |
|
|
|
struct in_addr inaddr; |
|
inaddr.s_addr = htonl(INADDR_LOOPBACK); |
|
|
|
char hostname[256]; |
|
PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname); |
|
if (status == PR_SUCCESS) |
|
{ |
|
char netdbbuf[PR_NETDB_BUF_SIZE]; |
|
PRHostEnt hostent; |
|
status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent); |
|
if (status == PR_SUCCESS) |
|
memcpy(&inaddr, hostent.h_addr, sizeof inaddr); |
|
} |
|
|
|
char *signature = |
|
PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "", |
|
(unsigned long)getpid()); |
|
const char *fileName = lockFilePath.get(); |
|
int symlink_rv, symlink_errno = 0, tries = 0; |
|
|
|
// use ns4.x-compatible symlinks if the FS supports them |
|
while ((symlink_rv = symlink(signature, fileName)) < 0) |
|
{ |
|
symlink_errno = errno; |
|
if (symlink_errno != EEXIST) |
|
break; |
|
|
|
if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock)) |
|
break; |
|
|
|
// Lock seems to be bogus: try to claim it. Give up after a large |
|
// number of attempts (100 comes from the 4.x codebase). |
|
(void) unlink(fileName); |
|
if (++tries > 100) |
|
break; |
|
} |
|
|
|
PR_smprintf_free(signature); |
|
signature = nullptr; |
|
|
|
if (symlink_rv == 0) |
|
{ |
|
// We exclusively created the symlink: record its name for eventual |
|
// unlock-via-unlink. |
|
rv = NS_OK; |
|
mHaveLock = true; |
|
mPidLockFileName = strdup(fileName); |
|
if (mPidLockFileName) |
|
{ |
|
PR_APPEND_LINK(this, &mPidLockList); |
|
if (!setupPidLockCleanup++) |
|
{ |
|
// Clean up on normal termination. |
|
// This instanciates a dummy class, and will trigger the class |
|
// destructor when libxul is unloaded. This is equivalent to atexit(), |
|
// but gracefully handles dlclose(). |
|
static RemovePidLockFilesExiting r; |
|
|
|
// Clean up on abnormal termination, using POSIX sigaction. |
|
// Don't arm a handler if the signal is being ignored, e.g., |
|
// because mozilla is run via nohup. |
|
if (!sDisableSignalHandling) { |
|
struct sigaction act, oldact; |
|
#ifdef SA_SIGINFO |
|
act.sa_sigaction = FatalSignalHandler; |
|
act.sa_flags = SA_SIGINFO; |
|
#else |
|
act.sa_handler = FatalSignalHandler; |
|
#endif |
|
sigfillset(&act.sa_mask); |
|
|
|
#define CATCH_SIGNAL(signame) \ |
|
PR_BEGIN_MACRO \ |
|
if (sigaction(signame, nullptr, &oldact) == 0 && \ |
|
oldact.sa_handler != SIG_IGN) \ |
|
{ \ |
|
sigaction(signame, &act, &signame##_oldact); \ |
|
} \ |
|
PR_END_MACRO |
|
|
|
CATCH_SIGNAL(SIGHUP); |
|
CATCH_SIGNAL(SIGINT); |
|
CATCH_SIGNAL(SIGQUIT); |
|
CATCH_SIGNAL(SIGILL); |
|
CATCH_SIGNAL(SIGABRT); |
|
CATCH_SIGNAL(SIGSEGV); |
|
CATCH_SIGNAL(SIGTERM); |
|
|
|
#undef CATCH_SIGNAL |
|
} |
|
} |
|
} |
|
} |
|
else if (symlink_errno == EEXIST) |
|
rv = NS_ERROR_FILE_ACCESS_DENIED; |
|
else |
|
{ |
|
#ifdef DEBUG |
|
printf("symlink() failed. errno = %d\n", errno); |
|
#endif |
|
rv = NS_ERROR_FAILURE; |
|
} |
|
return rv; |
|
} |
|
#endif /* XP_UNIX */ |
|
|
|
nsresult nsProfileLock::GetReplacedLockTime(PRTime *aResult) { |
|
*aResult = mReplacedLockTime; |
|
return NS_OK; |
|
} |
|
|
|
nsresult nsProfileLock::Lock(nsIFile* aProfileDir, |
|
nsIProfileUnlocker* *aUnlocker) |
|
{ |
|
#if defined (XP_MACOSX) |
|
NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); |
|
NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock"); |
|
#elif defined (XP_UNIX) |
|
NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock"); |
|
NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); |
|
#else |
|
NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, "parent.lock"); |
|
#endif |
|
|
|
nsresult rv; |
|
if (aUnlocker) |
|
*aUnlocker = nullptr; |
|
|
|
NS_ENSURE_STATE(!mHaveLock); |
|
|
|
bool isDir; |
|
rv = aProfileDir->IsDirectory(&isDir); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
if (!isDir) |
|
return NS_ERROR_FILE_NOT_DIRECTORY; |
|
|
|
nsCOMPtr<nsIFile> lockFile; |
|
rv = aProfileDir->Clone(getter_AddRefs(lockFile)); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
|
|
rv = lockFile->Append(LOCKFILE_NAME); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
|
|
#if defined(XP_MACOSX) |
|
// First, try locking using fcntl. It is more reliable on |
|
// a local machine, but may not be supported by an NFS server. |
|
|
|
rv = LockWithFcntl(lockFile); |
|
if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED)) |
|
{ |
|
// If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, |
|
// assume we tried an NFS that does not support it. Now, try with symlink. |
|
rv = LockWithSymlink(lockFile, false); |
|
} |
|
|
|
if (NS_SUCCEEDED(rv)) |
|
{ |
|
// Check for the old-style lock used by pre-mozilla 1.3 builds. |
|
// Those builds used an earlier check to prevent the application |
|
// from launching if another instance was already running. Because |
|
// of that, we don't need to create an old-style lock as well. |
|
struct LockProcessInfo |
|
{ |
|
ProcessSerialNumber psn; |
|
unsigned long launchDate; |
|
}; |
|
|
|
PRFileDesc *fd = nullptr; |
|
int32_t ioBytes; |
|
ProcessInfoRec processInfo; |
|
LockProcessInfo lockProcessInfo; |
|
|
|
rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); |
|
if (NS_SUCCEEDED(rv)) |
|
{ |
|
ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo)); |
|
PR_Close(fd); |
|
|
|
if (ioBytes == sizeof(LockProcessInfo)) |
|
{ |
|
#ifdef __LP64__ |
|
processInfo.processAppRef = nullptr; |
|
#else |
|
processInfo.processAppSpec = nullptr; |
|
#endif |
|
processInfo.processName = nullptr; |
|
processInfo.processInfoLength = sizeof(ProcessInfoRec); |
|
if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr && |
|
processInfo.processLaunchDate == lockProcessInfo.launchDate) |
|
{ |
|
return NS_ERROR_FILE_ACCESS_DENIED; |
|
} |
|
} |
|
else |
|
{ |
|
NS_WARNING("Could not read lock file - ignoring lock"); |
|
} |
|
} |
|
rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc. |
|
} |
|
#elif defined(XP_UNIX) |
|
// Get the old lockfile name |
|
nsCOMPtr<nsIFile> oldLockFile; |
|
rv = aProfileDir->Clone(getter_AddRefs(oldLockFile)); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
rv = oldLockFile->Append(OLD_LOCKFILE_NAME); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
|
|
// First, try locking using fcntl. It is more reliable on |
|
// a local machine, but may not be supported by an NFS server. |
|
rv = LockWithFcntl(lockFile); |
|
if (NS_SUCCEEDED(rv)) { |
|
// Check to see whether there is a symlink lock held by an older |
|
// Firefox build, and also place our own symlink lock --- but |
|
// mark it "obsolete" so that other newer builds can break the lock |
|
// if they obtain the fcntl lock |
|
rv = LockWithSymlink(oldLockFile, true); |
|
|
|
// If the symlink failed for some reason other than it already |
|
// exists, then something went wrong e.g. the file system |
|
// doesn't support symlinks, or we don't have permission to |
|
// create a symlink there. In such cases we should just |
|
// continue because it's unlikely there is an old build |
|
// running with a symlink there and we've already successfully |
|
// placed a fcntl lock. |
|
if (rv != NS_ERROR_FILE_ACCESS_DENIED) |
|
rv = NS_OK; |
|
} |
|
else if (rv != NS_ERROR_FILE_ACCESS_DENIED) |
|
{ |
|
// If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, |
|
// assume we tried an NFS that does not support it. Now, try with symlink |
|
// using the old symlink path |
|
rv = LockWithSymlink(oldLockFile, false); |
|
} |
|
|
|
#elif defined(XP_WIN) |
|
nsAutoString filePath; |
|
rv = lockFile->GetPath(filePath); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
|
|
lockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
|
|
// always create the profile lock and never delete it so we can use its |
|
// modification timestamp to detect startup crashes |
|
mLockFileHandle = CreateFileW(filePath.get(), |
|
GENERIC_READ | GENERIC_WRITE, |
|
0, // no sharing - of course |
|
nullptr, |
|
CREATE_ALWAYS, |
|
0, |
|
nullptr); |
|
if (mLockFileHandle == INVALID_HANDLE_VALUE) { |
|
// XXXbsmedberg: provide a profile-unlocker here! |
|
return NS_ERROR_FILE_ACCESS_DENIED; |
|
} |
|
#elif defined(XP_OS2) |
|
nsAutoCString filePath; |
|
rv = lockFile->GetNativePath(filePath); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
|
|
lockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
|
|
ULONG ulAction = 0; |
|
APIRET rc; |
|
rc = DosOpen(filePath.get(), |
|
&mLockFileHandle, |
|
&ulAction, |
|
0, |
|
FILE_NORMAL, |
|
OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, |
|
OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_NOINHERIT, |
|
0 ); |
|
if (rc != NO_ERROR) |
|
{ |
|
mLockFileHandle = -1; |
|
return NS_ERROR_FILE_ACCESS_DENIED; |
|
} |
|
#elif defined(VMS) |
|
nsAutoCString filePath; |
|
rv = lockFile->GetNativePath(filePath); |
|
if (NS_FAILED(rv)) |
|
return rv; |
|
|
|
lockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
|
|
mLockFileDesc = open_noshr(filePath.get(), O_CREAT, 0666); |
|
if (mLockFileDesc == -1) |
|
{ |
|
if ((errno == EVMSERR) && (vaxc$errno == RMS$_FLK)) |
|
{ |
|
return NS_ERROR_FILE_ACCESS_DENIED; |
|
} |
|
else |
|
{ |
|
NS_ERROR("Failed to open lock file."); |
|
return NS_ERROR_FAILURE; |
|
} |
|
} |
|
#endif |
|
|
|
mHaveLock = true; |
|
|
|
return rv; |
|
} |
|
|
|
|
|
nsresult nsProfileLock::Unlock(bool aFatalSignal) |
|
{ |
|
nsresult rv = NS_OK; |
|
|
|
if (mHaveLock) |
|
{ |
|
#if defined (XP_WIN) |
|
if (mLockFileHandle != INVALID_HANDLE_VALUE) |
|
{ |
|
CloseHandle(mLockFileHandle); |
|
mLockFileHandle = INVALID_HANDLE_VALUE; |
|
} |
|
#elif defined (XP_OS2) |
|
if (mLockFileHandle != -1) |
|
{ |
|
DosClose(mLockFileHandle); |
|
mLockFileHandle = -1; |
|
} |
|
#elif defined (XP_UNIX) |
|
if (mPidLockFileName) |
|
{ |
|
PR_REMOVE_LINK(this); |
|
(void) unlink(mPidLockFileName); |
|
|
|
// Only free mPidLockFileName if we're not in the fatal signal |
|
// handler. The problem is that a call to free() might be the |
|
// cause of this fatal signal. If so, calling free() might cause |
|
// us to wait on the malloc implementation's lock. We're already |
|
// holding this lock, so we'll deadlock. See bug 522332. |
|
if (!aFatalSignal) |
|
free(mPidLockFileName); |
|
mPidLockFileName = nullptr; |
|
} |
|
else if (mLockFileDesc != -1) |
|
{ |
|
close(mLockFileDesc); |
|
mLockFileDesc = -1; |
|
// Don't remove it |
|
} |
|
#endif |
|
|
|
mHaveLock = false; |
|
} |
|
|
|
return rv; |
|
}
|
|
|