diff --git a/renderdoc/common/common.cpp b/renderdoc/common/common.cpp index 2b9d71dd7..0f6bc5cde 100644 --- a/renderdoc/common/common.cpp +++ b/renderdoc/common/common.cpp @@ -293,7 +293,7 @@ uint64_t Log2Floor(uint64_t value) #endif static std::string logfile; -static bool logfileOpened = false; +static FileIO::LogFileHandle *logfileHandle = NULL; const char *rdclog_getfilename() { @@ -308,21 +308,22 @@ void rdclog_filename(const char *filename) if(filename && filename[0]) logfile = filename; - FileIO::logfile_close(NULL); + FileIO::logfile_close(logfileHandle, NULL); - logfileOpened = false; + logfileHandle = NULL; if(!logfile.empty()) { - logfileOpened = FileIO::logfile_open(logfile.c_str()); + logfileHandle = FileIO::logfile_open(logfile.c_str()); - if(logfileOpened && previous.c_str()) + if(logfileHandle && previous.c_str()) { std::vector previousContents; FileIO::slurp(previous.c_str(), previousContents); if(!previousContents.empty()) - FileIO::logfile_append((const char *)&previousContents[0], previousContents.size()); + FileIO::logfile_append(logfileHandle, (const char *)&previousContents[0], + previousContents.size()); FileIO::Delete(previous.c_str()); } @@ -339,7 +340,7 @@ void rdclog_enableoutput() void rdclog_closelog(const char *filename) { log_output_enabled = false; - FileIO::logfile_close(filename); + FileIO::logfile_close(logfileHandle, filename); } void rdclog_flush() @@ -366,10 +367,10 @@ void rdclogprint_int(LogType type, const char *fullMsg, const char *msg) OSUtility::WriteOutput(OSUtility::Output_StdErr, msg); #endif #if ENABLED(OUTPUT_LOG_TO_DISK) - if(logfileOpened) + if(logfileHandle) { // strlen used as byte length - str is UTF-8 so this is NOT number of characters - FileIO::logfile_append(fullMsg, strlen(fullMsg)); + FileIO::logfile_append(logfileHandle, fullMsg, strlen(fullMsg)); } #endif } diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h index 54655152f..c088de5c4 100644 --- a/renderdoc/os/os_specific.h +++ b/renderdoc/os/os_specific.h @@ -311,9 +311,10 @@ int fclose(FILE *f); // functions for atomically appending to a log that may be in use in multiple // processes -bool logfile_open(const char *filename); -void logfile_append(const char *msg, size_t length); -void logfile_close(const char *filename); +struct LogFileHandle; +LogFileHandle *logfile_open(const char *filename); +void logfile_append(LogFileHandle *logHandle, const char *msg, size_t length); +void logfile_close(LogFileHandle *logHandle, const char *deleteFilename); // read the whole logfile into memory. This may race with processes writing, but it will read the // whole of the file at some point. Useful since normal file reading may fail on the shared logfile diff --git a/renderdoc/os/posix/posix_stringio.cpp b/renderdoc/os/posix/posix_stringio.cpp index 46dc8ceb4..7b3da5abe 100644 --- a/renderdoc/os/posix/posix_stringio.cpp +++ b/renderdoc/os/posix/posix_stringio.cpp @@ -471,15 +471,15 @@ bool exists(const char *filename) return (res == 0); } -static int logfileFD = -1; +rdcarray logfiles; // this is used in posix_process.cpp, so that we can close the handle any time that we fork() void ReleaseFDAfterFork() { // we do NOT release the shared lock here, since the file descriptor is shared so we'd be // releasing the parent process's lock. Just close our file descriptor - if(logfileFD >= 0) - close(logfileFD); + for(int log : logfiles) + close(log); } std::string logfile_readall(const char *filename) @@ -504,35 +504,49 @@ std::string logfile_readall(const char *filename) return ret; } -bool logfile_open(const char *filename) +LogFileHandle *logfile_open(const char *filename) { - logfileFD = open(filename, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + int fd = open(filename, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if(fd < 0) + { + RDCWARN("Couldn't open logfile '%s': %d", filename, (int)errno); + return NULL; + } + + logfiles.push_back(fd); // acquire a shared lock. Every process acquires a shared lock to the common logfile. Each time a // process shuts down and wants to close the logfile, it releases its shared lock and tries to // acquire an exclusive lock, to see if it can delete the file. See logfile_close. - int err = flock(logfileFD, LOCK_SH | LOCK_NB); + int err = flock(fd, LOCK_SH | LOCK_NB); if(err < 0) - RDCWARN("Couldn't acquire shared lock to %s: %d", filename, (int)errno); + RDCWARN("Couldn't acquire shared lock to '%s': %d", filename, (int)errno); - return logfileFD >= 0; + return (LogFileHandle *)(uintptr_t)fd; } -void logfile_append(const char *msg, size_t length) +void logfile_append(LogFileHandle *logHandle, const char *msg, size_t length) { - if(logfileFD >= 0) - write(logfileFD, msg, (unsigned int)length); -} - -void logfile_close(const char *filename) -{ - if(logfileFD >= 0) + if(logHandle) { - // release our shared lock - int err = flock(logfileFD, LOCK_UN | LOCK_NB); + int fd = int(uintptr_t(logHandle) & 0xffffffff); - if(err == 0 && filename) + write(fd, msg, (unsigned int)length); + } +} + +void logfile_close(LogFileHandle *logHandle, const char *deleteFilename) +{ + if(logHandle) + { + int fd = int(uintptr_t(logHandle) & 0xffffffff); + + // release our shared lock + int err = flock(fd, LOCK_UN | LOCK_NB); + + if(err == 0 && deleteFilename) { // now try to acquire an exclusive lock. If this succeeds, no other processes are using the // file (since no other shared locks exist), so we can delete it. If it fails, some other @@ -540,20 +554,20 @@ void logfile_close(const char *filename) // NOTE: there is a race here between acquiring the exclusive lock and unlinking, but we // aren't interested in this kind of race - we're interested in whether an application is // still running when the UI closes, or vice versa, or similar cases. - err = flock(logfileFD, LOCK_EX | LOCK_NB); + err = flock(fd, LOCK_EX | LOCK_NB); if(err == 0) { // we got the exclusive lock. Now release it, close fd, and unlink the file - err = flock(logfileFD, LOCK_UN | LOCK_NB); + err = flock(fd, LOCK_UN | LOCK_NB); // can't really error handle here apart from retrying if(err != 0) - RDCWARN("Couldn't release exclusive lock to %s: %d", filename, (int)errno); + RDCWARN("Couldn't release exclusive lock to '%s': %d", deleteFilename, (int)errno); - close(logfileFD); + close(fd); - unlink(filename); + unlink(deleteFilename); // return immediately so we don't close again below. return; @@ -561,12 +575,14 @@ void logfile_close(const char *filename) } else { - RDCWARN("Couldn't release shared lock to %s: %d", filename, (int)errno); + RDCWARN("Couldn't release shared lock to '%s': %d", deleteFilename, (int)errno); // nothing to do, we won't try again, just exit. The log might lie around, but that's // relatively harmless. } - close(logfileFD); + logfiles.removeOne(fd); + + close(fd); } } }; diff --git a/renderdoc/os/win32/win32_stringio.cpp b/renderdoc/os/win32/win32_stringio.cpp index aee339129..86ea20e03 100644 --- a/renderdoc/os/win32/win32_stringio.cpp +++ b/renderdoc/os/win32/win32_stringio.cpp @@ -662,15 +662,12 @@ int fclose(FILE *f) return ::fclose(f); } -static HANDLE logHandle = NULL; - -bool logfile_open(const char *filename) +LogFileHandle *logfile_open(const char *filename) { std::wstring wfn = StringFormat::UTF82Wide(std::string(filename)); - logHandle = CreateFileW(wfn.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - return logHandle != NULL; + return (LogFileHandle *)CreateFileW(wfn.c_str(), FILE_APPEND_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); } static std::string logfile_readall_fallback(const wchar_t *filename) @@ -747,25 +744,24 @@ std::string logfile_readall(const char *filename) return ret; } -void logfile_append(const char *msg, size_t length) +void logfile_append(LogFileHandle *logHandle, const char *msg, size_t length) { if(logHandle) { DWORD bytesWritten = 0; - WriteFile(logHandle, msg, (DWORD)length, &bytesWritten, NULL); + WriteFile((HANDLE)logHandle, msg, (DWORD)length, &bytesWritten, NULL); } } -void logfile_close(const char *filename) +void logfile_close(LogFileHandle *logHandle, const char *deleteFilename) { - CloseHandle(logHandle); - logHandle = NULL; + CloseHandle((HANDLE)logHandle); - if(filename) + if(deleteFilename) { // we can just try to delete the file. If it's open elsewhere in another process, the delete // will fail. - std::wstring wpath = StringFormat::UTF82Wide(std::string(filename)); + std::wstring wpath = StringFormat::UTF82Wide(std::string(deleteFilename)); ::DeleteFileW(wpath.c_str()); } }