mirror of
				https://github.com/Atmosphere-NX/Atmosphere-libs.git
				synced 2025-10-31 19:45:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			182 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) Atmosphère-NX
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms and conditions of the GNU General Public License,
 | |
|  * version 2, as published by the Free Software Foundation.
 | |
|  *
 | |
|  * This program is distributed in the hope it will be useful, but WITHOUT
 | |
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | |
|  * more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| #include <stratosphere.hpp>
 | |
| #include "lm_log_server_proxy.hpp"
 | |
| #include "lm_sd_card_logger.hpp"
 | |
| #include "lm_log_buffer.hpp"
 | |
| #include "lm_event_log_transmitter.hpp"
 | |
| 
 | |
| namespace ams::lm::srv {
 | |
| 
 | |
|     bool IsSleeping();
 | |
| 
 | |
|     namespace {
 | |
| 
 | |
|         alignas(os::ThreadStackAlignment) u8 g_flush_thread_stack[8_KB];
 | |
| 
 | |
|         constinit u8 g_fs_heap[32_KB];
 | |
|         constinit lmem::HeapHandle g_fs_heap_handle;
 | |
| 
 | |
|         constinit os::ThreadType g_flush_thread = {};
 | |
| 
 | |
|         os::Event g_stop_event(os::EventClearMode_ManualClear);
 | |
|         os::Event g_sd_logging_event(os::EventClearMode_ManualClear);
 | |
|         os::Event g_host_connection_event(os::EventClearMode_ManualClear);
 | |
| 
 | |
|         constinit std::unique_ptr<fs::IEventNotifier> g_sd_card_detection_event_notifier;
 | |
|         os::SystemEvent g_sd_card_detection_event;
 | |
| 
 | |
|         void *AllocateForFs(size_t size) {
 | |
|             return lmem::AllocateFromExpHeap(g_fs_heap_handle, size);
 | |
|         }
 | |
| 
 | |
|         void DeallocateForFs(void *ptr, size_t size) {
 | |
|             AMS_UNUSED(size);
 | |
|             return lmem::FreeToExpHeap(g_fs_heap_handle, ptr);
 | |
|         }
 | |
| 
 | |
|         void HostConnectionObserver(bool is_connected) {
 | |
|             /* Update the host connection event. */
 | |
|             if (is_connected) {
 | |
|                 g_host_connection_event.Signal();
 | |
|             } else {
 | |
|                 g_host_connection_event.Clear();
 | |
| 
 | |
|                 /* Potentially cancel the log buffer push. */
 | |
|                 if (!g_sd_logging_event.TryWait()) {
 | |
|                     LogBuffer::GetDefaultInstance().CancelPush();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void SdLoggingObserver(bool is_available) {
 | |
|             /* Update the SD card logging event. */
 | |
|             if (is_available) {
 | |
|                 g_sd_logging_event.Signal();
 | |
|             } else {
 | |
|                 g_sd_logging_event.Clear();
 | |
| 
 | |
|                 /* Potentially cancel the log buffer push. */
 | |
|                 if (!g_host_connection_event.TryWait()) {
 | |
|                     LogBuffer::GetDefaultInstance().CancelPush();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         bool WaitForFlush() {
 | |
|             while (true) {
 | |
|                 /* Wait for something to be signaled. */
 | |
|                 os::WaitAny(g_stop_event.GetBase(), g_host_connection_event.GetBase(), g_sd_logging_event.GetBase(), g_sd_card_detection_event.GetBase());
 | |
| 
 | |
|                 /* If we're stopping, no flush. */
 | |
|                 if (g_stop_event.TryWait()) {
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 /* If host is connected/we're logging to sd, flush. */
 | |
|                 if (g_host_connection_event.TryWait() || g_sd_logging_event.TryWait()) {
 | |
|                     return true;
 | |
|                 }
 | |
| 
 | |
|                 /* If the sd card is newly inserted, flush. */
 | |
|                 if (g_sd_card_detection_event.TryWait()) {
 | |
|                     g_sd_card_detection_event.Clear();
 | |
| 
 | |
|                     if (fs::IsSdCardInserted()) {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void FlushThreadFunction(void *) {
 | |
|             /* Initialize fs. */
 | |
|             fs::InitializeWithMultiSessionForSystem();
 | |
|             fs::SetEnabledAutoAbort(false);
 | |
| 
 | |
|             /* Create fs heap. */
 | |
|             g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap, sizeof(g_fs_heap), lmem::CreateOption_None);
 | |
|             AMS_ABORT_UNLESS(g_fs_heap_handle != nullptr);
 | |
| 
 | |
|             /* Set fs allocator functions. */
 | |
|             fs::SetAllocator(AllocateForFs, DeallocateForFs);
 | |
| 
 | |
|             /* Create SD card detection event notifier. */
 | |
|             R_ABORT_UNLESS(fs::OpenSdCardDetectionEventNotifier(std::addressof(g_sd_card_detection_event_notifier)));
 | |
|             R_ABORT_UNLESS(g_sd_card_detection_event_notifier->BindEvent(g_sd_card_detection_event.GetBase(), os::EventClearMode_ManualClear));
 | |
| 
 | |
|             /* Set connection observers. */
 | |
|             SdCardLogger::GetInstance().SetLoggingObserver(SdLoggingObserver);
 | |
|             LogServerProxy::GetInstance().SetConnectionObserver(HostConnectionObserver);
 | |
| 
 | |
|             /* Do flush loop. */
 | |
|             do {
 | |
|                 if (LogBuffer::GetDefaultInstance().Flush()) {
 | |
|                     EventLogTransmitter::GetDefaultInstance().PushLogPacketDropCountIfExists();
 | |
|                 }
 | |
|             } while (WaitForFlush());
 | |
| 
 | |
|             /* Clear connection observer. */
 | |
|             LogServerProxy::GetInstance().SetConnectionObserver(nullptr);
 | |
| 
 | |
|             /* Finalize the SD card logger. */
 | |
|             SdCardLogger::GetInstance().Finalize();
 | |
|             SdCardLogger::GetInstance().SetLoggingObserver(nullptr);
 | |
| 
 | |
|             /* Destroy the fs heap. */
 | |
|             lmem::DestroyExpHeap(g_fs_heap_handle);
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     bool IsFlushAvailable() {
 | |
|         /* If we're sleeping, we can't flush. */
 | |
|         if (IsSleeping()) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /* Try to wait for an event. */
 | |
|         if (os::TryWaitAny(g_stop_event.GetBase(), g_host_connection_event.GetBase(), g_sd_logging_event.GetBase()) < 0) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /* Return whether we're not stopping. */
 | |
|         return !os::TryWaitEvent(g_stop_event.GetBase());
 | |
|     }
 | |
| 
 | |
|     void InitializeFlushThread() {
 | |
|         /* Create the flush thread. */
 | |
|         R_ABORT_UNLESS(os::CreateThread(std::addressof(g_flush_thread), FlushThreadFunction, nullptr, g_flush_thread_stack, sizeof(g_flush_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(lm, Flush)));
 | |
|         os::SetThreadNamePointer(std::addressof(g_flush_thread), AMS_GET_SYSTEM_THREAD_NAME(lm, Flush));
 | |
| 
 | |
|         /* Clear the stop event. */
 | |
|         g_stop_event.Clear();
 | |
| 
 | |
|         /* Start the flush thread. */
 | |
|         os::StartThread(std::addressof(g_flush_thread));
 | |
|     }
 | |
| 
 | |
|     void FinalizeFlushThread() {
 | |
|         /* Signal the flush thread to stop. */
 | |
|         g_stop_event.Signal();
 | |
| 
 | |
|         /* Wait for the flush thread to stop. */
 | |
|         os::WaitThread(std::addressof(g_flush_thread));
 | |
|         os::DestroyThread(std::addressof(g_flush_thread));
 | |
|     }
 | |
| 
 | |
| }
 |