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