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
FtpServer (std::uint16_t port_);
/// \brief Handle when start button is pressed
void handleStartButton ();
/// \brief Handle when network is found
void handleNetworkFound ();
/// \brief Handle when stop button is pressed
void handleStopButton ();
/// \brief Handle when network is lost
void handleNetworkLost ();
/// \brief Server loop
void loop ();

View File

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

View File

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

View File

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

View File

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

View File

@ -40,6 +40,17 @@ bool platform::init ()
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 ()
{
if (!appletMainLoop ())