Switches JNI to use SafeThread from WPIUtil (#282)

This commit is contained in:
Thad House
2016-10-23 14:18:46 -07:00
committed by Peter Johnson
parent 499da6d08d
commit 4f4c52d6d5
4 changed files with 6 additions and 130 deletions

View File

@@ -15,8 +15,8 @@
#include "HAL/Interrupts.h"
#include "HALUtil.h"
#include "SafeThread.h"
#include "edu_wpi_first_wpilibj_hal_InterruptJNI.h"
#include "support/SafeThread.h"
TLogLevel interruptJNILogLevel = logERROR;
@@ -38,7 +38,7 @@ TLogLevel interruptJNILogLevel = logERROR;
//
// We don't want to use a FIFO here. If the user code takes too long to
// process, we will just ignore the redundant wakeup.
class InterruptThreadJNI : public SafeThread {
class InterruptThreadJNI : public wpi::SafeThread {
public:
void Main();
@@ -49,7 +49,7 @@ class InterruptThreadJNI : public SafeThread {
jobject m_param = nullptr;
};
class InterruptJNI : public SafeThreadOwner<InterruptThreadJNI> {
class InterruptJNI : public wpi::SafeThreadOwner<InterruptThreadJNI> {
public:
void SetFunc(JNIEnv* env, jobject func, jmethodID mid, jobject param);

View File

@@ -16,8 +16,8 @@
#include <thread>
#include "HALUtil.h"
#include "HAL/cpp/Log.h"
#include "SafeThread.h"
#include "edu_wpi_first_wpilibj_hal_NotifierJNI.h"
#include "support/SafeThread.h"
// set the logging level
TLogLevel notifierJNILogLevel = logWARNING;
@@ -40,7 +40,7 @@ TLogLevel notifierJNILogLevel = logWARNING;
//
// We don't want to use a FIFO here. If the user code takes too long to
// process, we will just ignore the redundant wakeup.
class NotifierThreadJNI : public SafeThread {
class NotifierThreadJNI : public wpi::SafeThread {
public:
void Main();
@@ -50,7 +50,7 @@ class NotifierThreadJNI : public SafeThread {
uint64_t m_currentTime;
};
class NotifierJNI : public SafeThreadOwner<NotifierThreadJNI> {
class NotifierJNI : public wpi::SafeThreadOwner<NotifierThreadJNI> {
public:
void SetFunc(JNIEnv *env, jobject func, jmethodID mid);

View File

@@ -1,31 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015-2016. 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. */
/*----------------------------------------------------------------------------*/
#include "SafeThread.h"
// using namespace nt;
void detail::SafeThreadOwnerBase::Start(SafeThread* thr) {
SafeThread* curthr = nullptr;
SafeThread* newthr = thr;
if (!m_thread.compare_exchange_strong(curthr, newthr)) {
delete newthr;
return;
}
std::thread([=]() {
newthr->Main();
delete newthr;
}).detach();
}
void detail::SafeThreadOwnerBase::Stop() {
SafeThread* thr = m_thread.exchange(nullptr);
if (!thr) return;
std::lock_guard<std::mutex> lock(thr->m_mutex);
thr->m_active = false;
thr->m_cond.notify_one();
}

View File

@@ -1,93 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015-2016. 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 NT_SAFETHREAD_H_
#define NT_SAFETHREAD_H_
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
// namespace nt {
// Base class for SafeThreadOwner threads.
class SafeThread {
public:
virtual ~SafeThread() = default;
virtual void Main() = 0;
std::mutex m_mutex;
bool m_active = true;
std::condition_variable m_cond;
};
namespace detail {
// Non-template proxy base class for common proxy code.
class SafeThreadProxyBase {
public:
SafeThreadProxyBase(SafeThread* thr) : m_thread(thr) {
if (!m_thread) return;
std::unique_lock<std::mutex>(m_thread->m_mutex).swap(m_lock);
if (!m_thread->m_active) {
m_lock.unlock();
m_thread = nullptr;
return;
}
}
explicit operator bool() const { return m_thread != nullptr; }
std::unique_lock<std::mutex>& GetLock() { return m_lock; }
protected:
SafeThread* m_thread;
std::unique_lock<std::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:
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();
protected:
SafeThreadOwnerBase() { m_thread = nullptr; }
SafeThreadOwnerBase(const SafeThreadOwnerBase&) = delete;
SafeThreadOwnerBase& operator=(const SafeThreadOwnerBase&) = delete;
~SafeThreadOwnerBase() { Stop(); }
void Start(SafeThread* thr);
SafeThread* GetThread() { return m_thread.load(); }
private:
std::atomic<SafeThread*> m_thread;
};
} // 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() { return Proxy(detail::SafeThreadOwnerBase::GetThread()); }
};
//} // namespace nt
#endif // NT_SAFETHREAD_H_