diff --git a/CMakeLists.txt b/CMakeLists.txt index c2fb041..fb8c69b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,16 +52,17 @@ option(TESSESFRAMEWORK_ENABLE_APPS "Enable Tesses Framework cli apps" ON) option(TESSESFRAMEWORK_INSTALL_DEVELOPMENT "Enable Installing Tesses Framework Development Packages" ON) option(TESSESFRAMEWORK_ENABLE_STATIC "Enable Tesses Framework Static Libraries" ON) option(TESSESFRAMEWORK_ENABLE_SHARED "Enable Tesses Framework Shared Libraries" ON) +option(TESSESFRAMEWORK_LOGTOFILE "TessesFramework Log to file" ON) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include) if(TESSESFRAMEWORK_ENABLE_MBED) if(TESSESFRAMEWORK_EMBED_CERT_BUNDLE) include(cmake/bin2h.cmake) -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/include/CertificateChain.h "#pragma once\n") +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h "#pragma once\n") #target_compile_definitions(TessesFramework PUBLIC TESSESFRAMEWORK_EMBED_CERT_BUNDLE) -bin2h(SOURCE_FILE ${TESSESFRAMEWORK_CERT_BUNDLE_FILE} HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/include/CertificateChain.h VARIABLE_NAME CertificateChain APPEND NULL_TERMINATE) -file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/include/CertificateChain.h "\n") +bin2h(SOURCE_FILE ${TESSESFRAMEWORK_CERT_BUNDLE_FILE} HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h VARIABLE_NAME CertificateChain APPEND NULL_TERMINATE) +file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h "\n") #else() #target_compile_definitions(TessesFramework PUBLIC TESSESFRAMEWORK_CERT_BUNDLE_FILE=${TESSESFRAMEWORK_CERT_BUNDLE_FILE}) @@ -89,13 +90,17 @@ target_include_directories(${TessesFramework_TARGET} PUBLIC ${MBEDTLS_DIR}/inclu target_link_directories(${TessesFramework_TARGET} PUBLIC ${MBEDTLS_DIR}/lib) endif() target_link_libraries(${TessesFramework_TARGET} PUBLIC mbedtls mbedx509 mbedcrypto) -target_include_directories(${TessesFramework_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) endif() target_include_directories(${TessesFramework_TARGET} PUBLIC "$" "$" ) +target_include_directories(${TessesFramework_TARGET} + PUBLIC + "$" + "$" +) if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube") target_link_libraries(${TessesFramework_TARGET} PUBLIC fat) endif() @@ -145,7 +150,8 @@ install(TARGETS ${TessesFrameworkLibs} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) -install(DIRECTORY include/TessesFramework DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/TessesFramework DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(EXPORT TessesFrameworkTargets FILE TessesFrameworkTargets.cmake @@ -157,15 +163,13 @@ install(EXPORT TessesFrameworkTargets include(CMakePackageConfigHelpers) configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/TessesFrameworkConfig.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesFramework) -configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/TessesFrameworkFeatures.h.in "${CMAKE_CURRENT_BINARY_DIR}/TessesFrameworkFeatures.h" +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/TessesFrameworkFeatures.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/TessesFrameworkFeatures.h" INSTALL_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/TessesFramework/TessesFrameworkFeatures.h) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/TessesFrameworkConfig.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesFramework) - -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/TessesFrameworkFeatures.h" -DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/TessesFramework) endif() + if(TESSESFRAMEWORK_ENABLE_EXAMPLES) add_executable(copyfile examples/copyfile.cpp) target_link_libraries(copyfile PUBLIC tessesframework) diff --git a/TessesFrameworkFeatures.h.in b/TessesFrameworkFeatures.h.in index 2c0110e..74156dd 100644 --- a/TessesFrameworkFeatures.h.in +++ b/TessesFrameworkFeatures.h.in @@ -14,5 +14,9 @@ #if TESSES_FRAMEWORK_FLAG_@TESSESFRAMEWORK_ENABLE_THREADING@ #define TESSESFRAMEWORK_ENABLE_THREADING #endif + +#if TESSES_FRAMEWORK_FLAG_@TESSESFRAMEWORK_LOGTOFILE@ +#define TESSESFRAMEWORK_LOGTOFILE +#endif #undef TESSES_FRAMEWORK_FLAG_OFF #undef TESSES_FRAMEWORK_FLAG_ON diff --git a/apps/tfileserver.cpp b/apps/tfileserver.cpp index 2235c11..3fa37ff 100644 --- a/apps/tfileserver.cpp +++ b/apps/tfileserver.cpp @@ -14,8 +14,10 @@ void print_help(const char* name) } int main(int argc, char** argv) { - TF_Init(); + try { + TF_InitWithConsole(); + TF_LOG("INIT"); const char* directory = "wwwroot"; bool spa=false; bool allowListing = false; @@ -53,6 +55,8 @@ int main(int argc, char** argv) directory = argv[i]; } } + + std::cout << "In folder: " << std::filesystem::absolute(directory).string() << std::endl; FileServer fs(directory,allowListing, spa); @@ -60,5 +64,10 @@ int main(int argc, char** argv) server.StartAccepting(); TF_RunEventLoop(); std::cout << "Closing server" << std::endl; + TF_Quit(); +}catch(std::exception& ex) +{ + TF_LOG(ex.what()); +} return 0; -} \ No newline at end of file +} diff --git a/examples/webserverex.cpp b/examples/webserverex.cpp index d95eb83..95fc530 100644 --- a/examples/webserverex.cpp +++ b/examples/webserverex.cpp @@ -86,12 +86,14 @@ class MyOtherWebServer : public IHttpServer public: bool Handle(ServerContext& ctx) { + TF_LOG("IN HANDLE"); if(ctx.path == "/") { std::string name; if(ctx.queryParams.TryGetFirst("name",name)) { std::cout << name << std::endl; + TF_LOG(name); ctx .WithMimeType("text/plain") .WithContentDisposition(HttpUtils::Sanitise(name) + ".txt",false) @@ -114,7 +116,7 @@ class MyOtherWebServer : public IHttpServer int main(int argc, char** argv) { - TF_Init(); + TF_InitWithConsole(); MyOtherWebServer myo; MyWebServer mws; diff --git a/include/TessesFramework/Common.hpp b/include/TessesFramework/Common.hpp index b3ec5a2..e21bafb 100644 --- a/include/TessesFramework/Common.hpp +++ b/include/TessesFramework/Common.hpp @@ -30,9 +30,24 @@ namespace Tesses::Framework { void TF_Init(); + void TF_InitWithConsole(); void TF_ConnectToSelf(uint16_t port); void TF_RunEventLoop(); void TF_RunEventLoopItteration(); bool TF_IsRunning(); void TF_Quit(); + bool TF_GetConsoleEventsEnabled(); + void TF_SetConsoleEventsEnabled(bool flag); + void TF_InitConsole(); + #define TESSESFRAMEWORK_LOGTOFILE + #if defined(TESSESFRAMEWORK_LOGTOFILE) + void TF_Log(std::string dataToLog); + #endif + + + #if defined(TESSESFRAMEWORK_LOGTOFILE) + #define TF_LOG(log) Tesses::Framework::TF_Log(log) + #else + #define TF_LOG(log) + #endif } \ No newline at end of file diff --git a/include/TessesFramework/Streams/NetworkStream.hpp b/include/TessesFramework/Streams/NetworkStream.hpp index 3ead39d..f941af6 100644 --- a/include/TessesFramework/Streams/NetworkStream.hpp +++ b/include/TessesFramework/Streams/NetworkStream.hpp @@ -15,6 +15,7 @@ namespace Tesses::Framework::Streams TcpServer(std::string ip, uint16_t port, int32_t backlog); NetworkStream* GetStream(std::string& ip, uint16_t& port); ~TcpServer(); + bool IsValid(); void Close(); }; class NetworkStream : public Stream { diff --git a/include/TessesFramework/Threading/Thread.hpp b/include/TessesFramework/Threading/Thread.hpp index cb9a51b..c2f9541 100644 --- a/include/TessesFramework/Threading/Thread.hpp +++ b/include/TessesFramework/Threading/Thread.hpp @@ -4,6 +4,7 @@ #include #elif defined(GEKKO) #include +#elif defined(__SWITCH__) #else #include #endif diff --git a/src/Crypto/ClientTLSStream.cpp b/src/Crypto/ClientTLSStream.cpp index 2e13cc7..c93e798 100644 --- a/src/Crypto/ClientTLSStream.cpp +++ b/src/Crypto/ClientTLSStream.cpp @@ -2,7 +2,7 @@ #if defined(TESSESFRAMEWORK_ENABLE_MBED) #if defined(TESSESFRAMEWORK_EMBED_CERT_BUNDLE) -#include "CertificateChain.h" +#include "TessesFramework/CertificateChain.h" #else #include "TessesFramework/TextStreams/StreamReader.hpp" using StreamReader = Tesses::Framework::TextStreams::StreamReader; diff --git a/src/Http/FileServer.cpp b/src/Http/FileServer.cpp index 546becb..2b9eab9 100644 --- a/src/Http/FileServer.cpp +++ b/src/Http/FileServer.cpp @@ -3,6 +3,7 @@ #include "TessesFramework/Filesystem/SubdirFilesystem.hpp" #include #include +#include "TessesFramework/Common.hpp" using LocalFilesystem = Tesses::Framework::Filesystem::LocalFilesystem; using SubdirFilesystem = Tesses::Framework::Filesystem::SubdirFilesystem; using VFSPath = Tesses::Framework::Filesystem::VFSPath; @@ -38,7 +39,7 @@ namespace Tesses::Framework::Http } bool FileServer::SendFile(ServerContext& ctx,VFSPath path) { - + TF_LOG("File: " + path.ToString()); auto strm = this->vfs->OpenFile(path,"rb"); bool retVal = false; if(strm != nullptr) @@ -55,14 +56,18 @@ namespace Tesses::Framework::Http bool FileServer::Handle(ServerContext& ctx) { auto path = HttpUtils::UrlPathDecode(ctx.path); - + if(this->vfs->DirectoryExists(path)) { + TF_LOG("Directory exists"); for(auto f : defaultNames) { - VFSPath p(path,f); - - + VFSPath p=path; + p = p / f; + TF_LOG("Trying " + p.ToString()); + TF_LOG("Before file exists"); + TF_LOG(this->vfs->FileExists(p)?"File Exists" : "File Does Not Exist"); + TF_LOG("After file exists"); if(this->vfs->FileExists(p)) return SendFile(ctx,p); } diff --git a/src/Http/HttpServer.cpp b/src/Http/HttpServer.cpp index 58cd048..01ec078 100644 --- a/src/Http/HttpServer.cpp +++ b/src/Http/HttpServer.cpp @@ -8,6 +8,7 @@ #include "TessesFramework/Http/HttpStream.hpp" #include "TessesFramework/Crypto/MbedHelpers.hpp" #include "TessesFramework/Threading/Mutex.hpp" +#include "TessesFramework/Common.hpp" #include using FileStream = Tesses::Framework::Streams::FileStream; @@ -536,20 +537,36 @@ namespace Tesses::Framework::Http if(http == nullptr) return; auto svr=this->server; auto http = this->http; + TF_LOG("Before Creating Thread"); thrd = new Threading::Thread([svr,http]()->void { while(TF_IsRunning()) { + TF_LOG("after TF_IsRunning"); std::string ip; uint16_t port; auto sock =svr->GetStream(ip,port); - if(sock == nullptr) return; + + TF_LOG("New Host IP: " + ip + ":" + std::to_string(port)); + + if(sock == nullptr) + { + std::cout << "STREAM ERROR" << std::endl; + return; + } + TF_LOG("Before entering socket thread"); Threading::Thread thrd2([sock,http,ip,port]()->void { + TF_LOG("In thread to process"); HttpServer::Process(*sock,*http,ip,port,false); + TF_LOG("In thread after process"); delete sock; }); + TF_LOG("Before attach"); thrd2.Detach(); + TF_LOG("After attach"); } }); + TF_LOG("Before printing interfaces"); + std::cout << "\e[34mInterfaces:\n"; for(auto _ip : NetworkStream::GetIPs()) { @@ -558,7 +575,9 @@ namespace Tesses::Framework::Http std::cout << "\e[35mhttp://"; std::cout << _ip.second << ":" << std::to_string(this->port) << "/\n"; } + if(!svr->IsValid()) std::cout << "\e[31mError, we failed to bind or something\e[39m\n" << std::endl; std::cout << "\e[31mAlmost Ready to Listen\e[39m\n"; + TF_LOG("After printing interfaces"); } HttpServer::~HttpServer() { @@ -834,7 +853,7 @@ namespace Tesses::Framework::Http } void HttpServer::Process(Stream& strm, IHttpServer& server, std::string ip, uint16_t port, bool encrypted) { - + TF_LOG("In process"); while(true) { BufferedStream bStrm(strm); @@ -863,6 +882,8 @@ namespace Tesses::Framework::Http ctx.originalPath = pp[0]; ctx.path = ctx.originalPath; + TF_LOG(ctx.method + " with path " + ctx.path); + auto queryPart = pp[1]; if(!queryPart.empty()) { diff --git a/src/Streams/NetworkStream.cpp b/src/Streams/NetworkStream.cpp index 97fd3d5..1a6eb09 100644 --- a/src/Streams/NetworkStream.cpp +++ b/src/Streams/NetworkStream.cpp @@ -1,6 +1,6 @@ #include "TessesFramework/Streams/NetworkStream.hpp" #include "TessesFramework/Http/HttpUtils.hpp" - +#include using HttpUtils = Tesses::Framework::Http::HttpUtils; #if defined(TESSESFRAMEWORK_ENABLE_NETWORKING) @@ -36,7 +36,7 @@ extern "C" { #if defined(GEKKO) extern "C" uint32_t if_config( char *local_ip, char *netmask, char *gateway,bool use_dhcp, int max_retries); -#elif !defined(_WIN32) && !defined(__ANDROID__) +#elif !defined(_WIN32) && !defined(__ANDROID__) && !defined(__SWITCH__) #include #endif @@ -75,7 +75,7 @@ namespace Tesses::Framework::Streams { char gateway[16]; if_config(localIp,netmask, gateway, true, 1); ipConfig.push_back(std::pair("net",localIp)); - #elif defined(_WIN32) || defined(__ANDROID__) + #elif defined(_WIN32) || defined(__ANDROID__) || defined(__SWITCH__) #else struct ifaddrs *ifAddrStruct = NULL; @@ -228,6 +228,7 @@ namespace Tesses::Framework::Streams { this->sock = NETWORK_SOCKET(AF_INET, SOCK_STREAM, 0); if(this->sock < 0) { + std::cout << "FAILED TO CREATE SOCKET FOR SOME REASON" << std::endl; this->valid=false; return; } @@ -245,17 +246,23 @@ namespace Tesses::Framework::Streams { #endif if(NETWORK_BIND(this->sock, (const sockaddr*)&addr, (socklen_t)sizeof(addr)) != 0) { + std::cout << "FAILED TO BIND FOR SOME REASON" << std::endl; this->valid = false; return; } if(NETWORK_LISTEN(this->sock, backlog) != 0) { + std::cout << "FAILED TO LISTEN FOR SOME REASON" << std::endl; this->valid = false; return; } this->valid = true; } + bool TcpServer::IsValid() + { + return this->valid; + } TcpServer::TcpServer(std::string ip, uint16_t port, int32_t backlog) { this->owns=true; @@ -345,14 +352,14 @@ namespace Tesses::Framework::Streams { if(ipV6) { #if defined(AF_INET6) - this->sock = socket(AF_INET6, datagram ? SOCK_DGRAM : SOCK_STREAM, 0); + this->sock = NETWORK_SOCKET(AF_INET6, datagram ? SOCK_DGRAM : SOCK_STREAM, 0); if(this->sock >= 0) this->success=true; #endif } else { #if defined(AF_INET) - this->sock = socket(AF_INET, datagram ? SOCK_DGRAM : SOCK_STREAM, 0); + this->sock = NETWORK_SOCKET(AF_INET, datagram ? SOCK_DGRAM : SOCK_STREAM, 0); if(this->sock >= 0) this->success=true; #endif } @@ -563,6 +570,7 @@ namespace Tesses::Framework::Streams { int noDelay2 = noDelay; NETWORK_SETSOCKOPT(this->sock, SOL_SOCKET, TCP_NODELAY, (const char*)&noDelay2,(socklen_t)sizeof(noDelay2)); } + } #else namespace Tesses::Framework::Streams { @@ -587,6 +595,10 @@ TcpServer::~TcpServer() { } +bool TcpServer::IsValid() + { + return this->valid; + } void TcpServer::Close() { @@ -659,4 +671,4 @@ void NetworkStream::SetNoDelay(bool noDelay) } } -#endif \ No newline at end of file +#endif diff --git a/src/TF_Init.cpp b/src/TF_Init.cpp index 7102e13..ea6e397 100644 --- a/src/TF_Init.cpp +++ b/src/TF_Init.cpp @@ -5,6 +5,10 @@ #if defined(_WIN32) #include #include +#elif defined(__SWITCH__) +extern "C" { +#include +} #elif defined(GEKKO) #include #include @@ -25,10 +29,23 @@ static GXRModeObj *rmode = NULL; #endif +#if defined(TESSESFRAMEWORK_ENABLE_THREADING) +#include "TessesFramework/Threading/Mutex.hpp" +#endif + namespace Tesses::Framework { + + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) && (defined(GEKKO) || defined(__SWITCH__)) + namespace Threading + { + extern void JoinAllThreads(); + extern void LookForFinishedThreads(); + } + #endif volatile static bool isRunningSig=true; volatile static std::atomic isRunning; + volatile static std::atomic gaming_console_events=true; void TF_ConnectToSelf(uint16_t port) { Tesses::Framework::Streams::NetworkStream ns("127.0.0.1",port,false,false,false); @@ -49,21 +66,52 @@ namespace Tesses::Framework TF_RunEventLoopItteration(); } } + #if defined(__SWITCH__) + bool initedConsole=false; + PadState default_pad; + #endif void TF_RunEventLoopItteration() { + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) && (defined(GEKKO) || defined(__SWITCH__)) + Tesses::Framework::Threading::LookForFinishedThreads(); + #endif if(!isRunningSig) isRunning=false; #if defined(GEKKO) - PAD_ScanPads(); - if(PAD_ButtonsDown(0) & PAD_BUTTON_START) isRunning=false; + if(gaming_console_events) + { + PAD_ScanPads(); + if(PAD_ButtonsDown(0) & PAD_BUTTON_START) isRunning=false; + } + #elif defined(__SWITCH__) + if(gaming_console_events) + { + if(!appletMainLoop()) isRunning=false; + + padUpdate(&default_pad); + + u64 kDown = padGetButtonsDown(&default_pad); + + if (kDown & HidNpadButton_Plus) + isRunning=false; + + + if(initedConsole) + consoleUpdate(NULL); + + + } #endif + } void TF_Quit() { isRunning=false; + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) && (defined(GEKKO) || defined(__SWITCH__)) + Tesses::Framework::Threading::JoinAllThreads(); + #endif } - void TF_Init() { #if defined(_WIN32) @@ -91,6 +139,29 @@ if (iResult != 0) { #endif WPAD_Init(); #endif + #elif defined(__SWITCH__) + padConfigureInput(1, HidNpadStyleSet_NpadStandard); + padInitializeDefault(&default_pad); + socketInitializeDefault(); + + // Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller) + #else + signal(SIGPIPE,SIG_IGN); + signal(SIGINT,_sigInt); + #endif + + } + bool TF_GetConsoleEventsEnabled() + { + return gaming_console_events; + } + void TF_SetConsoleEventsEnabled(bool flag) + { + gaming_console_events=flag; + } + void TF_InitConsole() + { + #if defined(GEKKO) rmode = VIDEO_GetPreferredMode(NULL); // Allocate memory for the display in the uncached region @@ -121,9 +192,34 @@ if (iResult != 0) { // we can use variables for this with format codes too // e.g. printf ("\x1b[%d;%dH", row, column ); printf("\x1b[2;0H"); - #else - signal(SIGPIPE,SIG_IGN); - signal(SIGINT,_sigInt); + #elif defined(__SWITCH__) + consoleInit(NULL); + initedConsole=true; #endif } + void TF_InitWithConsole() + { + TF_Init(); + TF_InitConsole(); + #if defined(TESSESFRAMEWORK_LOGTOFILE) + printf("Enabled Logging\n"); + #endif + } + #if defined(TESSESFRAMEWORK_LOGTOFILE) + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + Tesses::Framework::Threading::Mutex log_mtx; + #endif + void TF_Log(std::string txtToLog) + { + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + log_mtx.Lock(); + #endif + FILE* f = fopen("TF_Log.log","a"); + fprintf(f,"%s\n",txtToLog.c_str()); + fclose(f); + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + log_mtx.Unlock(); + #endif + } + #endif } \ No newline at end of file diff --git a/src/Threading/Mutex.cpp b/src/Threading/Mutex.cpp index f1d296d..f387c94 100644 --- a/src/Threading/Mutex.cpp +++ b/src/Threading/Mutex.cpp @@ -5,6 +5,10 @@ #include #elif defined(GEKKO) #include +#elif defined(__SWITCH__) +extern "C" { +#include +} #else #include #endif @@ -19,6 +23,8 @@ namespace Tesses::Framework::Threading HANDLE mtx; #elif defined(GEKKO) mutex_t mtx; + #elif defined(__SWITCH__) + RMutex mtx; #else pthread_mutex_t mtx; pthread_mutexattr_t attr; @@ -29,6 +35,8 @@ namespace Tesses::Framework::Threading CloseHandle(mtx); #elif defined(GEKKO) LWP_MutexDestroy(mtx); + #elif defined(__SWITCH__) + #else pthread_mutex_destroy(&mtx); pthread_mutexattr_destroy(&attr); @@ -45,6 +53,8 @@ namespace Tesses::Framework::Threading #elif defined(GEKKO) md->mtx = LWP_MUTEX_NULL; LWP_MutexInit(&md->mtx, true); + #elif defined(__SWITCH__) + rmutexInit(&md->mtx); #else pthread_mutexattr_init(&md->attr); pthread_mutexattr_settype(&md->attr,PTHREAD_MUTEX_RECURSIVE); @@ -61,6 +71,8 @@ namespace Tesses::Framework::Threading WaitForSingleObject(md->mtx, INFINITE); #elif defined(GEKKO) LWP_MutexLock(md->mtx); + #elif defined(__SWITCH__) + rmutexLock(&md->mtx); #else pthread_mutex_lock(&md->mtx); #endif @@ -74,6 +86,8 @@ namespace Tesses::Framework::Threading ReleaseMutex(md->mtx); #elif defined(GEKKO) LWP_MutexUnlock(md->mtx); + #elif defined(__SWITCH__) + rmutexUnlock(&md->mtx); #else pthread_mutex_unlock(&md->mtx); #endif @@ -87,6 +101,8 @@ namespace Tesses::Framework::Threading return WaitForSingleObject(md->mtx, 100) == WAIT_OBJECT_0; #elif defined(GEKKO) return LWP_MutexTryLock(md->mtx) == 0; + #elif defined(__SWITCH__) + return rmutexTryLock(&md->mtx); #else return pthread_mutex_trylock(&md->mtx) == 0; #endif diff --git a/src/Threading/Thread.cpp b/src/Threading/Thread.cpp index 113abc7..9cb3ff8 100644 --- a/src/Threading/Thread.cpp +++ b/src/Threading/Thread.cpp @@ -1,10 +1,150 @@ + #include "TessesFramework/Threading/Thread.hpp" #include - +#include +#include "TessesFramework/Threading/Mutex.hpp" +#include "TessesFramework/Common.hpp" +#if defined(__SWITCH__) +extern "C" { +#include +#include +} +using NxThread = Thread; +#endif namespace Tesses::Framework::Threading { - #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + + #if defined(__SWITCH__) || defined(GEKKO) + Mutex needed_to_be_joined_mtx; + class NeedToBeJoinnedThread { + + #if defined(GEKKO) + static void* cb(void* data) + #elif defined(__SWITCH__) + static void cb(void* data) + #endif + { + + auto ntbjt = static_cast(data); + + ntbjt->hasInvoked=true; + TF_LOG("About to call thread func"); + if(ntbjt->_cb) + ntbjt->_cb(); + TF_LOG("Finished calling thread func"); + ntbjt->hasExited=true; + + #if defined(GEKKO) + return NULL; + #endif + } + std::function _cb; + std::atomic hasInvoked=false; + #if defined(__SWITCH__) + NxThread thrd; + #elif defined(GEKKO) + lwp_t thrd; + #endif + public: + NeedToBeJoinnedThread(std::function cb) + { + this->_cb = cb; + joinned=false; + joinning=false; + hasExited=false; + #if defined(GEKKO) + LWP_CreateThread(&thrd, cb, static_cast(this), nullptr,12000, 98); + #elif defined(__SWITCH__) + TF_LOG("Before Thread create"); + Result rc = threadCreate(&thrd,this->cb, + static_cast(this), NULL, 0x100000, + 0x20 , 2); + if (R_FAILED(rc)) + { + this->hasExited=true; + this->joinned=true; + TF_LOG("Failed to create Thread"); + return; + } + + TF_LOG("After Thread create, before starting"); + rc = threadStart(&thrd); + if (R_FAILED(rc)) + { + TF_LOG("Failed to start thread"); + threadClose(&thrd); + this->hasExited=true; + this->joinned=true; + return; + } + TF_LOG("Starting"); + #endif + } + std::atomic joinned; + std::atomic joinning; + std::atomic hasExited; + void Join(); + void WaitTillInvoked() + { + while(!hasInvoked); + TF_LOG("Invoked!"); + } + }; + + void NeedToBeJoinnedThread::Join() + { + if(joinning) + { + return; + } + joinning=true; + #if defined(__SWITCH__) + threadWaitForExit(&this->thrd); + threadClose(&this->thrd); + #elif defined(GEKKO) + void* res; + LWP_JoinThread(this->thrd,&res); + #endif + joinned=true; + //start the joinning process + } + + std::vector> needToBeJoinnedThread; + void JoinAllThreads() + { + needed_to_be_joined_mtx.Lock(); + for(auto item : needToBeJoinnedThread) + { + item->Join(); + } + needToBeJoinnedThread.clear(); + needed_to_be_joined_mtx.Unlock(); + + } + void LookForFinishedThreads() + { + + needed_to_be_joined_mtx.Lock(); + for(auto index = needToBeJoinnedThread.begin(); index < needToBeJoinnedThread.end(); index++) + { + auto& idx = *index; + if(idx->hasExited) + { + if(idx->joinning) while(!idx->joinned); + TF_LOG("ABOUT TO JOIN"); + idx->Join(); + TF_LOG("JOINNED"); + needToBeJoinnedThread.erase(index); + index--; + } + } + needed_to_be_joined_mtx.Unlock(); + } + + #endif class ThreadHiddenFieldData : public HiddenFieldData { public: #if defined(_WIN32) @@ -16,7 +156,8 @@ namespace Tesses::Framework::Threading #elif defined(GEKKO) lwp_t thrd; - + #elif defined(__SWITCH__) || defined(GEKKO) + std::shared_ptr thread; #else pthread_t thrd; #endif @@ -30,6 +171,8 @@ namespace Tesses::Framework::Threading #if defined(_WIN32) static DWORD __stdcall cb(LPVOID data) + #elif defined(__SWITCH__) + static void cb(void* data) #else static void* cb(void* data) #endif @@ -39,8 +182,10 @@ namespace Tesses::Framework::Threading auto fn = thrd->fn; thrd->hasInvoked=true; fn(); - #if !defined(_WIN32) + #if !defined(_WIN32) && !defined(__SWITCH__) return NULL; + #elif(__SWITCH__) + #else return 0; #endif @@ -55,26 +200,37 @@ namespace Tesses::Framework::Threading data->fn = fn; #if defined(_WIN32) data->thrd = CreateThread(NULL,0,cb,static_cast(data), 0, &data->thrdId); - #elif defined(GEKKO) - auto res = LWP_CreateThread(&data->thrd, cb, static_cast(data), nullptr,12000, 98); + while(!data->hasInvoked); + #elif defined(__SWITCH__) || defined(GEKKO) + data->thread = std::make_shared(fn); + data->thread->WaitTillInvoked(); + //threadCreate(,cb,static_cast(data),NULL,8000000,0x00,-2); #else pthread_create(&data->thrd,NULL,cb,static_cast(data)); + while(!data->hasInvoked); //thrd_create(&thrd, cb, static_cast(this)); #endif - while(!data->hasInvoked); + #endif } void Thread::Detach() { #if defined(TESSESFRAMEWORK_ENABLE_THREADING) auto data = this->data.GetField(); - #if !defined(GEKKO) + #if defined(_WIN32) CloseHandle(data->thrd); + #elif defined(__SWITCH__) || defined(GEKKO) + TF_LOG("Detaching"); + needed_to_be_joined_mtx.Lock(); + needToBeJoinnedThread.push_back(data->thread); + needed_to_be_joined_mtx.Unlock(); + + TF_LOG("Detached!"); #else pthread_detach(data->thrd); #endif - #endif + #endif } @@ -84,9 +240,8 @@ namespace Tesses::Framework::Threading auto data = this->data.GetField(); #if defined(_WIN32) WaitForSingleObject(data->thrd, INFINITE); - #elif defined(GEKKO) - void* res; - LWP_JoinThread(data->thrd,&res); + #elif defined(__SWITCH__) || defined(GEKKO) + data->thread->Join(); #else pthread_join(data->thrd,NULL); #endif