452 lines
13 KiB
C++
452 lines
13 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
#pragma once
|
|
|
|
#ifndef _WIN32
|
|
# define ARROW_HAVE_SIGACTION 1
|
|
#endif
|
|
|
|
#include <atomic>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#if ARROW_HAVE_SIGACTION
|
|
# include <csignal> // Needed for struct sigaction
|
|
#endif
|
|
|
|
#include "arrow/result.h"
|
|
#include "arrow/status.h"
|
|
#include "arrow/type_fwd.h"
|
|
#include "arrow/util/macros.h"
|
|
#include "arrow/util/windows_fixup.h"
|
|
|
|
namespace arrow::internal {
|
|
|
|
// NOTE: 8-bit path strings on Windows are encoded using UTF-8.
|
|
// Using MBCS would fail encoding some paths.
|
|
|
|
#if defined(_WIN32)
|
|
using NativePathString = std::wstring;
|
|
#else
|
|
using NativePathString = std::string;
|
|
#endif
|
|
|
|
class ARROW_EXPORT PlatformFilename {
|
|
public:
|
|
struct Impl;
|
|
|
|
~PlatformFilename();
|
|
PlatformFilename();
|
|
PlatformFilename(const PlatformFilename&);
|
|
PlatformFilename(PlatformFilename&&);
|
|
PlatformFilename& operator=(const PlatformFilename&);
|
|
PlatformFilename& operator=(PlatformFilename&&);
|
|
explicit PlatformFilename(NativePathString path);
|
|
explicit PlatformFilename(const NativePathString::value_type* path);
|
|
|
|
const NativePathString& ToNative() const;
|
|
std::string ToString() const;
|
|
|
|
PlatformFilename Parent() const;
|
|
Result<PlatformFilename> Real() const;
|
|
|
|
// These functions can fail for character encoding reasons.
|
|
static Result<PlatformFilename> FromString(std::string_view file_name);
|
|
Result<PlatformFilename> Join(std::string_view child_name) const;
|
|
|
|
PlatformFilename Join(const PlatformFilename& child_name) const;
|
|
|
|
bool operator==(const PlatformFilename& other) const;
|
|
bool operator!=(const PlatformFilename& other) const;
|
|
|
|
// Made public to avoid the proliferation of friend declarations.
|
|
const Impl* impl() const { return impl_.get(); }
|
|
|
|
private:
|
|
std::unique_ptr<Impl> impl_;
|
|
|
|
explicit PlatformFilename(Impl impl);
|
|
};
|
|
|
|
/// Create a directory if it doesn't exist.
|
|
///
|
|
/// Return whether the directory was created.
|
|
ARROW_EXPORT
|
|
Result<bool> CreateDir(const PlatformFilename& dir_path);
|
|
|
|
/// Create a directory and its parents if it doesn't exist.
|
|
///
|
|
/// Return whether the directory was created.
|
|
ARROW_EXPORT
|
|
Result<bool> CreateDirTree(const PlatformFilename& dir_path);
|
|
|
|
/// Delete a directory's contents (but not the directory itself) if it exists.
|
|
///
|
|
/// Return whether the directory existed.
|
|
ARROW_EXPORT
|
|
Result<bool> DeleteDirContents(const PlatformFilename& dir_path,
|
|
bool allow_not_found = true);
|
|
|
|
/// Delete a directory tree if it exists.
|
|
///
|
|
/// Return whether the directory existed.
|
|
ARROW_EXPORT
|
|
Result<bool> DeleteDirTree(const PlatformFilename& dir_path, bool allow_not_found = true);
|
|
|
|
// Non-recursively list the contents of the given directory.
|
|
// The returned names are the children's base names, not including dir_path.
|
|
ARROW_EXPORT
|
|
Result<std::vector<PlatformFilename>> ListDir(const PlatformFilename& dir_path);
|
|
|
|
/// Delete a file if it exists.
|
|
///
|
|
/// Return whether the file existed.
|
|
ARROW_EXPORT
|
|
Result<bool> DeleteFile(const PlatformFilename& file_path, bool allow_not_found = true);
|
|
|
|
/// Return whether a file exists.
|
|
ARROW_EXPORT
|
|
Result<bool> FileExists(const PlatformFilename& path);
|
|
|
|
// TODO expose this more publicly to make it available from io/file.h?
|
|
/// A RAII wrapper for a file descriptor.
|
|
///
|
|
/// The underlying file descriptor is automatically closed on destruction.
|
|
/// Moving is supported with well-defined semantics.
|
|
/// Furthermore, closing is idempotent.
|
|
class ARROW_EXPORT FileDescriptor {
|
|
public:
|
|
FileDescriptor() = default;
|
|
explicit FileDescriptor(int fd) : fd_(fd) {}
|
|
FileDescriptor(FileDescriptor&&);
|
|
FileDescriptor& operator=(FileDescriptor&&);
|
|
|
|
~FileDescriptor();
|
|
|
|
Status Close();
|
|
|
|
/// May return -1 if closed or default-initialized
|
|
int fd() const { return fd_.load(); }
|
|
|
|
/// Detach and return the underlying file descriptor
|
|
int Detach();
|
|
|
|
bool closed() const { return fd_.load() == -1; }
|
|
|
|
protected:
|
|
static void CloseFromDestructor(int fd);
|
|
|
|
std::atomic<int> fd_{-1};
|
|
};
|
|
|
|
/// Open a file for reading and return a file descriptor.
|
|
ARROW_EXPORT
|
|
Result<FileDescriptor> FileOpenReadable(const PlatformFilename& file_name);
|
|
|
|
/// Open a file for writing and return a file descriptor.
|
|
ARROW_EXPORT
|
|
Result<FileDescriptor> FileOpenWritable(const PlatformFilename& file_name,
|
|
bool write_only = true, bool truncate = true,
|
|
bool append = false);
|
|
|
|
/// Read from current file position. Return number of bytes read.
|
|
ARROW_EXPORT
|
|
Result<int64_t> FileRead(int fd, uint8_t* buffer, int64_t nbytes);
|
|
/// Read from given file position. Return number of bytes read.
|
|
ARROW_EXPORT
|
|
Result<int64_t> FileReadAt(int fd, uint8_t* buffer, int64_t position, int64_t nbytes);
|
|
|
|
ARROW_EXPORT
|
|
Status FileWrite(int fd, const uint8_t* buffer, const int64_t nbytes);
|
|
ARROW_EXPORT
|
|
Status FileTruncate(int fd, const int64_t size);
|
|
|
|
ARROW_EXPORT
|
|
Status FileSeek(int fd, int64_t pos);
|
|
ARROW_EXPORT
|
|
Status FileSeek(int fd, int64_t pos, int whence);
|
|
ARROW_EXPORT
|
|
Result<int64_t> FileTell(int fd);
|
|
ARROW_EXPORT
|
|
Result<int64_t> FileGetSize(int fd);
|
|
|
|
ARROW_EXPORT
|
|
Status FileClose(int fd);
|
|
|
|
struct Pipe {
|
|
FileDescriptor rfd;
|
|
FileDescriptor wfd;
|
|
|
|
Status Close() { return rfd.Close() & wfd.Close(); }
|
|
};
|
|
|
|
ARROW_EXPORT
|
|
Result<Pipe> CreatePipe();
|
|
|
|
ARROW_EXPORT
|
|
Status SetPipeFileDescriptorNonBlocking(int fd);
|
|
|
|
class ARROW_EXPORT SelfPipe {
|
|
public:
|
|
static Result<std::shared_ptr<SelfPipe>> Make(bool signal_safe);
|
|
virtual ~SelfPipe();
|
|
|
|
/// \brief Wait for a wakeup.
|
|
///
|
|
/// Status::Invalid is returned if the pipe has been shutdown.
|
|
/// Otherwise the next sent payload is returned.
|
|
virtual Result<uint64_t> Wait() = 0;
|
|
|
|
/// \brief Wake up the pipe by sending a payload.
|
|
///
|
|
/// This method is async-signal-safe if `signal_safe` was set to true.
|
|
virtual void Send(uint64_t payload) = 0;
|
|
|
|
/// \brief Wake up the pipe and shut it down.
|
|
virtual Status Shutdown() = 0;
|
|
};
|
|
|
|
ARROW_EXPORT
|
|
int64_t GetPageSize();
|
|
|
|
struct MemoryRegion {
|
|
void* addr;
|
|
size_t size;
|
|
};
|
|
|
|
ARROW_EXPORT
|
|
Status MemoryMapRemap(void* addr, size_t old_size, size_t new_size, int fildes,
|
|
void** new_addr);
|
|
ARROW_EXPORT
|
|
Status MemoryAdviseWillNeed(const std::vector<MemoryRegion>& regions);
|
|
|
|
ARROW_EXPORT
|
|
Result<std::string> GetEnvVar(const char* name);
|
|
ARROW_EXPORT
|
|
Result<std::string> GetEnvVar(const std::string& name);
|
|
ARROW_EXPORT
|
|
Result<NativePathString> GetEnvVarNative(const char* name);
|
|
ARROW_EXPORT
|
|
Result<NativePathString> GetEnvVarNative(const std::string& name);
|
|
|
|
ARROW_EXPORT
|
|
Status SetEnvVar(const char* name, const char* value);
|
|
ARROW_EXPORT
|
|
Status SetEnvVar(const std::string& name, const std::string& value);
|
|
ARROW_EXPORT
|
|
Status DelEnvVar(const char* name);
|
|
ARROW_EXPORT
|
|
Status DelEnvVar(const std::string& name);
|
|
|
|
ARROW_EXPORT
|
|
std::string ErrnoMessage(int errnum);
|
|
#if _WIN32
|
|
ARROW_EXPORT
|
|
std::string WinErrorMessage(int errnum);
|
|
#endif
|
|
|
|
ARROW_EXPORT
|
|
std::shared_ptr<StatusDetail> StatusDetailFromErrno(int errnum);
|
|
ARROW_EXPORT
|
|
std::optional<int> ErrnoFromStatusDetail(const StatusDetail& detail);
|
|
#if _WIN32
|
|
ARROW_EXPORT
|
|
std::shared_ptr<StatusDetail> StatusDetailFromWinError(int errnum);
|
|
#endif
|
|
ARROW_EXPORT
|
|
std::shared_ptr<StatusDetail> StatusDetailFromSignal(int signum);
|
|
|
|
template <typename... Args>
|
|
Status StatusFromErrno(int errnum, StatusCode code, Args&&... args) {
|
|
return Status::FromDetailAndArgs(code, StatusDetailFromErrno(errnum),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <typename... Args>
|
|
Status IOErrorFromErrno(int errnum, Args&&... args) {
|
|
return StatusFromErrno(errnum, StatusCode::IOError, std::forward<Args>(args)...);
|
|
}
|
|
|
|
#if _WIN32
|
|
template <typename... Args>
|
|
Status StatusFromWinError(int errnum, StatusCode code, Args&&... args) {
|
|
return Status::FromDetailAndArgs(code, StatusDetailFromWinError(errnum),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <typename... Args>
|
|
Status IOErrorFromWinError(int errnum, Args&&... args) {
|
|
return StatusFromWinError(errnum, StatusCode::IOError, std::forward<Args>(args)...);
|
|
}
|
|
#endif
|
|
|
|
template <typename... Args>
|
|
Status StatusFromSignal(int signum, StatusCode code, Args&&... args) {
|
|
return Status::FromDetailAndArgs(code, StatusDetailFromSignal(signum),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <typename... Args>
|
|
Status CancelledFromSignal(int signum, Args&&... args) {
|
|
return StatusFromSignal(signum, StatusCode::Cancelled, std::forward<Args>(args)...);
|
|
}
|
|
|
|
ARROW_EXPORT
|
|
int ErrnoFromStatus(const Status&);
|
|
|
|
// Always returns 0 on non-Windows platforms (for Python).
|
|
ARROW_EXPORT
|
|
int WinErrorFromStatus(const Status&);
|
|
|
|
ARROW_EXPORT
|
|
int SignalFromStatus(const Status&);
|
|
|
|
class ARROW_EXPORT TemporaryDir {
|
|
public:
|
|
~TemporaryDir();
|
|
|
|
/// '/'-terminated path to the temporary dir
|
|
const PlatformFilename& path() { return path_; }
|
|
|
|
/// Create a temporary subdirectory in the system temporary dir,
|
|
/// named starting with `prefix`.
|
|
static Result<std::unique_ptr<TemporaryDir>> Make(const std::string& prefix);
|
|
|
|
private:
|
|
PlatformFilename path_;
|
|
|
|
explicit TemporaryDir(PlatformFilename&&);
|
|
};
|
|
|
|
class ARROW_EXPORT SignalHandler {
|
|
public:
|
|
using Callback = void (*)(int);
|
|
|
|
SignalHandler();
|
|
explicit SignalHandler(Callback cb);
|
|
#if ARROW_HAVE_SIGACTION
|
|
explicit SignalHandler(const struct sigaction& sa);
|
|
#endif
|
|
|
|
Callback callback() const;
|
|
#if ARROW_HAVE_SIGACTION
|
|
const struct sigaction& action() const;
|
|
#endif
|
|
|
|
protected:
|
|
#if ARROW_HAVE_SIGACTION
|
|
// Storing the full sigaction allows to restore the entire signal handling
|
|
// configuration.
|
|
struct sigaction sa_;
|
|
#else
|
|
Callback cb_;
|
|
#endif
|
|
};
|
|
|
|
/// \brief Return the current handler for the given signal number.
|
|
ARROW_EXPORT
|
|
Result<SignalHandler> GetSignalHandler(int signum);
|
|
|
|
/// \brief Set a new handler for the given signal number.
|
|
///
|
|
/// The old signal handler is returned.
|
|
ARROW_EXPORT
|
|
Result<SignalHandler> SetSignalHandler(int signum, const SignalHandler& handler);
|
|
|
|
/// \brief Reinstate the signal handler
|
|
///
|
|
/// For use in signal handlers. This is needed on platforms without sigaction()
|
|
/// such as Windows, as the default signal handler is restored there as
|
|
/// soon as a signal is raised.
|
|
ARROW_EXPORT
|
|
void ReinstateSignalHandler(int signum, SignalHandler::Callback handler);
|
|
|
|
/// \brief Send a signal to the current process
|
|
///
|
|
/// The thread which will receive the signal is unspecified.
|
|
ARROW_EXPORT
|
|
Status SendSignal(int signum);
|
|
|
|
/// \brief Send a signal to the given thread
|
|
///
|
|
/// This function isn't supported on Windows.
|
|
ARROW_EXPORT
|
|
Status SendSignalToThread(int signum, uint64_t thread_id);
|
|
|
|
/// \brief Get an unpredictable random seed
|
|
///
|
|
/// This function may be slightly costly, so should only be used to initialize
|
|
/// a PRNG, not to generate a large amount of random numbers.
|
|
/// It is better to use this function rather than std::random_device, unless
|
|
/// absolutely necessary (e.g. to generate a cryptographic secret).
|
|
ARROW_EXPORT
|
|
int64_t GetRandomSeed();
|
|
|
|
/// \brief Get the current thread id
|
|
///
|
|
/// In addition to having the same properties as std::thread, the returned value
|
|
/// is a regular integer value, which is more convenient than an opaque type.
|
|
ARROW_EXPORT
|
|
uint64_t GetThreadId();
|
|
|
|
/// \brief Get the current memory used by the current process in bytes
|
|
///
|
|
/// This function supports Windows, Linux, and Mac and will return 0 otherwise
|
|
ARROW_EXPORT
|
|
int64_t GetCurrentRSS();
|
|
|
|
/// \brief Get the total memory available to the system in bytes
|
|
///
|
|
/// This function supports Windows, Linux, and Mac and will return 0 otherwise
|
|
ARROW_EXPORT
|
|
int64_t GetTotalMemoryBytes();
|
|
|
|
/// \brief Load a dynamic library
|
|
///
|
|
/// This wraps dlopen() except on Windows, where LoadLibrary() is called.
|
|
/// These two platforms handle absolute paths consistently; relative paths
|
|
/// or the library's bare name may be handled but inconsistently.
|
|
///
|
|
/// \return An opaque handle for the dynamic library, which can be used for
|
|
/// subsequent symbol lookup. Nullptr will never be returned; instead
|
|
/// an error will be raised.
|
|
ARROW_EXPORT Result<void*> LoadDynamicLibrary(const PlatformFilename& path);
|
|
|
|
/// \brief Load a dynamic library
|
|
///
|
|
/// An overload taking null terminated string.
|
|
ARROW_EXPORT Result<void*> LoadDynamicLibrary(const char* path);
|
|
|
|
/// \brief Retrieve a symbol by name from a library handle.
|
|
///
|
|
/// This wraps dlsym() except on Windows, where GetProcAddress() is called.
|
|
///
|
|
/// \return The address associated with the named symbol. Nullptr will never be
|
|
/// returned; instead an error will be raised.
|
|
ARROW_EXPORT Result<void*> GetSymbol(void* handle, const char* name);
|
|
|
|
template <typename T>
|
|
Result<T*> GetSymbolAs(void* handle, const char* name) {
|
|
ARROW_ASSIGN_OR_RAISE(void* sym, GetSymbol(handle, name));
|
|
return reinterpret_cast<T*>(sym);
|
|
}
|
|
|
|
} // namespace arrow::internal
|