mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-24 01:31:46 +00:00
Move entirety of llvm namespace to wpi namespace.
During shared library loading, a different libLLVM can be pulled in, causing llvm symbols from dependent libraries to resolve to that library instead of this one. This has been seen in the wild with the Mesa OpenGL implementation in JavaFX applications (see wpilibsuite/shuffleboard#361). This is clearly a very breaking change. For some level of backwards compatibility, a namespace alias from llvm to wpi is performed in the "llvm" headers. Unfortunately, forward declarations of llvm classes will still break, but compilers seem to generate clear error messages in those cases ("namespace alias 'llvm' not allowed here, assuming 'wpi'"). This change also moves all the wpiutil headers to a single "wpi" subdirectory from the previously split "llvm", "support", "tcpsockets", and "udpsockets". Shim headers will be added for backwards compatibility in a later commit.
This commit is contained in:
@@ -1,40 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_BASE64_H_
|
||||
#define WPIUTIL_SUPPORT_BASE64_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
class raw_ostream;
|
||||
} // namespace llvm
|
||||
|
||||
namespace wpi {
|
||||
|
||||
size_t Base64Decode(llvm::raw_ostream& os, llvm::StringRef encoded);
|
||||
|
||||
size_t Base64Decode(llvm::StringRef encoded, std::string* plain);
|
||||
|
||||
llvm::StringRef Base64Decode(llvm::StringRef encoded, size_t* num_read,
|
||||
llvm::SmallVectorImpl<char>& buf);
|
||||
|
||||
void Base64Encode(llvm::raw_ostream& os, llvm::StringRef plain);
|
||||
|
||||
void Base64Encode(llvm::StringRef plain, std::string* encoded);
|
||||
|
||||
llvm::StringRef Base64Encode(llvm::StringRef plain,
|
||||
llvm::SmallVectorImpl<char>& buf);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_BASE64_H_
|
||||
@@ -1,85 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2013 Juan Palacios juan.palacios.puyana@gmail.com
|
||||
// Subject to the BSD 2-Clause License
|
||||
// - see < http://opensource.org/licenses/BSD-2-Clause>
|
||||
//
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_CONCURRENTQUEUE_H_
|
||||
#define WPIUTIL_SUPPORT_CONCURRENTQUEUE_H_
|
||||
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "support/condition_variable.h"
|
||||
#include "support/mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T>
|
||||
class ConcurrentQueue {
|
||||
public:
|
||||
bool empty() const {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
typename std::queue<T>::size_type size() const {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
return queue_.size();
|
||||
}
|
||||
|
||||
T pop() {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
while (queue_.empty()) {
|
||||
cond_.wait(mlock);
|
||||
}
|
||||
auto item = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
return item;
|
||||
}
|
||||
|
||||
void pop(T& item) {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
while (queue_.empty()) {
|
||||
cond_.wait(mlock);
|
||||
}
|
||||
item = queue_.front();
|
||||
queue_.pop();
|
||||
}
|
||||
|
||||
void push(const T& item) {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
queue_.push(item);
|
||||
mlock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
void push(T&& item) {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
queue_.push(std::forward<T>(item));
|
||||
mlock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
std::unique_lock<wpi::mutex> mlock(mutex_);
|
||||
queue_.emplace(std::forward<Args>(args)...);
|
||||
mlock.unlock();
|
||||
cond_.notify_one();
|
||||
}
|
||||
|
||||
ConcurrentQueue() = default;
|
||||
ConcurrentQueue(const ConcurrentQueue&) = delete;
|
||||
ConcurrentQueue& operator=(const ConcurrentQueue&) = delete;
|
||||
|
||||
private:
|
||||
std::queue<T> queue_;
|
||||
mutable wpi::mutex mutex_;
|
||||
wpi::condition_variable cond_;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_CONCURRENTQUEUE_H_
|
||||
@@ -1,150 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_HTTPUTIL_H_
|
||||
#define WPIUTIL_SUPPORT_HTTPUTIL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/SmallString.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringMap.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include "llvm/Twine.h"
|
||||
#include "support/raw_istream.h"
|
||||
#include "support/raw_socket_istream.h"
|
||||
#include "support/raw_socket_ostream.h"
|
||||
#include "tcpsockets/NetworkStream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
// Unescape a %xx-encoded URI.
|
||||
// @param buf Buffer for output
|
||||
// @param error Set to true if an error occurred
|
||||
// @return Escaped string
|
||||
llvm::StringRef UnescapeURI(const llvm::Twine& str,
|
||||
llvm::SmallVectorImpl<char>& buf, bool* error);
|
||||
|
||||
// Escape a string with %xx-encoding.
|
||||
// @param buf Buffer for output
|
||||
// @param spacePlus If true, encodes spaces to '+' rather than "%20"
|
||||
// @return Escaped string
|
||||
llvm::StringRef EscapeURI(const llvm::Twine& str,
|
||||
llvm::SmallVectorImpl<char>& buf,
|
||||
bool spacePlus = true);
|
||||
|
||||
// Parse a set of HTTP headers. Saves just the Content-Type and Content-Length
|
||||
// fields.
|
||||
// @param is Input stream
|
||||
// @param contentType If not null, Content-Type contents are saved here.
|
||||
// @param contentLength If not null, Content-Length contents are saved here.
|
||||
// @return False if error occurred in input stream
|
||||
bool ParseHttpHeaders(wpi::raw_istream& is,
|
||||
llvm::SmallVectorImpl<char>* contentType,
|
||||
llvm::SmallVectorImpl<char>* contentLength);
|
||||
|
||||
// Look for a MIME multi-part boundary. On return, the input stream will
|
||||
// be located at the character following the boundary (usually "\r\n").
|
||||
// @param is Input stream
|
||||
// @param boundary Boundary string to scan for (not including "--" prefix)
|
||||
// @param saveBuf If not null, all scanned characters up to but not including
|
||||
// the boundary are saved to this string
|
||||
// @return False if error occurred on input stream, true if boundary found.
|
||||
bool FindMultipartBoundary(wpi::raw_istream& is, llvm::StringRef boundary,
|
||||
std::string* saveBuf);
|
||||
|
||||
class HttpLocation {
|
||||
public:
|
||||
HttpLocation() = default;
|
||||
HttpLocation(const llvm::Twine& url_, bool* error, std::string* errorMsg);
|
||||
|
||||
std::string url; // retain copy
|
||||
std::string user; // unescaped
|
||||
std::string password; // unescaped
|
||||
std::string host;
|
||||
int port;
|
||||
std::string path; // escaped, not including leading '/'
|
||||
std::vector<std::pair<std::string, std::string>> params; // unescaped
|
||||
std::string fragment;
|
||||
};
|
||||
|
||||
class HttpRequest {
|
||||
public:
|
||||
HttpRequest() = default;
|
||||
|
||||
explicit HttpRequest(const HttpLocation& loc)
|
||||
: host{loc.host}, port{loc.port} {
|
||||
SetPath(loc.path, loc.params);
|
||||
SetAuth(loc);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HttpRequest(const HttpLocation& loc, const T& extraParams);
|
||||
|
||||
HttpRequest(const HttpLocation& loc, llvm::StringRef path_)
|
||||
: host{loc.host}, port{loc.port}, path{path_} {
|
||||
SetAuth(loc);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HttpRequest(const HttpLocation& loc, llvm::StringRef path_, const T& params)
|
||||
: host{loc.host}, port{loc.port} {
|
||||
SetPath(path_, params);
|
||||
SetAuth(loc);
|
||||
}
|
||||
|
||||
llvm::SmallString<128> host;
|
||||
int port;
|
||||
std::string auth;
|
||||
llvm::SmallString<128> path;
|
||||
|
||||
private:
|
||||
void SetAuth(const HttpLocation& loc);
|
||||
template <typename T>
|
||||
void SetPath(llvm::StringRef path_, const T& params);
|
||||
|
||||
template <typename T>
|
||||
static llvm::StringRef GetFirst(const T& elem) {
|
||||
return elem.first;
|
||||
}
|
||||
template <typename T>
|
||||
static llvm::StringRef GetFirst(const llvm::StringMapEntry<T>& elem) {
|
||||
return elem.getKey();
|
||||
}
|
||||
template <typename T>
|
||||
static llvm::StringRef GetSecond(const T& elem) {
|
||||
return elem.second;
|
||||
}
|
||||
};
|
||||
|
||||
class HttpConnection {
|
||||
public:
|
||||
HttpConnection(std::unique_ptr<wpi::NetworkStream> stream_, int timeout)
|
||||
: stream{std::move(stream_)}, is{*stream, timeout}, os{*stream, true} {}
|
||||
|
||||
bool Handshake(const HttpRequest& request, std::string* warnMsg);
|
||||
|
||||
std::unique_ptr<wpi::NetworkStream> stream;
|
||||
wpi::raw_socket_istream is;
|
||||
wpi::raw_socket_ostream os;
|
||||
|
||||
// Valid after Handshake() is successful
|
||||
llvm::SmallString<64> contentType;
|
||||
llvm::SmallString<64> contentLength;
|
||||
|
||||
explicit operator bool() const { return stream && !is.has_error(); }
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#include "HttpUtil.inl"
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_HTTPUTIL_H_
|
||||
@@ -1,48 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_HTTPUTIL_INL_
|
||||
#define WPIUTIL_SUPPORT_HTTPUTIL_INL_
|
||||
|
||||
namespace wpi {
|
||||
|
||||
template <typename T>
|
||||
HttpRequest::HttpRequest(const HttpLocation& loc, const T& extraParams)
|
||||
: host{loc.host}, port{loc.port} {
|
||||
llvm::SmallVector<std::pair<llvm::StringRef, llvm::StringRef>, 8> params;
|
||||
for (const auto& p : loc.params)
|
||||
params.emplace_back(std::make_pair(GetFirst(p), GetSecond(p)));
|
||||
for (const auto& p : extraParams)
|
||||
params.emplace_back(std::make_pair(GetFirst(p), GetSecond(p)));
|
||||
SetPath(loc.path, params);
|
||||
SetAuth(loc);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HttpRequest::SetPath(llvm::StringRef path_, const T& params) {
|
||||
// Build location including query string
|
||||
llvm::raw_svector_ostream pathOs{path};
|
||||
pathOs << path_;
|
||||
bool first = true;
|
||||
for (const auto& param : params) {
|
||||
if (first) {
|
||||
pathOs << '?';
|
||||
first = false;
|
||||
} else {
|
||||
pathOs << '&';
|
||||
}
|
||||
llvm::SmallString<64> escapeBuf;
|
||||
pathOs << EscapeURI(GetFirst(param), escapeBuf);
|
||||
if (!GetSecond(param).empty()) {
|
||||
pathOs << '=' << EscapeURI(GetSecond(param), escapeBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_HTTPUTIL_INL_
|
||||
@@ -1,100 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_LOGGER_H_
|
||||
#define WPIUTIL_SUPPORT_LOGGER_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "llvm/SmallString.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
enum LogLevel {
|
||||
WPI_LOG_CRITICAL = 50,
|
||||
WPI_LOG_ERROR = 40,
|
||||
WPI_LOG_WARNING = 30,
|
||||
WPI_LOG_INFO = 20,
|
||||
WPI_LOG_DEBUG = 10,
|
||||
WPI_LOG_DEBUG1 = 9,
|
||||
WPI_LOG_DEBUG2 = 8,
|
||||
WPI_LOG_DEBUG3 = 7,
|
||||
WPI_LOG_DEBUG4 = 6
|
||||
};
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
typedef std::function<void(unsigned int level, const char* file,
|
||||
unsigned int line, const char* msg)>
|
||||
LogFunc;
|
||||
|
||||
Logger() = default;
|
||||
explicit Logger(const LogFunc& func) : m_func(func) {}
|
||||
Logger(const LogFunc& func, unsigned int min_level)
|
||||
: m_func(func), m_min_level(min_level) {}
|
||||
|
||||
void SetLogger(LogFunc func) { m_func = func; }
|
||||
|
||||
void set_min_level(unsigned int level) { m_min_level = level; }
|
||||
unsigned int min_level() const { return m_min_level; }
|
||||
|
||||
void Log(unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg) {
|
||||
if (!m_func || level < m_min_level) return;
|
||||
m_func(level, file, line, msg);
|
||||
}
|
||||
|
||||
bool HasLogger() const { return m_func != nullptr; }
|
||||
|
||||
private:
|
||||
LogFunc m_func;
|
||||
unsigned int m_min_level = 20;
|
||||
};
|
||||
|
||||
#define WPI_LOG(logger_inst, level, x) \
|
||||
do { \
|
||||
::wpi::Logger& WPI_logger_ = logger_inst; \
|
||||
if (WPI_logger_.min_level() <= level && WPI_logger_.HasLogger()) { \
|
||||
llvm::SmallString<128> log_buf_; \
|
||||
llvm::raw_svector_ostream log_os_{log_buf_}; \
|
||||
log_os_ << x; \
|
||||
WPI_logger_.Log(level, __FILE__, __LINE__, log_buf_.c_str()); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WPI_ERROR(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, x)
|
||||
#define WPI_WARNING(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, x)
|
||||
#define WPI_INFO(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_INFO, x)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define WPI_DEBUG(inst, x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG1(inst, x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG2(inst, x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG3(inst, x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#define WPI_DEBUG4(inst, x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#else
|
||||
#define WPI_DEBUG(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, x)
|
||||
#define WPI_DEBUG1(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, x)
|
||||
#define WPI_DEBUG2(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, x)
|
||||
#define WPI_DEBUG3(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, x)
|
||||
#define WPI_DEBUG4(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, x)
|
||||
#endif
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_LOGGER_H_
|
||||
@@ -1,133 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_SAFETHREAD_H_
|
||||
#define WPIUTIL_SUPPORT_SAFETHREAD_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include "support/condition_variable.h"
|
||||
#include "support/mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
// Base class for SafeThreadOwner threads.
|
||||
class SafeThread {
|
||||
public:
|
||||
SafeThread() { m_active = true; }
|
||||
virtual ~SafeThread() = default;
|
||||
virtual void Main() = 0;
|
||||
|
||||
wpi::mutex m_mutex;
|
||||
std::atomic_bool m_active;
|
||||
wpi::condition_variable m_cond;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Non-template proxy base class for common proxy code.
|
||||
class SafeThreadProxyBase {
|
||||
public:
|
||||
explicit SafeThreadProxyBase(SafeThread* thr) : m_thread(thr) {
|
||||
if (!m_thread) return;
|
||||
m_lock = std::unique_lock<wpi::mutex>(m_thread->m_mutex);
|
||||
if (!m_thread->m_active) {
|
||||
m_lock.unlock();
|
||||
m_thread = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
explicit operator bool() const { return m_thread != nullptr; }
|
||||
std::unique_lock<wpi::mutex>& GetLock() { return m_lock; }
|
||||
|
||||
protected:
|
||||
SafeThread* m_thread;
|
||||
std::unique_lock<wpi::mutex> m_lock;
|
||||
};
|
||||
|
||||
// A proxy for SafeThread.
|
||||
// Also serves as a scoped lock on SafeThread::m_mutex.
|
||||
template <typename T>
|
||||
class SafeThreadProxy : public SafeThreadProxyBase {
|
||||
public:
|
||||
explicit SafeThreadProxy(SafeThread* thr) : SafeThreadProxyBase(thr) {}
|
||||
T& operator*() const { return *static_cast<T*>(m_thread); }
|
||||
T* operator->() const { return static_cast<T*>(m_thread); }
|
||||
};
|
||||
|
||||
// Non-template owner base class for common owner code.
|
||||
class SafeThreadOwnerBase {
|
||||
public:
|
||||
void Stop();
|
||||
|
||||
SafeThreadOwnerBase() { m_thread = nullptr; }
|
||||
SafeThreadOwnerBase(const SafeThreadOwnerBase&) = delete;
|
||||
SafeThreadOwnerBase& operator=(const SafeThreadOwnerBase&) = delete;
|
||||
SafeThreadOwnerBase(SafeThreadOwnerBase&& other)
|
||||
: m_thread(other.m_thread.exchange(nullptr)) {}
|
||||
SafeThreadOwnerBase& operator=(SafeThreadOwnerBase other) {
|
||||
SafeThread* otherthr = other.m_thread.exchange(nullptr);
|
||||
SafeThread* curthr = m_thread.exchange(otherthr);
|
||||
other.m_thread.exchange(curthr); // other destructor will clean up
|
||||
return *this;
|
||||
}
|
||||
~SafeThreadOwnerBase() { Stop(); }
|
||||
|
||||
explicit operator bool() const { return m_thread.load(); }
|
||||
|
||||
protected:
|
||||
void Start(SafeThread* thr);
|
||||
SafeThread* GetThread() const { return m_thread.load(); }
|
||||
std::thread::native_handle_type GetNativeThreadHandle() const {
|
||||
return m_nativeHandle;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<SafeThread*> m_thread;
|
||||
std::atomic<std::thread::native_handle_type> m_nativeHandle;
|
||||
};
|
||||
|
||||
inline void SafeThreadOwnerBase::Start(SafeThread* thr) {
|
||||
SafeThread* curthr = nullptr;
|
||||
SafeThread* newthr = thr;
|
||||
if (!m_thread.compare_exchange_strong(curthr, newthr)) {
|
||||
delete newthr;
|
||||
return;
|
||||
}
|
||||
std::thread stdThread([=]() {
|
||||
newthr->Main();
|
||||
delete newthr;
|
||||
});
|
||||
m_nativeHandle = stdThread.native_handle();
|
||||
stdThread.detach();
|
||||
}
|
||||
|
||||
inline void SafeThreadOwnerBase::Stop() {
|
||||
SafeThread* thr = m_thread.exchange(nullptr);
|
||||
if (!thr) return;
|
||||
thr->m_active = false;
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
class SafeThreadOwner : public detail::SafeThreadOwnerBase {
|
||||
public:
|
||||
void Start() { Start(new T); }
|
||||
void Start(T* thr) { detail::SafeThreadOwnerBase::Start(thr); }
|
||||
|
||||
using Proxy = typename detail::SafeThreadProxy<T>;
|
||||
Proxy GetThread() const {
|
||||
return Proxy(detail::SafeThreadOwnerBase::GetThread());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_SAFETHREAD_H_
|
||||
@@ -1,67 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_UIDVECTOR_H_
|
||||
#define WPIUTIL_SUPPORT_UIDVECTOR_H_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
// Vector which provides an integrated freelist for removal and reuse of
|
||||
// individual elements.
|
||||
// @tparam T element type; must be default-constructible and evaluate in
|
||||
// boolean context to false when "empty"
|
||||
// @tparam reuse_threshold how many free elements to store up before starting
|
||||
// to recycle them
|
||||
template <typename T, typename std::vector<T>::size_type reuse_threshold>
|
||||
class UidVector {
|
||||
public:
|
||||
typedef typename std::vector<T>::size_type size_type;
|
||||
|
||||
bool empty() const { return m_active_count == 0; }
|
||||
size_type size() const { return m_vector.size(); }
|
||||
T& operator[](size_type i) { return m_vector[i]; }
|
||||
const T& operator[](size_type i) const { return m_vector[i]; }
|
||||
|
||||
// Add a new T to the vector. If there are elements on the freelist,
|
||||
// reuses the last one; otherwise adds to the end of the vector.
|
||||
// Returns the resulting element index.
|
||||
template <class... Args>
|
||||
size_type emplace_back(Args&&... args) {
|
||||
size_type uid;
|
||||
if (m_free.size() < reuse_threshold) {
|
||||
uid = m_vector.size();
|
||||
m_vector.emplace_back(std::forward<Args>(args)...);
|
||||
} else {
|
||||
uid = m_free.front();
|
||||
m_free.erase(m_free.begin());
|
||||
m_vector[uid] = T(std::forward<Args>(args)...);
|
||||
}
|
||||
++m_active_count;
|
||||
return uid;
|
||||
}
|
||||
|
||||
// Removes the identified element by replacing it with a default-constructed
|
||||
// one. The element is added to the freelist for later reuse.
|
||||
void erase(size_type uid) {
|
||||
if (uid >= m_vector.size() || !m_vector[uid]) return;
|
||||
m_free.push_back(uid);
|
||||
m_vector[uid] = T();
|
||||
--m_active_count;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> m_vector;
|
||||
std::vector<size_type> m_free;
|
||||
size_type m_active_count{0};
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_UIDVECTOR_H_
|
||||
@@ -1,49 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_ATOMIC_STATIC_H_
|
||||
#define WPIUTIL_SUPPORT_ATOMIC_STATIC_H_
|
||||
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
|
||||
// Just use a local static. This is thread-safe per
|
||||
// http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
|
||||
// Per https://msdn.microsoft.com/en-us/library/Hh567368.aspx "Magic Statics"
|
||||
// are supported in Visual Studio 2015 but not in earlier versions.
|
||||
#define ATOMIC_STATIC(cls, inst) static cls inst
|
||||
#define ATOMIC_STATIC_DECL(cls)
|
||||
#define ATOMIC_STATIC_INIT(cls)
|
||||
|
||||
#else
|
||||
// From http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#define ATOMIC_STATIC(cls, inst) \
|
||||
cls* inst##tmp = m_instance.load(std::memory_order_acquire); \
|
||||
if (inst##tmp == nullptr) { \
|
||||
std::lock_guard<std::mutex> lock(m_instance_mutex); \
|
||||
inst##tmp = m_instance.load(std::memory_order_relaxed); \
|
||||
if (inst##tmp == nullptr) { \
|
||||
inst##tmp = new cls; \
|
||||
m_instance.store(inst##tmp, std::memory_order_release); \
|
||||
} \
|
||||
} \
|
||||
cls& inst = *inst##tmp
|
||||
|
||||
#define ATOMIC_STATIC_DECL(cls) \
|
||||
static std::atomic<cls*> m_instance; \
|
||||
static std::mutex m_instance_mutex;
|
||||
|
||||
#define ATOMIC_STATIC_INIT(cls) \
|
||||
std::atomic<cls*> cls::m_instance; \
|
||||
std::mutex cls::m_instance_mutex;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_ATOMIC_STATIC_H_
|
||||
@@ -1,22 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
#include "priority_condition_variable.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifdef WPI_HAVE_PRIORITY_CONDITION_VARIABLE
|
||||
using condition_variable = priority_condition_variable;
|
||||
#else
|
||||
using condition_variable = ::std::condition_variable;
|
||||
#endif
|
||||
|
||||
} // namespace wpi
|
||||
@@ -1,33 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_DEPRECATED_H_
|
||||
#define WPIUTIL_SUPPORT_DEPRECATED_H_
|
||||
|
||||
// [[deprecated(msg)]] is a C++14 feature not supported by MSVC or GCC < 4.9.
|
||||
// We provide an equivalent warning implementation for those compilers here.
|
||||
#ifndef WPI_DEPRECATED
|
||||
#if defined(_MSC_VER)
|
||||
#define WPI_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8)
|
||||
#if __cplusplus > 201103L
|
||||
#define WPI_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#else
|
||||
#define WPI_DEPRECATED(msg) [[gnu::deprecated(msg)]]
|
||||
#endif
|
||||
#else
|
||||
#define WPI_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
#endif
|
||||
#elif __cplusplus > 201103L
|
||||
#define WPI_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#else
|
||||
#define WPI_DEPRECATED(msg) /*nothing*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_DEPRECATED_H_
|
||||
@@ -1,25 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_HOSTNAME_H_
|
||||
#define WPIUTIL_SUPPORT_HOSTNAME_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
} // namespace llvm
|
||||
|
||||
namespace wpi {
|
||||
std::string GetHostname();
|
||||
llvm::StringRef GetHostname(llvm::SmallVectorImpl<char>& name);
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_HOSTNAME_H_
|
||||
@@ -1,639 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_JNI_UTIL_H_
|
||||
#define WPIUTIL_SUPPORT_JNI_UTIL_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/ConvertUTF.h"
|
||||
#include "llvm/SmallString.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include "support/SafeThread.h"
|
||||
#include "support/atomic_static.h"
|
||||
#include "support/deprecated.h"
|
||||
#include "support/mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace java {
|
||||
|
||||
// Gets a Java stack trace. Also provides the last function
|
||||
// in the stack trace not starting with excludeFuncPrefix (useful for e.g.
|
||||
// finding the first user call to a series of library functions).
|
||||
std::string GetJavaStackTrace(
|
||||
JNIEnv* env, std::string* func = nullptr,
|
||||
llvm::StringRef excludeFuncPrefix = llvm::StringRef());
|
||||
|
||||
// Shim for backwards compatibility
|
||||
template <const char* excludeFuncPrefix>
|
||||
WPI_DEPRECATED("use StringRef function instead")
|
||||
std::string GetJavaStackTrace(JNIEnv* env, std::string* func) {
|
||||
return GetJavaStackTrace(
|
||||
env, func,
|
||||
excludeFuncPrefix == nullptr ? llvm::StringRef() : excludeFuncPrefix);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Finds a class and keep it as a global reference.
|
||||
// Use with caution, as the destructor does NOT call DeleteGlobalRef due
|
||||
// to potential shutdown issues with doing so.
|
||||
class JClass {
|
||||
public:
|
||||
JClass() = default;
|
||||
|
||||
JClass(JNIEnv* env, const char* name) {
|
||||
jclass local = env->FindClass(name);
|
||||
if (!local) return;
|
||||
m_cls = static_cast<jclass>(env->NewGlobalRef(local));
|
||||
env->DeleteLocalRef(local);
|
||||
}
|
||||
|
||||
void free(JNIEnv* env) {
|
||||
if (m_cls) env->DeleteGlobalRef(m_cls);
|
||||
m_cls = nullptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_cls; }
|
||||
|
||||
operator jclass() const { return m_cls; }
|
||||
|
||||
protected:
|
||||
jclass m_cls = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class JGlobal {
|
||||
public:
|
||||
JGlobal() = default;
|
||||
|
||||
JGlobal(JNIEnv* env, T obj) {
|
||||
m_cls = static_cast<T>(env->NewGlobalRef(obj));
|
||||
}
|
||||
|
||||
void free(JNIEnv* env) {
|
||||
if (m_cls) env->DeleteGlobalRef(m_cls);
|
||||
m_cls = nullptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_cls; }
|
||||
|
||||
operator T() const { return m_cls; }
|
||||
|
||||
protected:
|
||||
T m_cls = nullptr;
|
||||
};
|
||||
|
||||
// Container class for cleaning up Java local references.
|
||||
// The destructor calls DeleteLocalRef.
|
||||
template <typename T>
|
||||
class JLocal {
|
||||
public:
|
||||
JLocal(JNIEnv* env, T obj) : m_env(env), m_obj(obj) {}
|
||||
JLocal(const JLocal&) = delete;
|
||||
JLocal(JLocal&& oth) : m_env(oth.m_env), m_obj(oth.m_obj) {
|
||||
oth.m_obj = nullptr;
|
||||
}
|
||||
JLocal& operator=(const JLocal&) = delete;
|
||||
JLocal& operator=(JLocal&& oth) {
|
||||
m_env = oth.m_env;
|
||||
m_obj = oth.m_obj;
|
||||
oth.m_obj = nullptr;
|
||||
return *this;
|
||||
}
|
||||
~JLocal() {
|
||||
if (m_obj) m_env->DeleteLocalRef(m_obj);
|
||||
}
|
||||
operator T() { return m_obj; }
|
||||
T obj() { return m_obj; }
|
||||
|
||||
private:
|
||||
JNIEnv* m_env;
|
||||
T m_obj;
|
||||
};
|
||||
|
||||
//
|
||||
// Conversions from Java objects to C++
|
||||
//
|
||||
|
||||
// Java string (jstring) reference. The string is provided as UTF8.
|
||||
// This is not actually a reference, as it makes a copy of the string
|
||||
// characters, but it's named this way for consistency.
|
||||
class JStringRef {
|
||||
public:
|
||||
JStringRef(JNIEnv* env, jstring str) {
|
||||
if (str) {
|
||||
jsize size = env->GetStringLength(str);
|
||||
const jchar* chars = env->GetStringCritical(str, nullptr);
|
||||
if (chars) {
|
||||
llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str);
|
||||
env->ReleaseStringCritical(str, chars);
|
||||
}
|
||||
} else {
|
||||
llvm::errs() << "JStringRef was passed a null pointer at \n"
|
||||
<< GetJavaStackTrace(env);
|
||||
}
|
||||
// Ensure str is null-terminated.
|
||||
m_str.push_back('\0');
|
||||
m_str.pop_back();
|
||||
}
|
||||
|
||||
operator llvm::StringRef() const { return m_str; }
|
||||
llvm::StringRef str() const { return m_str; }
|
||||
const char* c_str() const { return m_str.data(); }
|
||||
size_t size() const { return m_str.size(); }
|
||||
|
||||
private:
|
||||
llvm::SmallString<128> m_str;
|
||||
};
|
||||
|
||||
// Details for J*ArrayRef and CriticalJ*ArrayRef
|
||||
namespace detail {
|
||||
|
||||
template <typename C, typename T>
|
||||
class JArrayRefInner {};
|
||||
|
||||
// Specialization of JArrayRefBase to provide StringRef conversion.
|
||||
template <typename C>
|
||||
class JArrayRefInner<C, jbyte> {
|
||||
public:
|
||||
operator llvm::StringRef() const { return str(); }
|
||||
|
||||
llvm::StringRef str() const {
|
||||
auto arr = static_cast<const C*>(this)->array();
|
||||
if (arr.empty()) return llvm::StringRef{};
|
||||
return llvm::StringRef{reinterpret_cast<const char*>(arr.data()),
|
||||
arr.size()};
|
||||
}
|
||||
};
|
||||
|
||||
// Base class for J*ArrayRef and CriticalJ*ArrayRef
|
||||
template <typename T>
|
||||
class JArrayRefBase : public JArrayRefInner<JArrayRefBase<T>, T> {
|
||||
public:
|
||||
explicit operator bool() const { return this->m_elements != nullptr; }
|
||||
|
||||
operator llvm::ArrayRef<T>() const { return array(); }
|
||||
|
||||
llvm::ArrayRef<T> array() const {
|
||||
if (!this->m_elements) return llvm::ArrayRef<T>{};
|
||||
return llvm::ArrayRef<T>{this->m_elements, this->m_size};
|
||||
}
|
||||
|
||||
JArrayRefBase(const JArrayRefBase&) = delete;
|
||||
JArrayRefBase& operator=(const JArrayRefBase&) = delete;
|
||||
|
||||
JArrayRefBase(JArrayRefBase&& oth)
|
||||
: m_env(oth.m_env),
|
||||
m_jarr(oth.m_jarr),
|
||||
m_size(oth.m_size),
|
||||
m_elements(oth.m_elements) {
|
||||
oth.m_jarr = nullptr;
|
||||
oth.m_elements = nullptr;
|
||||
}
|
||||
|
||||
JArrayRefBase& operator=(JArrayRefBase&& oth) {
|
||||
this->m_env = oth.m_env;
|
||||
this->m_jarr = oth.m_jarr;
|
||||
this->m_size = oth.m_size;
|
||||
this->m_elements = oth.m_elements;
|
||||
oth.m_jarr = nullptr;
|
||||
oth.m_elements = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
JArrayRefBase(JNIEnv* env, T* elements, size_t size) {
|
||||
this->m_env = env;
|
||||
this->m_jarr = nullptr;
|
||||
this->m_size = size;
|
||||
this->m_elements = elements;
|
||||
}
|
||||
|
||||
JArrayRefBase(JNIEnv* env, jarray jarr) {
|
||||
this->m_env = env;
|
||||
this->m_jarr = jarr;
|
||||
this->m_size = jarr ? env->GetArrayLength(jarr) : 0;
|
||||
this->m_elements = nullptr;
|
||||
}
|
||||
|
||||
JNIEnv* m_env;
|
||||
jarray m_jarr = nullptr;
|
||||
size_t m_size;
|
||||
T* m_elements;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Java array / DirectBuffer reference.
|
||||
|
||||
#define WPI_JNI_JARRAYREF(T, F) \
|
||||
class J##F##ArrayRef : public detail::JArrayRefBase<T> { \
|
||||
public: \
|
||||
J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \
|
||||
: detail::JArrayRefBase<T>( \
|
||||
env, \
|
||||
static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \
|
||||
len) { \
|
||||
if (!bb) \
|
||||
llvm::errs() << "JArrayRef was passed a null pointer at \n" \
|
||||
<< GetJavaStackTrace(env); \
|
||||
} \
|
||||
J##F##ArrayRef(JNIEnv* env, T##Array jarr) \
|
||||
: detail::JArrayRefBase<T>(env, jarr) { \
|
||||
if (jarr) \
|
||||
m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
|
||||
else \
|
||||
llvm::errs() << "JArrayRef was passed a null pointer at \n" \
|
||||
<< GetJavaStackTrace(env); \
|
||||
} \
|
||||
~J##F##ArrayRef() { \
|
||||
if (m_jarr && m_elements) \
|
||||
m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \
|
||||
m_elements, JNI_ABORT); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \
|
||||
public: \
|
||||
CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \
|
||||
: detail::JArrayRefBase<T>(env, jarr) { \
|
||||
if (jarr) \
|
||||
m_elements = \
|
||||
static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
|
||||
else \
|
||||
llvm::errs() << "JArrayRef was passed a null pointer at \n" \
|
||||
<< GetJavaStackTrace(env); \
|
||||
} \
|
||||
~CriticalJ##F##ArrayRef() { \
|
||||
if (m_jarr && m_elements) \
|
||||
m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \
|
||||
} \
|
||||
};
|
||||
|
||||
WPI_JNI_JARRAYREF(jboolean, Boolean)
|
||||
WPI_JNI_JARRAYREF(jbyte, Byte)
|
||||
WPI_JNI_JARRAYREF(jshort, Short)
|
||||
WPI_JNI_JARRAYREF(jint, Int)
|
||||
WPI_JNI_JARRAYREF(jlong, Long)
|
||||
WPI_JNI_JARRAYREF(jfloat, Float)
|
||||
WPI_JNI_JARRAYREF(jdouble, Double)
|
||||
|
||||
#undef WPI_JNI_JARRAYREF
|
||||
|
||||
//
|
||||
// Conversions from C++ to Java objects
|
||||
//
|
||||
|
||||
// Convert a UTF8 string into a jstring.
|
||||
inline jstring MakeJString(JNIEnv* env, llvm::StringRef str) {
|
||||
llvm::SmallVector<UTF16, 128> chars;
|
||||
llvm::convertUTF8ToUTF16String(str, chars);
|
||||
return env->NewString(chars.begin(), chars.size());
|
||||
}
|
||||
|
||||
// details for MakeJIntArray
|
||||
namespace detail {
|
||||
|
||||
// Slow path (get primitive array and set individual elements). This
|
||||
// is used if the input type is not an integer of the same size (note
|
||||
// signed/unsigned is ignored).
|
||||
template <typename T,
|
||||
bool = (std::is_integral<T>::value && sizeof(jint) == sizeof(T))>
|
||||
struct ConvertIntArray {
|
||||
static jintArray ToJava(JNIEnv* env, llvm::ArrayRef<T> arr) {
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
jint* elements =
|
||||
static_cast<jint*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
elements[i] = static_cast<jint>(arr[i]);
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
};
|
||||
|
||||
// Fast path (use SetIntArrayRegion)
|
||||
template <typename T>
|
||||
struct ConvertIntArray<T, true> {
|
||||
static jintArray ToJava(JNIEnv* env, llvm::ArrayRef<T> arr) {
|
||||
jintArray jarr = env->NewIntArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
env->SetIntArrayRegion(jarr, 0, arr.size(),
|
||||
reinterpret_cast<const jint*>(arr.data()));
|
||||
return jarr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Convert an ArrayRef to a jintArray.
|
||||
template <typename T>
|
||||
inline jintArray MakeJIntArray(JNIEnv* env, llvm::ArrayRef<T> arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a SmallVector to a jintArray. This is required in addition to
|
||||
// ArrayRef because template resolution occurs prior to implicit conversions.
|
||||
template <typename T>
|
||||
inline jintArray MakeJIntArray(JNIEnv* env,
|
||||
const llvm::SmallVectorImpl<T>& arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a std::vector to a jintArray. This is required in addition to
|
||||
// ArrayRef because template resolution occurs prior to implicit conversions.
|
||||
template <typename T>
|
||||
inline jintArray MakeJIntArray(JNIEnv* env, const std::vector<T>& arr) {
|
||||
return detail::ConvertIntArray<T>::ToJava(env, arr);
|
||||
}
|
||||
|
||||
// Convert a StringRef into a jbyteArray.
|
||||
inline jbyteArray MakeJByteArray(JNIEnv* env, llvm::StringRef str) {
|
||||
jbyteArray jarr = env->NewByteArray(str.size());
|
||||
if (!jarr) return nullptr;
|
||||
env->SetByteArrayRegion(jarr, 0, str.size(),
|
||||
reinterpret_cast<const jbyte*>(str.data()));
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Convert an array of integers into a jbooleanArray.
|
||||
inline jbooleanArray MakeJBooleanArray(JNIEnv* env, llvm::ArrayRef<int> arr) {
|
||||
jbooleanArray jarr = env->NewBooleanArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
jboolean* elements =
|
||||
static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Convert an array of booleans into a jbooleanArray.
|
||||
inline jbooleanArray MakeJBooleanArray(JNIEnv* env, llvm::ArrayRef<bool> arr) {
|
||||
jbooleanArray jarr = env->NewBooleanArray(arr.size());
|
||||
if (!jarr) return nullptr;
|
||||
jboolean* elements =
|
||||
static_cast<jboolean*>(env->GetPrimitiveArrayCritical(jarr, nullptr));
|
||||
if (!elements) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
|
||||
env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Other MakeJ*Array conversions.
|
||||
|
||||
#define WPI_JNI_MAKEJARRAY(T, F) \
|
||||
inline T##Array MakeJ##F##Array(JNIEnv* env, llvm::ArrayRef<T> arr) { \
|
||||
T##Array jarr = env->New##F##Array(arr.size()); \
|
||||
if (!jarr) return nullptr; \
|
||||
env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
|
||||
return jarr; \
|
||||
}
|
||||
|
||||
WPI_JNI_MAKEJARRAY(jboolean, Boolean)
|
||||
WPI_JNI_MAKEJARRAY(jbyte, Byte)
|
||||
WPI_JNI_MAKEJARRAY(jshort, Short)
|
||||
WPI_JNI_MAKEJARRAY(jlong, Long)
|
||||
WPI_JNI_MAKEJARRAY(jfloat, Float)
|
||||
WPI_JNI_MAKEJARRAY(jdouble, Double)
|
||||
|
||||
#undef WPI_JNI_MAKEJARRAY
|
||||
|
||||
// Convert an array of std::string into a jarray of jstring.
|
||||
inline jobjectArray MakeJStringArray(JNIEnv* env,
|
||||
llvm::ArrayRef<std::string> arr) {
|
||||
static JClass stringCls{env, "java/lang/String"};
|
||||
if (!stringCls) return nullptr;
|
||||
jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
JLocal<jstring> elem{env, MakeJString(env, arr[i])};
|
||||
env->SetObjectArrayElement(jarr, i, elem.obj());
|
||||
}
|
||||
return jarr;
|
||||
}
|
||||
|
||||
// Generic callback thread implementation.
|
||||
//
|
||||
// JNI's AttachCurrentThread() creates a Java Thread object on every
|
||||
// invocation, which is both time inefficient and causes issues with Eclipse
|
||||
// (which tries to keep a thread list up-to-date and thus gets swamped).
|
||||
//
|
||||
// Instead, this class attaches just once. When a hardware notification
|
||||
// occurs, a condition variable wakes up this thread and this thread actually
|
||||
// makes the call into Java.
|
||||
//
|
||||
// The template parameter T is the message being passed to the callback, but
|
||||
// also needs to provide the following functions:
|
||||
// static JavaVM* GetJVM();
|
||||
// static const char* GetName();
|
||||
// void CallJava(JNIEnv *env, jobject func, jmethodID mid);
|
||||
//
|
||||
// When creating this, ATOMIC_STATIC_INIT() needs to be performed on the
|
||||
// templated class as well.
|
||||
template <typename T>
|
||||
class JCallbackThread : public SafeThread {
|
||||
public:
|
||||
void Main();
|
||||
|
||||
std::queue<T> m_queue;
|
||||
jobject m_func = nullptr;
|
||||
jmethodID m_mid;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class JCallbackManager : public SafeThreadOwner<JCallbackThread<T>> {
|
||||
public:
|
||||
void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
|
||||
|
||||
template <typename... Args>
|
||||
void Send(Args&&... args);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void JCallbackManager<T>::SetFunc(JNIEnv* env, jobject func, jmethodID mid) {
|
||||
auto thr = this->GetThread();
|
||||
if (!thr) return;
|
||||
// free global reference
|
||||
if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
|
||||
// create global reference
|
||||
thr->m_func = env->NewGlobalRef(func);
|
||||
thr->m_mid = mid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
void JCallbackManager<T>::Send(Args&&... args) {
|
||||
auto thr = this->GetThread();
|
||||
if (!thr) return;
|
||||
thr->m_queue.emplace(std::forward<Args>(args)...);
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void JCallbackThread<T>::Main() {
|
||||
JNIEnv* env;
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_2;
|
||||
args.name = const_cast<char*>(T::GetName());
|
||||
args.group = nullptr;
|
||||
jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon(
|
||||
reinterpret_cast<void**>(&env), &args);
|
||||
if (rs != JNI_OK) return;
|
||||
|
||||
std::unique_lock<wpi::mutex> lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !(m_active && m_queue.empty()); });
|
||||
if (!m_active) break;
|
||||
while (!m_queue.empty()) {
|
||||
if (!m_active) break;
|
||||
auto item = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
auto func = m_func;
|
||||
auto mid = m_mid;
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
item.CallJava(env, func, mid);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
JavaVM* jvm = T::GetJVM();
|
||||
if (jvm) jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class JSingletonCallbackManager : public JCallbackManager<T> {
|
||||
public:
|
||||
static JSingletonCallbackManager<T>& GetInstance() {
|
||||
ATOMIC_STATIC(JSingletonCallbackManager<T>, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
ATOMIC_STATIC_DECL(JSingletonCallbackManager<T>)
|
||||
};
|
||||
|
||||
inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
|
||||
llvm::StringRef excludeFuncPrefix) {
|
||||
// create a throwable
|
||||
static JClass throwableCls(env, "java/lang/Throwable");
|
||||
if (!throwableCls) return "";
|
||||
static jmethodID constructorId = nullptr;
|
||||
if (!constructorId)
|
||||
constructorId = env->GetMethodID(throwableCls, "<init>", "()V");
|
||||
JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
|
||||
|
||||
// retrieve information from the exception.
|
||||
// get method id
|
||||
// getStackTrace returns an array of StackTraceElement
|
||||
static jmethodID getStackTraceId = nullptr;
|
||||
if (!getStackTraceId)
|
||||
getStackTraceId = env->GetMethodID(throwableCls, "getStackTrace",
|
||||
"()[Ljava/lang/StackTraceElement;");
|
||||
|
||||
// call getStackTrace
|
||||
JLocal<jobjectArray> stackTrace(
|
||||
env, static_cast<jobjectArray>(
|
||||
env->CallObjectMethod(throwable, getStackTraceId)));
|
||||
|
||||
if (!stackTrace) return "";
|
||||
|
||||
// get length of the array
|
||||
jsize stackTraceLength = env->GetArrayLength(stackTrace);
|
||||
|
||||
// get toString methodId of StackTraceElement class
|
||||
static JClass stackTraceElementCls(env, "java/lang/StackTraceElement");
|
||||
if (!stackTraceElementCls) return "";
|
||||
static jmethodID toStringId = nullptr;
|
||||
if (!toStringId)
|
||||
toStringId = env->GetMethodID(stackTraceElementCls, "toString",
|
||||
"()Ljava/lang/String;");
|
||||
|
||||
bool haveLoc = false;
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream oss(buf);
|
||||
for (jsize i = 0; i < stackTraceLength; i++) {
|
||||
// add the result of toString method of each element in the result
|
||||
JLocal<jobject> curStackTraceElement(
|
||||
env, env->GetObjectArrayElement(stackTrace, i));
|
||||
|
||||
// call to string on the object
|
||||
JLocal<jstring> stackElementString(
|
||||
env, static_cast<jstring>(
|
||||
env->CallObjectMethod(curStackTraceElement, toStringId)));
|
||||
|
||||
if (!stackElementString) return "";
|
||||
|
||||
// add a line to res
|
||||
JStringRef elem(env, stackElementString);
|
||||
oss << elem << '\n';
|
||||
|
||||
if (func) {
|
||||
// func is caller of immediate caller (if there was one)
|
||||
// or, if we see it, the first user function
|
||||
if (i == 1) {
|
||||
*func = elem.str();
|
||||
} else if (i > 1 && !haveLoc && !excludeFuncPrefix.empty() &&
|
||||
!elem.str().startswith(excludeFuncPrefix)) {
|
||||
*func = elem.str();
|
||||
haveLoc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Finds an exception class and keep it as a global reference.
|
||||
// Similar to JClass, but provides Throw methods.
|
||||
// Use with caution, as the destructor does NOT call DeleteGlobalRef due
|
||||
// to potential shutdown issues with doing so.
|
||||
class JException : public JClass {
|
||||
public:
|
||||
JException() = default;
|
||||
JException(JNIEnv* env, const char* name) : JClass(env, name) {
|
||||
if (m_cls)
|
||||
m_constructor =
|
||||
env->GetMethodID(m_cls, "<init>", "(Ljava/lang/String;)V");
|
||||
}
|
||||
|
||||
void Throw(JNIEnv* env, jstring msg) {
|
||||
jobject exception = env->NewObject(m_cls, m_constructor, msg);
|
||||
env->Throw(static_cast<jthrowable>(exception));
|
||||
}
|
||||
|
||||
void Throw(JNIEnv* env, llvm::StringRef msg) {
|
||||
Throw(env, MakeJString(env, msg));
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_constructor; }
|
||||
|
||||
private:
|
||||
jmethodID m_constructor = nullptr;
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_JNI_UTIL_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_LEB128_H_
|
||||
#define WPIUTIL_SUPPORT_LEB128_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_istream;
|
||||
|
||||
uint64_t SizeUleb128(uint64_t val);
|
||||
uint64_t WriteUleb128(llvm::SmallVectorImpl<char>& dest, uint64_t val);
|
||||
uint64_t ReadUleb128(const char* addr, uint64_t* ret);
|
||||
bool ReadUleb128(raw_istream& is, uint64_t* ret);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_LEB128_H_
|
||||
@@ -1,24 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "priority_mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifdef WPI_HAVE_PRIORITY_MUTEX
|
||||
using mutex = priority_mutex;
|
||||
using recursive_mutex = priority_recursive_mutex;
|
||||
#else
|
||||
using mutex = ::std::mutex;
|
||||
using recursive_mutex = ::std::recursive_mutex;
|
||||
#endif
|
||||
|
||||
} // namespace wpi
|
||||
@@ -1,122 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __linux__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "priority_mutex.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#if defined(__linux__) && defined(WPI_HAVE_PRIORITY_MUTEX)
|
||||
|
||||
#define WPI_HAVE_PRIORITY_CONDITION_VARIABLE 1
|
||||
|
||||
class priority_condition_variable {
|
||||
typedef std::chrono::system_clock clock;
|
||||
|
||||
public:
|
||||
typedef pthread_cond_t* native_handle_type;
|
||||
|
||||
priority_condition_variable() noexcept = default;
|
||||
~priority_condition_variable() noexcept { pthread_cond_destroy(&m_cond); }
|
||||
|
||||
priority_condition_variable(const priority_condition_variable&) = delete;
|
||||
priority_condition_variable& operator=(const priority_condition_variable&) =
|
||||
delete;
|
||||
|
||||
void notify_one() noexcept { pthread_cond_signal(&m_cond); }
|
||||
|
||||
void notify_all() noexcept { pthread_cond_broadcast(&m_cond); }
|
||||
|
||||
void wait(std::unique_lock<priority_mutex>& lock) noexcept {
|
||||
int e = pthread_cond_wait(&m_cond, lock.mutex()->native_handle());
|
||||
if (e) std::terminate();
|
||||
}
|
||||
|
||||
template <typename Predicate>
|
||||
void wait(std::unique_lock<priority_mutex>& lock, Predicate p) {
|
||||
while (!p()) {
|
||||
wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Duration>
|
||||
std::cv_status wait_until(
|
||||
std::unique_lock<priority_mutex>& lock,
|
||||
const std::chrono::time_point<clock, Duration>& atime) {
|
||||
return wait_until_impl(lock, atime);
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
std::cv_status wait_until(
|
||||
std::unique_lock<priority_mutex>& lock,
|
||||
const std::chrono::time_point<Clock, Duration>& atime) {
|
||||
const typename Clock::time_point c_entry = Clock::now();
|
||||
const clock::time_point s_entry = clock::now();
|
||||
const auto delta = atime - c_entry;
|
||||
const auto s_atime = s_entry + delta;
|
||||
|
||||
return wait_until_impl(lock, s_atime);
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration, typename Predicate>
|
||||
bool wait_until(std::unique_lock<priority_mutex>& lock,
|
||||
const std::chrono::time_point<Clock, Duration>& atime,
|
||||
Predicate p) {
|
||||
while (!p()) {
|
||||
if (wait_until(lock, atime) == std::cv_status::timeout) {
|
||||
return p();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Rep, typename Period>
|
||||
std::cv_status wait_for(std::unique_lock<priority_mutex>& lock,
|
||||
const std::chrono::duration<Rep, Period>& rtime) {
|
||||
return wait_until(lock, clock::now() + rtime);
|
||||
}
|
||||
|
||||
template <typename Rep, typename Period, typename Predicate>
|
||||
bool wait_for(std::unique_lock<priority_mutex>& lock,
|
||||
const std::chrono::duration<Rep, Period>& rtime, Predicate p) {
|
||||
return wait_until(lock, clock::now() + rtime, std::move(p));
|
||||
}
|
||||
|
||||
native_handle_type native_handle() { return &m_cond; }
|
||||
|
||||
private:
|
||||
pthread_cond_t m_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
template <typename Dur>
|
||||
std::cv_status wait_until_impl(
|
||||
std::unique_lock<priority_mutex>& lock,
|
||||
const std::chrono::time_point<clock, Dur>& atime) {
|
||||
auto s = std::chrono::time_point_cast<std::chrono::seconds>(atime);
|
||||
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(atime - s);
|
||||
|
||||
struct timespec ts = {
|
||||
static_cast<std::time_t>(s.time_since_epoch().count()),
|
||||
static_cast<long>(ns.count())}; // NOLINT(runtime/int)
|
||||
|
||||
pthread_cond_timedwait(&m_cond, lock.mutex()->native_handle(), &ts);
|
||||
|
||||
return (clock::now() < atime ? std::cv_status::no_timeout
|
||||
: std::cv_status::timeout);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace wpi
|
||||
@@ -1,84 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Allows usage with std::lock_guard without including <mutex> separately
|
||||
#ifdef __linux__
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#define WPI_HAVE_PRIORITY_MUTEX 1
|
||||
|
||||
class priority_recursive_mutex {
|
||||
public:
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
|
||||
constexpr priority_recursive_mutex() noexcept = default;
|
||||
priority_recursive_mutex(const priority_recursive_mutex&) = delete;
|
||||
priority_recursive_mutex& operator=(const priority_recursive_mutex&) = delete;
|
||||
|
||||
// Lock the mutex, blocking until it's available.
|
||||
void lock() { pthread_mutex_lock(&m_mutex); }
|
||||
|
||||
// Unlock the mutex.
|
||||
void unlock() { pthread_mutex_unlock(&m_mutex); }
|
||||
|
||||
// Tries to lock the mutex.
|
||||
bool try_lock() noexcept { return !pthread_mutex_trylock(&m_mutex); }
|
||||
|
||||
pthread_mutex_t* native_handle() { return &m_mutex; }
|
||||
|
||||
private:
|
||||
// Do the equivalent of setting PTHREAD_PRIO_INHERIT and
|
||||
// PTHREAD_MUTEX_RECURSIVE_NP.
|
||||
#ifdef __PTHREAD_MUTEX_HAVE_PREV
|
||||
pthread_mutex_t m_mutex = {
|
||||
{0, 0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, __PTHREAD_SPINS, {0, 0}}};
|
||||
#else
|
||||
pthread_mutex_t m_mutex = {
|
||||
{0, 0, 0, 0x20 | PTHREAD_MUTEX_RECURSIVE_NP, 0, {__PTHREAD_SPINS}}};
|
||||
#endif
|
||||
};
|
||||
|
||||
class priority_mutex {
|
||||
public:
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
|
||||
constexpr priority_mutex() noexcept = default;
|
||||
priority_mutex(const priority_mutex&) = delete;
|
||||
priority_mutex& operator=(const priority_mutex&) = delete;
|
||||
|
||||
// Lock the mutex, blocking until it's available.
|
||||
void lock() { pthread_mutex_lock(&m_mutex); }
|
||||
|
||||
// Unlock the mutex.
|
||||
void unlock() { pthread_mutex_unlock(&m_mutex); }
|
||||
|
||||
// Tries to lock the mutex.
|
||||
bool try_lock() noexcept { return !pthread_mutex_trylock(&m_mutex); }
|
||||
|
||||
pthread_mutex_t* native_handle() { return &m_mutex; }
|
||||
|
||||
private:
|
||||
// Do the equivalent of setting PTHREAD_PRIO_INHERIT.
|
||||
#ifdef __PTHREAD_MUTEX_HAVE_PREV
|
||||
pthread_mutex_t m_mutex = {{0, 0, 0, 0, 0x20, __PTHREAD_SPINS, {0, 0}}};
|
||||
#else
|
||||
pthread_mutex_t m_mutex = {{0, 0, 0, 0x20, 0, {__PTHREAD_SPINS}}};
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
} // namespace wpi
|
||||
@@ -1,115 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_RAW_ISTREAM_H_
|
||||
#define WPIUTIL_SUPPORT_RAW_ISTREAM_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <system_error>
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include "llvm/Twine.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_istream {
|
||||
public:
|
||||
raw_istream() = default;
|
||||
virtual ~raw_istream() = default;
|
||||
|
||||
raw_istream& read(char& c) {
|
||||
read_impl(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_istream& read(unsigned char& c) {
|
||||
read_impl(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_istream& read(signed char& c) {
|
||||
read_impl(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_istream& read(void* data, size_t len) {
|
||||
read_impl(data, len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t readsome(void* data, size_t len) {
|
||||
size_t readlen = std::min(in_avail(), len);
|
||||
if (readlen == 0) return 0;
|
||||
read_impl(data, readlen);
|
||||
return readlen;
|
||||
}
|
||||
|
||||
// Read a line from an input stream (up to a maximum length).
|
||||
// The returned buffer will contain the trailing \n (unless the maximum length
|
||||
// was reached). \r's are stripped from the buffer.
|
||||
// @param buf Buffer for output
|
||||
// @param maxLen Maximum length
|
||||
// @return Line
|
||||
llvm::StringRef getline(llvm::SmallVectorImpl<char>& buf, int maxLen);
|
||||
|
||||
virtual void close() = 0;
|
||||
virtual size_t in_avail() const = 0;
|
||||
|
||||
bool has_error() const { return m_error; }
|
||||
void clear_error() { m_error = false; }
|
||||
|
||||
raw_istream(const raw_istream&) = delete;
|
||||
raw_istream& operator=(const raw_istream&) = delete;
|
||||
|
||||
protected:
|
||||
void error_detected() { m_error = true; }
|
||||
|
||||
private:
|
||||
virtual void read_impl(void* data, size_t len) = 0;
|
||||
|
||||
bool m_error = false;
|
||||
};
|
||||
|
||||
class raw_mem_istream : public raw_istream {
|
||||
public:
|
||||
explicit raw_mem_istream(llvm::StringRef mem);
|
||||
raw_mem_istream(const char* mem, size_t len) : m_cur(mem), m_left(len) {}
|
||||
void close() override;
|
||||
size_t in_avail() const override;
|
||||
|
||||
private:
|
||||
void read_impl(void* data, size_t len) override;
|
||||
|
||||
const char* m_cur;
|
||||
size_t m_left;
|
||||
};
|
||||
|
||||
class raw_fd_istream : public raw_istream {
|
||||
public:
|
||||
raw_fd_istream(const llvm::Twine& filename, std::error_code& ec,
|
||||
size_t bufSize = 4096);
|
||||
raw_fd_istream(int fd, bool shouldClose, size_t bufSize = 4096);
|
||||
~raw_fd_istream() override;
|
||||
void close() override;
|
||||
size_t in_avail() const override;
|
||||
|
||||
private:
|
||||
void read_impl(void* data, size_t len) override;
|
||||
|
||||
char* m_buf;
|
||||
char* m_cur;
|
||||
char* m_end;
|
||||
size_t m_bufSize;
|
||||
int m_fd;
|
||||
bool m_shouldClose;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_RAW_ISTREAM_H_
|
||||
@@ -1,34 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_
|
||||
#define WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_
|
||||
|
||||
#include "support/raw_istream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class NetworkStream;
|
||||
|
||||
class raw_socket_istream : public raw_istream {
|
||||
public:
|
||||
explicit raw_socket_istream(NetworkStream& stream, int timeout = 0)
|
||||
: m_stream(stream), m_timeout(timeout) {}
|
||||
|
||||
void close() override;
|
||||
size_t in_avail() const override;
|
||||
|
||||
private:
|
||||
void read_impl(void* data, size_t len) override;
|
||||
|
||||
NetworkStream& m_stream;
|
||||
int m_timeout;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_
|
||||
@@ -1,42 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_RAW_SOCKET_OSTREAM_H_
|
||||
#define WPIUTIL_SUPPORT_RAW_SOCKET_OSTREAM_H_
|
||||
|
||||
#include "llvm/raw_ostream.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class NetworkStream;
|
||||
|
||||
class raw_socket_ostream : public llvm::raw_ostream {
|
||||
public:
|
||||
raw_socket_ostream(NetworkStream& stream, bool shouldClose)
|
||||
: m_stream(stream), m_shouldClose(shouldClose) {}
|
||||
~raw_socket_ostream();
|
||||
|
||||
void close();
|
||||
|
||||
bool has_error() const { return m_error; }
|
||||
void clear_error() { m_error = false; }
|
||||
|
||||
protected:
|
||||
void error_detected() { m_error = true; }
|
||||
|
||||
private:
|
||||
void write_impl(const char* data, size_t len) override;
|
||||
uint64_t current_pos() const override;
|
||||
|
||||
NetworkStream& m_stream;
|
||||
bool m_error = false;
|
||||
bool m_shouldClose;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_RAW_SOCKET_OSTREAM_H_
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
sha1.hpp - header of
|
||||
|
||||
============
|
||||
SHA-1 in C++
|
||||
============
|
||||
|
||||
100% Public Domain.
|
||||
|
||||
Original C Code
|
||||
-- Steve Reid <steve@edmweb.com>
|
||||
Small changes to fit into bglibs
|
||||
-- Bruce Guenter <bruce@untroubled.org>
|
||||
Translation to simpler C++ Code
|
||||
-- Volker Grabsch <vog@notjusthosting.com>
|
||||
Safety fixes
|
||||
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
|
||||
*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_SHA1_H_
|
||||
#define WPIUTIL_SUPPORT_SHA1_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
} // namespace llvm
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class raw_istream;
|
||||
|
||||
class SHA1 {
|
||||
public:
|
||||
SHA1();
|
||||
void Update(llvm::StringRef s);
|
||||
void Update(raw_istream& is);
|
||||
std::string Final();
|
||||
llvm::StringRef Final(llvm::SmallVectorImpl<char>& buf);
|
||||
static std::string FromFile(llvm::StringRef filename);
|
||||
|
||||
private:
|
||||
uint32_t digest[5];
|
||||
unsigned char buffer[64];
|
||||
size_t buf_size;
|
||||
uint64_t transforms;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_SHA1_H_
|
||||
@@ -1,71 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef WPIUTIL_SUPPORT_TIMESTAMP_H_
|
||||
#define WPIUTIL_SUPPORT_TIMESTAMP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The default implementation used for Now().
|
||||
* In general this is the time returned by the operating system.
|
||||
* @return Time in microseconds.
|
||||
*/
|
||||
uint64_t WPI_NowDefault(void);
|
||||
|
||||
/**
|
||||
* Set the implementation used by WPI_Now().
|
||||
* The implementation must return monotonic time in microseconds to maintain
|
||||
* the contract of WPI_Now().
|
||||
* @param func Function called by WPI_Now() to return the time.
|
||||
*/
|
||||
void WPI_SetNowImpl(uint64_t (*func)(void));
|
||||
|
||||
/**
|
||||
* Return a value representing the current time in microseconds.
|
||||
* The epoch is not defined.
|
||||
* @return Time in microseconds.
|
||||
*/
|
||||
uint64_t WPI_Now(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* The default implementation used for Now().
|
||||
* In general this is the time returned by the operating system.
|
||||
* @return Time in microseconds.
|
||||
*/
|
||||
uint64_t NowDefault(void);
|
||||
|
||||
/**
|
||||
* Set the implementation used by Now().
|
||||
* The implementation must return monotonic time in microseconds to maintain
|
||||
* the contract of Now().
|
||||
* @param func Function called by Now() to return the time.
|
||||
*/
|
||||
void SetNowImpl(uint64_t (*func)());
|
||||
|
||||
/**
|
||||
* Return a value representing the current time in microseconds.
|
||||
* This is a monotonic clock with an undefined epoch.
|
||||
* @return Time in microseconds.
|
||||
*/
|
||||
uint64_t Now(void);
|
||||
|
||||
} // namespace wpi
|
||||
#endif
|
||||
|
||||
#endif // WPIUTIL_SUPPORT_TIMESTAMP_H_
|
||||
Reference in New Issue
Block a user