mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-07 12:21:27 +01:00
Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/57566 Fix the problem that `tempfile` has never been deleted even after `torch_shm_manager` is destroyed. - The previous implementation has wrong path length for the Linux Socket. It leads to we lose the last character of the name of `tempfile` when bind the pathname to socket. At the end, we can not delete this file due to unexpected file name. - After we solve the racing problem by introducing a temporary directory, it becomes more dangerous since it prevents `torch_shm_manager` to delete directory as the tempfile persists in the temporary directory. Test Plan: Imported from OSS Reviewed By: VitalyFedyunin Differential Revision: D28202866 Pulled By: ejguan fbshipit-source-id: 912cfd8fec0cc309d47df223b2b0faa599c60799
201 lines
5.9 KiB
C++
201 lines
5.9 KiB
C++
#pragma once
|
|
|
|
#include <c10/util/Exception.h>
|
|
#include <c10/util/Optional.h>
|
|
|
|
#include <cerrno>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#if !defined(_WIN32)
|
|
#include <unistd.h>
|
|
#else // defined(_WIN32)
|
|
#include <Windows.h>
|
|
#include <fileapi.h>
|
|
#endif // defined(_WIN32)
|
|
|
|
namespace c10 {
|
|
namespace detail {
|
|
// Creates the filename pattern passed to and completed by `mkstemp`.
|
|
// Returns std::vector<char> because `mkstemp` needs a (non-const) `char*` and
|
|
// `std::string` only provides `const char*` before C++17.
|
|
#if !defined(_WIN32)
|
|
inline std::vector<char> make_filename(std::string name_prefix) {
|
|
// The filename argument to `mkstemp` needs "XXXXXX" at the end according to
|
|
// http://pubs.opengroup.org/onlinepubs/009695399/functions/mkstemp.html
|
|
static const std::string kRandomPattern = "XXXXXX";
|
|
|
|
// We see if any of these environment variables is set and use their value, or
|
|
// else default the temporary directory to `/tmp`.
|
|
static const char* env_variables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
|
|
|
|
std::string tmp_directory = "/tmp";
|
|
for (const char* variable : env_variables) {
|
|
if (const char* path = getenv(variable)) {
|
|
tmp_directory = path;
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::vector<char> filename;
|
|
filename.reserve(
|
|
tmp_directory.size() + name_prefix.size() + kRandomPattern.size() + 2);
|
|
|
|
filename.insert(filename.end(), tmp_directory.begin(), tmp_directory.end());
|
|
filename.push_back('/');
|
|
filename.insert(filename.end(), name_prefix.begin(), name_prefix.end());
|
|
filename.insert(filename.end(), kRandomPattern.begin(), kRandomPattern.end());
|
|
filename.push_back('\0');
|
|
|
|
return filename;
|
|
}
|
|
#endif // !defined(_WIN32)
|
|
} // namespace detail
|
|
|
|
struct TempFile {
|
|
#if !defined(_WIN32)
|
|
TempFile() : fd(-1) {}
|
|
TempFile(std::string name, int fd) : fd(fd), name(std::move(name)) {}
|
|
TempFile(const TempFile&) = delete;
|
|
TempFile(TempFile&& other) noexcept
|
|
: fd(other.fd), name(std::move(other.name)) {
|
|
other.fd = -1;
|
|
other.name.clear();
|
|
}
|
|
|
|
TempFile& operator=(const TempFile&) = delete;
|
|
TempFile& operator=(TempFile&& other) {
|
|
fd = other.fd;
|
|
name = std::move(other.name);
|
|
other.fd = -1;
|
|
other.name.clear();
|
|
return *this;
|
|
}
|
|
|
|
~TempFile() {
|
|
if (fd >= 0) {
|
|
unlink(name.c_str());
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
int fd;
|
|
#endif // !defined(_WIN32)
|
|
|
|
std::string name;
|
|
};
|
|
|
|
struct TempDir {
|
|
TempDir() = default;
|
|
explicit TempDir(std::string name) : name(std::move(name)) {}
|
|
TempDir(const TempDir&) = delete;
|
|
TempDir(TempDir&& other) noexcept : name(std::move(other.name)) {
|
|
other.name.clear();
|
|
}
|
|
|
|
TempDir& operator=(const TempDir&) = delete;
|
|
TempDir& operator=(TempDir&& other) {
|
|
name = std::move(other.name);
|
|
other.name.clear();
|
|
return *this;
|
|
}
|
|
|
|
~TempDir() {
|
|
if (!name.empty()) {
|
|
#if !defined(_WIN32)
|
|
rmdir(name.c_str());
|
|
#else // defined(_WIN32)
|
|
RemoveDirectoryA(name.c_str());
|
|
#endif // defined(_WIN32)
|
|
}
|
|
}
|
|
|
|
std::string name;
|
|
};
|
|
|
|
/// Attempts to return a temporary file or returns `nullopt` if an error
|
|
/// occurred.
|
|
///
|
|
/// The file returned follows the pattern
|
|
/// `<tmp-dir>/<name-prefix><random-pattern>`, where `<tmp-dir>` is the value of
|
|
/// the `"TMPDIR"`, `"TMP"`, `"TEMP"` or
|
|
/// `"TEMPDIR"` environment variable if any is set, or otherwise `/tmp`;
|
|
/// `<name-prefix>` is the value supplied to this function, and
|
|
/// `<random-pattern>` is a random sequence of numbers.
|
|
/// On Windows, `name_prefix` is ignored and `tmpnam` is used.
|
|
inline c10::optional<TempFile> try_make_tempfile(
|
|
std::string name_prefix = "torch-file-") {
|
|
#if defined(_WIN32)
|
|
return TempFile{std::tmpnam(nullptr)};
|
|
#else
|
|
std::vector<char> filename = detail::make_filename(std::move(name_prefix));
|
|
const int fd = mkstemp(filename.data());
|
|
if (fd == -1) {
|
|
return c10::nullopt;
|
|
}
|
|
// Don't make the string from string(filename.begin(), filename.end(), or
|
|
// there will be a trailing '\0' at the end.
|
|
return TempFile(filename.data(), fd);
|
|
#endif // defined(_WIN32)
|
|
}
|
|
|
|
/// Like `try_make_tempfile`, but throws an exception if a temporary file could
|
|
/// not be returned.
|
|
inline TempFile make_tempfile(std::string name_prefix = "torch-file-") {
|
|
if (auto tempfile = try_make_tempfile(std::move(name_prefix))) {
|
|
return std::move(*tempfile);
|
|
}
|
|
TORCH_CHECK(false, "Error generating temporary file: ", std::strerror(errno));
|
|
}
|
|
|
|
/// Attempts to return a temporary directory or returns `nullopt` if an error
|
|
/// occurred.
|
|
///
|
|
/// The directory returned follows the pattern
|
|
/// `<tmp-dir>/<name-prefix><random-pattern>/`, where `<tmp-dir>` is the value
|
|
/// of the `"TMPDIR"`, `"TMP"`, `"TEMP"` or
|
|
/// `"TEMPDIR"` environment variable if any is set, or otherwise `/tmp`;
|
|
/// `<name-prefix>` is the value supplied to this function, and
|
|
/// `<random-pattern>` is a random sequence of numbers.
|
|
/// On Windows, `name_prefix` is ignored and `tmpnam` is used.
|
|
inline c10::optional<TempDir> try_make_tempdir(
|
|
std::string name_prefix = "torch-dir-") {
|
|
#if defined(_WIN32)
|
|
while (true) {
|
|
const char* dirname = std::tmpnam(nullptr);
|
|
if (!dirname) {
|
|
return c10::nullopt;
|
|
}
|
|
if (CreateDirectoryA(dirname, NULL)) {
|
|
return TempDir(dirname);
|
|
}
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
return c10::nullopt;
|
|
}
|
|
}
|
|
return c10::nullopt;
|
|
#else
|
|
std::vector<char> filename = detail::make_filename(std::move(name_prefix));
|
|
const char* dirname = mkdtemp(filename.data());
|
|
if (!dirname) {
|
|
return c10::nullopt;
|
|
}
|
|
return TempDir(dirname);
|
|
#endif // defined(_WIN32)
|
|
}
|
|
|
|
/// Like `try_make_tempdir`, but throws an exception if a temporary directory
|
|
/// could not be returned.
|
|
inline TempDir make_tempdir(std::string name_prefix = "torch-dir-") {
|
|
if (auto tempdir = try_make_tempdir(std::move(name_prefix))) {
|
|
return std::move(*tempdir);
|
|
}
|
|
TORCH_CHECK(
|
|
false, "Error generating temporary directory: ", std::strerror(errno));
|
|
}
|
|
} // namespace c10
|