Auto start/stop

More fine-grained locking
This commit is contained in:
Michael Theall 2020-04-08 16:53:47 -05:00
parent b925088965
commit 49b2571336
6 changed files with 121 additions and 54 deletions

View File

@ -58,11 +58,11 @@ private:
/// \param port_ Port to listen on /// \param port_ Port to listen on
FtpServer (std::uint16_t port_); FtpServer (std::uint16_t port_);
/// \brief Handle when start button is pressed /// \brief Handle when network is found
void handleStartButton (); void handleNetworkFound ();
/// \brief Handle when stop button is pressed /// \brief Handle when network is lost
void handleStopButton (); void handleNetworkLost ();
/// \brief Server loop /// \brief Server loop
void loop (); void loop ();

View File

@ -34,6 +34,9 @@ namespace platform
/// \brief Initialize platform /// \brief Initialize platform
bool init (); bool init ();
/// \brief Whether network is visible
bool networkVisible ();
/// \brief Platform loop /// \brief Platform loop
bool loop (); bool loop ();

View File

@ -34,10 +34,13 @@
#include "gfx.h" #include "gfx.h"
#include <malloc.h>
#include <atomic>
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include <malloc.h> #include <mutex>
namespace namespace
{ {
@ -51,9 +54,11 @@ constexpr auto SOCU_BUFFERSIZE = 0x100000;
static_assert (SOCU_BUFFERSIZE % SOCU_ALIGN == 0); static_assert (SOCU_BUFFERSIZE % SOCU_ALIGN == 0);
/// \brief Whether soc:u is active /// \brief Whether soc:u is active
bool s_socuActive = false; std::atomic<bool> s_socuActive = false;
/// \brief soc:u buffer /// \brief soc:u buffer
u32 *s_socuBuffer = nullptr; u32 *s_socuBuffer = nullptr;
/// \brief ac:u fence
platform::Mutex s_acuFence;
/// \brief Clear color /// \brief Clear color
constexpr auto CLEAR_COLOR = 0x204B7AFF; constexpr auto CLEAR_COLOR = 0x204B7AFF;
@ -99,6 +104,20 @@ C3D_Tex s_gfxTexture;
/// \brief Texture atlas metadata /// \brief Texture atlas metadata
Tex3DS_Texture s_gfxT3x; Tex3DS_Texture s_gfxT3x;
/// \brief Get network visibility
bool getNetworkVisibility ()
{
// serialize ac:u access from multiple threads
auto lock = std::scoped_lock (s_acuFence);
// get wifi status
std::uint32_t wifi = 0;
if (R_FAILED (ACU_GetWifiStatus (&wifi)) || !wifi)
return false;
return true;
}
/// \brief Start network /// \brief Start network
void startNetwork () void startNetwork ()
{ {
@ -106,9 +125,7 @@ void startNetwork ()
if (s_socuActive) if (s_socuActive)
return; return;
// get wifi status if (!getNetworkVisibility ())
std::uint32_t wifi = 0;
if (R_FAILED (ACU_GetWifiStatus (&wifi)) || !wifi)
return; return;
// allocate soc:u buffer // allocate soc:u buffer
@ -302,6 +319,15 @@ bool platform::init ()
return true; return true;
} }
bool platform::networkVisible ()
{
// check if soc:u is active
if (!s_socuActive)
return false;
return getNetworkVisibility ();
}
bool platform::loop () bool platform::loop ()
{ {
if (!aptMainLoop ()) if (!aptMainLoop ())

View File

@ -21,6 +21,7 @@
#include "ftpServer.h" #include "ftpServer.h"
#include "fs.h" #include "fs.h"
#include "platform.h"
#include "imgui.h" #include "imgui.h"
@ -35,6 +36,13 @@
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
#define LOCKED(x) \
do \
{ \
auto const lock = std::scoped_lock (m_lock); \
x; \
} while (0)
namespace namespace
{ {
/// \brief Application start time /// \brief Application start time
@ -60,8 +68,6 @@ FtpServer::FtpServer (std::uint16_t const port_)
{ {
Log::bind (m_log); Log::bind (m_log);
handleStartButton ();
m_thread = platform::Thread (std::bind (&FtpServer::threadFunc, this)); m_thread = platform::Thread (std::bind (&FtpServer::threadFunc, this));
} }
@ -78,27 +84,11 @@ void FtpServer::draw ()
#else #else
ImGui::SetNextWindowSize (ImVec2 (width, height)); ImGui::SetNextWindowSize (ImVec2 (width, height));
#endif #endif
ImGui::SetNextWindowFocus ();
ImGui::Begin (STATUS_STRING, ImGui::Begin (STATUS_STRING,
nullptr, nullptr,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
{
auto const lock = std::scoped_lock (m_lock);
if (!m_socket)
{
if (ImGui::Button ("Start"))
handleStartButton ();
}
else if (ImGui::Button ("Stop"))
handleStopButton ();
if (m_socket)
{
ImGui::SameLine ();
ImGui::TextUnformatted (m_name.c_str ());
}
}
{ {
auto const lock = std::scoped_lock (s_lock); auto const lock = std::scoped_lock (s_lock);
if (!s_freeSpace.empty ()) if (!s_freeSpace.empty ())
@ -108,6 +98,15 @@ void FtpServer::draw ()
} }
} }
{
ImGui::SameLine ();
auto const lock = std::scoped_lock (m_lock);
if (m_socket)
ImGui::TextUnformatted (m_name.c_str ());
else
ImGui::TextUnformatted ("Waiting for network...");
}
ImGui::Separator (); ImGui::Separator ();
#ifdef _3DS #ifdef _3DS
@ -132,8 +131,11 @@ void FtpServer::draw ()
ImGui::Separator (); ImGui::Separator ();
#endif #endif
for (auto &session : m_sessions) {
session->draw (); auto lock = std::scoped_lock (m_lock);
for (auto &session : m_sessions)
session->draw ();
}
ImGui::End (); ImGui::End ();
} }
@ -161,10 +163,13 @@ std::time_t FtpServer::startTime ()
return s_startTime; return s_startTime;
} }
void FtpServer::handleStartButton () void FtpServer::handleNetworkFound ()
{ {
if (m_socket) {
return; auto lock = std::scoped_lock (m_lock);
if (m_socket)
return;
}
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
@ -196,49 +201,66 @@ void FtpServer::handleStartButton ()
Log::info ("Started server at %s\n", m_name.c_str ()); Log::info ("Started server at %s\n", m_name.c_str ());
m_socket = std::move (socket); LOCKED (m_socket = std::move (socket));
} }
void FtpServer::handleStopButton () void FtpServer::handleNetworkLost ()
{ {
m_socket.reset (); {
UniqueSocket sock;
LOCKED (sock = std::move (m_socket));
}
Log::info ("Stopped server at %s\n", m_name.c_str ()); Log::info ("Stopped server at %s\n", m_name.c_str ());
} }
void FtpServer::loop () void FtpServer::loop ()
{ {
if (platform::networkVisible ())
handleNetworkFound ();
// poll listen socket
if (m_socket)
{ {
// poll listen socket Socket::PollInfo info{*m_socket, POLLIN, 0};
auto const lock = std::scoped_lock (m_lock); if (Socket::poll (&info, 1, 0ms) > 0)
if (m_socket)
{ {
Socket::PollInfo info{*m_socket, POLLIN, 0}; auto socket = m_socket->accept ();
if (Socket::poll (&info, 1, 0ms) > 0) if (socket)
{ {
auto socket = m_socket->accept (); auto session = FtpSession::create (std::move (socket));
if (socket) LOCKED (m_sessions.emplace_back (std::move (session)));
m_sessions.emplace_back (FtpSession::create (std::move (socket)));
else
handleStopButton ();
} }
else
handleNetworkLost ();
} }
} }
// remove dead sessions
for (auto it = std::begin (m_sessions); it != std::end (m_sessions);)
{ {
auto const &session = *it; std::vector<UniqueFtpSession> deadSessions;
if (session->dead ()) {
it = m_sessions.erase (it); // remove dead sessions
else auto lock = std::scoped_lock (m_lock);
++it; auto it = std::begin (m_sessions);
while (it != std::end (m_sessions))
{
auto &session = *it;
if (session->dead ())
{
deadSessions.emplace_back (std::move (session));
it = m_sessions.erase (it);
}
else
++it;
}
}
} }
// poll sessions // poll sessions
if (!m_sessions.empty ()) if (!m_sessions.empty ())
{ {
if (!FtpSession::poll (m_sessions)) if (!FtpSession::poll (m_sessions))
handleStopButton (); handleNetworkLost ();
} }
// avoid busy polling in background thread // avoid busy polling in background thread
else else

View File

@ -162,6 +162,11 @@ bool platform::init ()
return true; return true;
} }
bool platform::networkVisible ()
{
return true;
}
bool platform::loop () bool platform::loop ()
{ {
bool inactive; bool inactive;

View File

@ -40,6 +40,17 @@ bool platform::init ()
return true; return true;
} }
bool platform::networkVisible ()
{
NifmInternetConnectionType type;
std::uint32_t wifi;
NifmInternetConnectionStatus status;
if (R_FAILED (nifmGetInternetConnectionStatus (&type, &wifi, &status)))
return false;
return status == NifmInternetConnectionStatus_Connected;
}
bool platform::loop () bool platform::loop ()
{ {
if (!appletMainLoop ()) if (!appletMainLoop ())