diff --git a/CMakeLists.txt b/CMakeLists.txt index 8119c5b..a959d8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,8 @@ set(EHS_SOURCES src/database/DVar.cpp include/ehs/database/DVar.h src/system/CPU.cpp include/ehs/system/CPU.h - src/system/Thread.cpp include/ehs/system/Thread.h + include/ehs/system/BaseThread.h src/system/BaseThread.cpp + include/ehs/system/Thread.h src/system/BaseMutex.cpp include/ehs/system/BaseMutex.h src/system/BaseSemaphore.cpp include/ehs/system/BaseSemaphore.h src/system/BaseSystem.cpp include/ehs/system/BaseSystem.h @@ -107,7 +108,7 @@ set(EHS_SOURCES src/json/JsonVar.cpp include/ehs/json/JsonVar.h src/io/Resource.cpp include/ehs/io/Resource.h - src/io/Console.cpp include/ehs/io/Console.h + src/io/BaseConsole.cpp include/ehs/io/BaseConsole.h src/io/RIFF_Chunk.cpp include/ehs/io/RIFF_Chunk.h src/io/RIFF.cpp include/ehs/io/RIFF.h src/io/BaseWindow.cpp include/ehs/io/BaseWindow.h @@ -160,6 +161,8 @@ set(EHS_SOURCES src/io/hid/HID.cpp include/ehs/io/hid/HID.h src/io/hid/InputHandler.cpp include/ehs/io/hid/InputHandler.h src/io/hid/Input.cpp include/ehs/io/hid/Input.h + include/ehs/io/Console.h + include/ehs/system/Lock.h ) if (IS_OS_WINDOWS) @@ -168,9 +171,11 @@ if (IS_OS_WINDOWS) src/io/socket/TCP_W32.cpp include/ehs/io/socket/TCP_W32.h src/system/Semaphore_W32.cpp include/ehs/system/Semaphore_W32.h src/system/System_W32.cpp include/ehs/system/System_W32.h + src/system/Thread_W32.cpp include/ehs/system/Thread_W32.h src/system/Mutex_W32.cpp include/ehs/system/Mutex_W32.h src/system/Open_W32.cpp include/ehs/system/Open_W32.h src/io/audio/audioDevice_W32.cpp include/ehs/io/audio/audioDevice_W32.h + src/io/Console_W32.cpp include/ehs/io/Console_W32.h src/io/File_W32.cpp include/ehs/io/File_W32.h src/io/FileMonitor_W32.cpp include/ehs/io/FileMonitor_W32.h src/io/Window_W32.cpp include/ehs/io/Window_W32.h @@ -179,17 +184,21 @@ if (IS_OS_WINDOWS) ) elseif (IS_OS_LINUX) list(APPEND EHS_SOURCES + src/CRT_LNX.cpp src/io/socket/UDP_BSD.cpp include/ehs/io/socket/UDP_BSD.h src/io/socket/TCP_BSD.cpp include/ehs/io/socket/TCP_BSD.h src/system/Semaphore_P.cpp include/ehs/system/Semaphore_P.h src/system/System_LNX.cpp include/ehs/system/System_LNX.h src/system/Open_UNX.cpp include/ehs/system/Open_UNX.h + src/io/Console_LNX.cpp include/ehs/io/Console_LNX.h src/io/File_UNX.cpp include/ehs/io/File_UNX.h src/io/FileMonitor_UNX.cpp include/ehs/io/FileMonitor_UNX.h + src/system/Thread_LNX.cpp include/ehs/system/Thread_LNX.h src/system/Mutex_PT.cpp include/ehs/system/Mutex_PT.h src/io/audio/AudioDevice_ALSA.cpp include/ehs/io/audio/AudioDevice_ALSA.h src/system/FileSystem.cpp include/ehs/system/FileSystem.h src/system/User.cpp include/ehs/system/User.h + src/system/Lock_GCC_AMD64.asm ) set(LINUX_WINDOW_SYSTEM "Wayland" CACHE STRING "Linux Window System") @@ -221,6 +230,7 @@ add_executable(StrToHash src/StrToHash.cpp) target_include_directories(EHS PUBLIC ${PROJECT_SOURCE_DIR}/include) if (IS_OS_LINUX) + target_link_options(EHS PUBLIC -nostdlib -nostartfiles -e _start) set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/.local") elseif (IS_OS_WINDOWS) set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/EHS") diff --git a/include/ehs/GarbageCollector.h b/include/ehs/GarbageCollector.h index 0b97777..2100a8b 100644 --- a/include/ehs/GarbageCollector.h +++ b/include/ehs/GarbageCollector.h @@ -33,7 +33,7 @@ namespace ehs /// Sets the maximum amount of garbage to delete per poll. /// @param[in] newMax The new maximum. - static void SetMax(const UInt_64 newMax); + static void SetMax(UInt_64 newMax); /// Gets the maximum amount of garbage to delete per poll. /// @returns The maximum. @@ -41,7 +41,7 @@ namespace ehs /// Sets a new amount for memory pre-allocation to save on memory operations. /// @param[in] newStride The stride to pre-allocate. - static void SetStride(const UInt_64 newStride); + static void SetStride(UInt_64 newStride); /// The amount of data pre-allocated to save on memory operations. /// @returns The stride. diff --git a/include/ehs/Task.h b/include/ehs/Task.h index 47d5d03..c5d2b7a 100644 --- a/include/ehs/Task.h +++ b/include/ehs/Task.h @@ -2,6 +2,7 @@ #include "EHS.h" #include "BaseObj.h" +#include "ehs/Serializer.h" #include "ehs/system/Thread.h" #include "ehs/system/Semaphore.h" diff --git a/include/ehs/io/BaseConsole.h b/include/ehs/io/BaseConsole.h new file mode 100644 index 0000000..e8844e7 --- /dev/null +++ b/include/ehs/io/BaseConsole.h @@ -0,0 +1,91 @@ +#pragma once + +#include "ehs/Str.h" +#include "ehs/UTF.h" +#include "ehs/Array.h" + +namespace ehs +{ + class BaseConsole + { + public: + static void Attach(); + + /// Frees the current console being used. + static void Free(); + + /// Writes to console using UTF32. + /// @param [in] str The text to write to the console. + /// @param [in] newLine To make a new line after the given text. + /// @warning Has to convert from UTF32 to UTF16 for the Windows API. + static void Write_32(const Str_32& str, bool newLine = true); + + /// Writes to console using UTF16. + /// @param [in] str The text to write to the console. + /// @param [in] newLine To make a new line after the given text. + static void Write_16(const Str_16& str, bool newLine = true); + + /// Writes to console using UTF8. + /// @param [in] str The text to write to the console. + /// @param [in] newLine To make a new line after the given text. + /// @warning Has to convert from UTF8 to UTF16 for the Windows API. + static void Write_8(const Str_8& str, bool newLine = true); + + /// Reads from the console using UTF32. + /// @returns The text the user wrote to the console. + /// @warning Has to convert from UTF16 to UTF32 for the Windows API. + static Str_32 Read_32(UInt_64 bufferSize = 1024); + + /// Reads from the console using UTF16. + /// @returns The text the user wrote to the console. + static Str_16 Read_16(UInt_64 bufferSize = 1024); + + /// Reads from the console using UTF8. + /// @returns The text the user wrote to the console. + /// @warning Has to convert from UTF8 to UTF16 for the Windows API. + static Str_8 Read_8(UInt_64 bufferSize = 1024); + + /// Clears the console. + static void Clear(); + + /// Changes the console's title. + /// @param [in] title The text to change the title to. + /// @warning Has to convert from UTF32 to UTF16 for the Windows API. + static void SetTitle_32(const Str_32& title); + + /// Changes the console's title. + /// @param [in] title The text to change the title to. + static void SetTitle_16(const Str_16& title); + + /// Changes the console's title. + /// @param [in] title The text to change the title to. + /// @warning Has to convert from UTF8 to UTF16 for the Windows API. + static void SetTitle_8(const Str_8& title); + + /// Retrieves the console's title in UTF32. + /// @returns The console's title. + /// @warning Has to convert from UTF16 to UTF32 for the Windows API. + static Str_32 GetTitle_32(); + + /// Retrieves the console's title in UTF16. + /// @returns The console's title. + static Str_16 GetTitle_16(); + + /// Retrieves the console's title in UTF8. + /// @returns The console's title. + /// @warning Has to convert from UTF16 to UTF8 for the Windows API. + static Str_8 GetTitle_8(); + + /// Retrieves the string used when executing the end application through a command line interface in UTF32. + /// @returns The result. + static Vector GetArgs_32(UInt_64 bufferSize = 1024); + + /// Retrieves the string used when executing the end application through a command line interface in UTF16. + /// @returns The result. + static Vector GetArgs_16(UInt_64 bufferSize = 1024); + + /// Retrieves the string used when executing the end application through a command line interface in UTF8. + /// @returns The result. + static Vector GetArgs_8(UInt_64 bufferSize = 1024); + }; +} \ No newline at end of file diff --git a/include/ehs/io/Console.h b/include/ehs/io/Console.h index ff4a783..2ce5c0d 100644 --- a/include/ehs/io/Console.h +++ b/include/ehs/io/Console.h @@ -1,115 +1,9 @@ #pragma once -#include "ehs/Str.h" -#include "ehs/UTF.h" -#include "ehs/Array.h" +#include "ehs/system/OS.h" -namespace ehs -{ - #if defined(EHS_OS_WINDOWS) - typedef void* ConsoleHdl; - #elif defined(EHS_OS_LINUX) - typedef int ConsoleHdl; - #endif - - class Console - { - private: - static ConsoleHdl hdlOut; - static ConsoleHdl hdlIn; - - #if defined(EHS_OS_WINDOWS) - static bool isConsole; - #endif - - public: - static void Attach(); - - /// Creates a console using standard input and output. - /// @param [in] inputRequired Whether or not input is required from the console. - static bool Create(); - - /// Frees the current console being used. - static void Free(); - - static bool CanRead(); - - static bool CanWrite(); - - /// Writes to console using UTF32. - /// @param [in] str The text to write to the console. - /// @param [in] newLine To make a new line after the given text. - /// @warning Has to convert from UTF32 to UTF16 for the Windows API. - static void Write_32(const Str_32& str, const bool newLine = true); - - /// Writes to console using UTF16. - /// @param [in] str The text to write to the console. - /// @param [in] newLine To make a new line after the given text. - static void Write_16(const Str_16& str, const bool newLine = true); - - /// Writes to console using UTF8. - /// @param [in] str The text to write to the console. - /// @param [in] newLine To make a new line after the given text. - /// @warning Has to convert from UTF8 to UTF16 for the Windows API. - static void Write_8(const Str_8& str, const bool newLine = true); - - /// Reads from the console using UTF32. - /// @returns The text the user wrote to the console. - /// @warning Has to convert from UTF16 to UTF32 for the Windows API. - static Str_32 Read_32(const UInt_64 bufferSize = 1024); - - /// Reads from the console using UTF16. - /// @returns The text the user wrote to the console. - static Str_16 Read_16(const UInt_64 bufferSize = 1024); - - /// Reads from the console using UTF8. - /// @returns The text the user wrote to the console. - /// @warning Has to convert from UTF8 to UTF16 for the Windows API. - static Str_8 Read_8(const UInt_64 bufferSize = 1024); - - /// Clears the console. - static void Clear(); - - /// Changes the console's title. - /// @param [in] title The text to change the title to. - /// @warning Has to convert from UTF32 to UTF16 for the Windows API. - static void SetTitle_32(const Str_32& title); - - /// Changes the console's title. - /// @param [in] title The text to change the title to. - static void SetTitle_16(const Str_16& title); - - /// Changes the console's title. - /// @param [in] title The text to change the title to. - /// @warning Has to convert from UTF8 to UTF16 for the Windows API. - static void SetTitle_8(const Str_8& title); - - /// Retrieves the console's title in UTF32. - /// @returns The console's title. - /// @warning Has to convert from UTF16 to UTF32 for the Windows API. - static Str_32 GetTitle_32(); - - /// Retrieves the console's title in UTF16. - /// @returns The console's title. - static Str_16 GetTitle_16(); - - /// Retrieves the console's title in UTF8. - /// @returns The console's title. - /// @warning Has to convert from UTF16 to UTF8 for the Windows API. - static Str_8 GetTitle_8(); - - /// Retrieves the string used when executing the end application through a command line interface in UTF32. - /// @returns The result. - static Vector GetArgs_32(const UInt_64 bufferSize = 1024); - - /// Retrieves the string used when executing the end application through a command line interface in UTF16. - /// @returns The result. - static Vector GetArgs_16(const UInt_64 bufferSize = 1024); - - /// Retrieves the string used when executing the end application through a command line interface in UTF8. - /// @returns The result. - static Vector GetArgs_8(const UInt_64 bufferSize = 1024); - - //static void* GetHandle(); - }; -} \ No newline at end of file +#if defined(EHS_OS_WINDOWS) + #include "Console_W32.h" +#elif defined(EHS_OS_LINUX) + #include "Console_LNX.h" +#endif \ No newline at end of file diff --git a/include/ehs/io/Console_LNX.h b/include/ehs/io/Console_LNX.h new file mode 100644 index 0000000..dc00e5c --- /dev/null +++ b/include/ehs/io/Console_LNX.h @@ -0,0 +1,50 @@ +#pragma once + +#include "BaseConsole.h" + +namespace ehs +{ + class Console : public BaseConsole + { + private: + static int hdlOut; + static int hdlIn; + + public: + static void Attach(); + + static void Free(); + + static void Write_32(const Str_32& str, bool newLine = true); + + static void Write_16(const Str_16& str, bool newLine = true); + + static void Write_8(const Str_8& str, bool newLine = true); + + static Str_32 Read_32(UInt_64 bufferSize = 1024); + + static Str_16 Read_16(UInt_64 bufferSize = 1024); + + static Str_8 Read_8(UInt_64 bufferSize = 1024); + + static void Clear(); + + static void SetTitle_32(const Str_32& title); + + static void SetTitle_16(const Str_16& title); + + static void SetTitle_8(const Str_8& title); + + static Str_32 GetTitle_32(); + + static Str_16 GetTitle_16(); + + static Str_8 GetTitle_8(); + + static Vector GetArgs_32(UInt_64 bufferSize = 1024); + + static Vector GetArgs_16(UInt_64 bufferSize = 1024); + + static Vector GetArgs_8(UInt_64 bufferSize = 1024); + }; +} \ No newline at end of file diff --git a/include/ehs/io/Console_W32.h b/include/ehs/io/Console_W32.h new file mode 100644 index 0000000..303f4df --- /dev/null +++ b/include/ehs/io/Console_W32.h @@ -0,0 +1,51 @@ +#pragma once + +#include "BaseConsole.h" + +namespace ehs +{ + class Console : public BaseConsole + { + private: + static void* hdlOut; + static void* hdlIn; + static bool isConsole; + + public: + static void Attach(); + + static void Free(); + + static void Write_32(const Str_32& str, bool newLine = true); + + static void Write_16(const Str_16& str, bool newLine = true); + + static void Write_8(const Str_8& str, bool newLine = true); + + static Str_32 Read_32(UInt_64 bufferSize = 1024); + + static Str_16 Read_16(UInt_64 bufferSize = 1024); + + static Str_8 Read_8(UInt_64 bufferSize = 1024); + + static void Clear(); + + static void SetTitle_32(const Str_32& title); + + static void SetTitle_16(const Str_16& title); + + static void SetTitle_8(const Str_8& title); + + static Str_32 GetTitle_32(); + + static Str_16 GetTitle_16(); + + static Str_8 GetTitle_8(); + + static Vector GetArgs_32(UInt_64 bufferSize = 1024); + + static Vector GetArgs_16(UInt_64 bufferSize = 1024); + + static Vector GetArgs_8(UInt_64 bufferSize = 1024); + }; +} \ No newline at end of file diff --git a/include/ehs/system/BaseThread.h b/include/ehs/system/BaseThread.h new file mode 100644 index 0000000..3f6d1fb --- /dev/null +++ b/include/ehs/system/BaseThread.h @@ -0,0 +1,51 @@ +#pragma once + +#include "ehs/Types.h" + +namespace ehs +{ + class BaseThread + { + private: + UInt_64 stackSize; + + protected: + UInt_32 id; + + public: + BaseThread(); + + BaseThread(UInt_64 stackSize); + + BaseThread(BaseThread&& thread) noexcept; + + BaseThread(const BaseThread& thread); + + BaseThread& operator=(BaseThread&& thread) noexcept; + + BaseThread& operator=(const BaseThread& thread); + + virtual void Detach(); + + virtual void Join() = 0; + + UInt_64 GetStackSize() const; + + UInt_32 GetId() const; + + static UInt_32 GetCurrentId(); + + virtual bool IsValid() const; + + /// A software implementation for sleeping the calling thread. + /// @param [in] seconds The amount in seconds to sleep for. + /// @returns The amount in seconds that the sleep exceeded for. + /// @note A more precise sleep method but more taxing on the CPU. + static float SoftSleep(float seconds); + + /// A hardware implementation for sleeping the calling thread. + /// @param [in] milliseconds The amount in milliseconds to sleep for. + /// @note A less precise sleep method but less taxing on the CPU. + static void HardSleep(UInt_32 milliseconds); + }; +} \ No newline at end of file diff --git a/include/ehs/system/Lock.h b/include/ehs/system/Lock.h new file mode 100644 index 0000000..c90d155 --- /dev/null +++ b/include/ehs/system/Lock.h @@ -0,0 +1,58 @@ +#pragma once + +#include "ehs/Types.h" + +namespace ehs +{ + class Lock + { + /// Does an atomic lock add operation. + /// @param [in] a The address of the value to add to. + /// @param [in] b The value to add from. + static void Add(UInt_64* a, UInt_64 b); + + /// Does an atomic lock subtract operation. + /// @param [in] a The address of the value to subtract to. + /// @param [in] b The value to subtract from. + static void Sub(UInt_64* a, UInt_64 b); + + /// Does an atomic lock compare exchange operation. + /// @param [in/out] a The address of the value to compare with the value of b. + /// @param [in/out] b The address of the value to compare with the value of a. + /// @param [in] setter The address of the value to set the value of b to when a and b are equal. + /// @returns True if equal. + /// @note If a and b are not equal the value at the address of a will be set to the value at the address of b. + static bool CmpXchg(UInt_64* a, UInt_64* b, UInt_64 setter); + + /// Does an atomic lock and operation. + /// @param [in] a The address of the first value to compare. + /// @param [in] b The second value to compare. + static void And(UInt_64* a, UInt_64 b); + + /// Does an atomic lock or operation. + /// @param [in] a The address of the first value to compare. + /// @param [in] b The second value to compare. + static void Or(UInt_64* a, UInt_64 b); + + /// Does an atomic lock xor operation. + /// @param [in] a The address of the first value to compare. + /// @param [in] b The second value to compare. + static void XOr(UInt_64* a, UInt_64 b); + + /// Does an atomic lock increase operation. + /// @param [in] a The address of the value to increase. + static void Inc(UInt_64* a); + + /// Does an atomic lock decrease operation. + /// @param [in] a The address of the value to decrease. + static void Dec(UInt_64* a); + + /// Does an atomic lock not operation. + /// @param [in] a The address of the value to not. + static void Not(UInt_64* a); + + /// Does an atomic lock negate operation. + /// @param [in] a The address of the value to negate. + static void Neg(UInt_64* a); + }; +} \ No newline at end of file diff --git a/include/ehs/system/Mutex_PT.h b/include/ehs/system/Mutex_PT.h index 422b2aa..224f2f5 100644 --- a/include/ehs/system/Mutex_PT.h +++ b/include/ehs/system/Mutex_PT.h @@ -10,7 +10,7 @@ namespace ehs class Mutex : public BaseMutex { private: - pthread_mutex_t hdl; + volatile UInt_64 state; public: ~Mutex() override; diff --git a/include/ehs/system/Thread.h b/include/ehs/system/Thread.h index e73a4b7..8352e54 100644 --- a/include/ehs/system/Thread.h +++ b/include/ehs/system/Thread.h @@ -1,148 +1,9 @@ #pragma once -#include "ehs/EHS.h" -#include "ehs/Serializer.h" -#include "ehs/Array.h" -#include "ehs/Log.h" -#include "ehs/Str.h" +#include "ehs/system/OS.h" -#ifdef EHS_OS_WINDOWS - #include -#endif - -namespace ehs -{ - #if defined(EHS_OS_WINDOWS) - #define EHS_INVALID_THREAD nullptr - typedef void* THandle; - #elif defined(EHS_OS_LINUX) - #define EHS_INVALID_THREAD 0 - typedef UInt_64 THandle; - #endif - - class Thread - { - private: - static UInt_32 mainId; - - #ifdef EHS_OS_WINDOWS - static Handle mainTaskHdl; - static UInt_32 mainTaskIndex; - #endif - - UInt_64 stackSize; - THandle hdl; - UInt_32 id; - - #ifdef EHS_OS_WINDOWS - Handle taskHdl; - UInt_32 taskIndex; - #endif - - public: - /// Frees any native handles. - ~Thread(); - - /// Default members initialization. - Thread(const UInt_64 stackSize = 0); - - /// Copies some members from the given thread object. - /// @param [in] thread The thread object to copy from. - Thread(const Thread& thread); - - /// Copies some members from the given thread object. - /// @param [in] thread The thread object to copy from. - /// @returns The thread that has been assigned to. - Thread& operator=(const Thread& thread); - - /// Creates a thread handle and starts it with the given method. - /// @param cb The function to run on the thread. - /// @param args Raw data to send over to the thread. - void Start(UInt_32 (*cb)(void*), void* args); - - /// Blocks the calling thread until the referenced thread is finished. - /// @param timeout The time to wait for before moving on. - /// @note Pass "EHS_INFINITE" to wait until the thread is finished. - bool Join(const unsigned int timeout = EHS_INFINITE); - - /// Detaches the referenced thread, removing ownership. - void Detach(); - - /// Retrieves the given stack size available to the referenced thread. - /// @returns The stack size. - UInt_64 GetStackSize() const; - - /// Retrieves the native thread handle. - /// @returns The native handle. - THandle GetHandle() const; - - /// Retrieves the thread's id. - /// @returns The id. - UInt_32 GetId() const; - - /// Checks whether or not the calling thread is the referenced thread. - /// @returns The result. - bool IsCurrent() const; - - bool IsValid() const; - - #ifdef EHS_OS_WINDOWS - /// Adjusts the thread's performance based on the type of task provided, that's going to be executed. - /// @param[in] task A task name from the provided list in the registry. - /// @note A list of tasks are in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. - void SetTaskType_32(const Str_32& task); - - /// Adjusts the thread's performance based on the type of task provided, that's going to be executed. - /// @param[in] task A task name from the provided list in the registry. - /// @note A list of tasks are in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. - void SetTaskType_16(const Str_16& task); - - /// Adjusts the thread's performance based on the type of task provided, that's going to be executed. - /// @param[in] task A task name from the provided list in the registry. - /// @note A list of tasks are in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. - void SetTaskType_8(const Str_8& task); - - void RevertTaskType(); - #endif - - /// Gets the main thread id. - static UInt_32 GetMainId(); - - /// Retrieves the calling thread's id. - /// @returns The id. - static UInt_64 GetCurrentId(); - - #ifdef EHS_OS_WINDOWS - /// Adjusts the main thread's performance based on the type of task provided, that's going to be executed. - /// @param[in] task A task name from the provided list in the registry. - /// @note A list of tasks are in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. - static void SetMainTaskType_32(const Str_32& task); - - /// Adjusts the main thread's performance based on the type of task provided, that's going to be executed. - /// @param[in] task A task name from the provided list in the registry. - /// @note A list of tasks are in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. - static void SetMainTaskType_16(const Str_16& task); - - /// Adjusts the main thread's performance based on the type of task provided, that's going to be executed. - /// @param[in] task A task name from the provided list in the registry. - /// @note A list of tasks are in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. - static void SetMainTaskType_8(const Str_8& task); - - static void RevertMainTaskType(); - #endif - - /// Causes the calling thread to wait until the given time using a while loop and the CPU clock. - /// @param seconds The time in seconds to wait for. - /// @returns The total elapsed time slept for due to this not being a 100% accurate. - /// @warning Use "SleepFor" instead unless accuracy is required because this does not do other tasks while sleeping. - static float HardSleepFor(const float seconds); - - /// Causes the calling thread to wait until the given time using native sleep calls. - /// @param miliseconds The time in miliseconds to wait for. - /// @warning This is not at all accurate. - static void SleepFor(const UInt_32 miliseconds); - - private: - static void* Redirect(void* args); - }; -} \ No newline at end of file +#if defined(EHS_OS_WINDOWS) + #include "Thread_W32.h" +#elif defined(EHS_OS_LINUX) + #include "Thread_LNX.h" +#endif \ No newline at end of file diff --git a/include/ehs/system/Thread_LNX.h b/include/ehs/system/Thread_LNX.h new file mode 100644 index 0000000..3b854f4 --- /dev/null +++ b/include/ehs/system/Thread_LNX.h @@ -0,0 +1,42 @@ +#pragma once + +#include "BaseThread.h" + +#include + +namespace ehs +{ + class Thread : public BaseThread + { + private: + void* stack; + pid_t hdl; + volatile bool* detached; + + public: + ~Thread(); + + Thread(); + + Thread(UInt_64 stackSize, void* args, UInt_32 (*func)(void*)); + + Thread(Thread&& thread) noexcept; + + Thread(const Thread& thread); + + Thread& operator=(Thread&& thread) noexcept; + + Thread& operator=(const Thread& thread); + + void Detach() override; + + void Join() override; + + static UInt_32 GetCurrentId(); + + static void HardSleep(UInt_32 milliseconds); + + private: + static UInt_32 Redirect(void* args); + }; +} \ No newline at end of file diff --git a/include/ehs/system/Thread_W32.h b/include/ehs/system/Thread_W32.h new file mode 100644 index 0000000..cd65e9b --- /dev/null +++ b/include/ehs/system/Thread_W32.h @@ -0,0 +1,37 @@ +#pragma once + +#include "BaseThread.h" + +namespace ehs +{ + class Thread : public BaseThread + { + private: + void* hdl; + + public: + ~Thread(); + + Thread(); + + Thread(UInt_64 stackSize, void* args, UInt_32 (*func)(void*)); + + Thread(Thread&& thread) noexcept; + + Thread(const Thread& thread); + + Thread& operator=(Thread&& thread) noexcept; + + Thread& operator=(const Thread& thread); + + void Detach() override; + + void Join() override; + + static UInt_32 GetCurrentId(); + + bool IsValid() const override; + + static void HardSleep(UInt_32 milliseconds); + }; +} \ No newline at end of file diff --git a/src/CRT_LNX.cpp b/src/CRT_LNX.cpp new file mode 100644 index 0000000..85c18a5 --- /dev/null +++ b/src/CRT_LNX.cpp @@ -0,0 +1,96 @@ +#include "ehs/Log.h" +#include "ehs/HRNG.h" + +#include +#include +#include +#include + +extern "C" +{ + long syscall(long number, ...) { + va_list args; + va_start(args, number); + + // Retrieve the system call arguments. + unsigned long arg1 = va_arg(args, unsigned long); + unsigned long arg2 = va_arg(args, unsigned long); + unsigned long arg3 = va_arg(args, unsigned long); + unsigned long arg4 = va_arg(args, unsigned long); + unsigned long arg5 = va_arg(args, unsigned long); + unsigned long arg6 = va_arg(args, unsigned long); + va_end(args); + + // Variable to store the system call return value + long ret; + + // Inline assembly to perform the system call + __asm__ volatile ( + "mov %1, %%rax\n\t" // System call number -> RAX + "mov %2, %%rdi\n\t" // First argument -> RDI + "mov %3, %%rsi\n\t" // Second argument -> RSI + "mov %4, %%rdx\n\t" // Third argument -> RDX + "mov %5, %%r10\n\t" // Fourth argument -> R10 + "mov %6, %%r8\n\t" // Fifth argument -> R8 + "mov %7, %%r9\n\t" // Sixth argument -> R9 + "syscall\n\t" // Invoke system call + "mov %%rax, %0\n\t" // Store return value + : "=r"(ret) // output + : "r"(number), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6) // inputs + : "%rax", "%rdi", "%rsi", "%rdx", "%r10", "%r8", "%r9", "memory", "cc" // clobbers + ); + + return ret; + } + + int* __errno_location() + { + static __thread int tls_errno = 0; // __thread or thread_local (C++11 and later) + return &tls_errno; + } + + #ifdef EHS_DEBUG + unsigned long __stack_chk_guard = 0x0000DEAD; + #else + unsigned long __stack_chk_guard = ehs::HRNG::GenerateSeed_u64(); + #endif + + void __stack_chk_fail(void) + { + EHS_LOG("Error", 0, "Found corrupted stack."); + + syscall(SYS_exit, 1); + } + + int __cxa_atexit(void (*func)(void *), void *arg, void * /*dso_handle*/) + { + return 0; + } + + size_t strlen(const char *s) + { + size_t count = 0; + while (s[count]) + count++; + + return count; + } +} + +void* operator new[](unsigned long size) noexcept(false) +{ + syscall(SYS_brk,) + void* ptr = (void*)syscall(SYS_mmap, nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) + { + EHS_LOG("Error", 0, "Failed to allocate memory on the heap."); + return nullptr; + } + + return ptr; +} + +void operator delete[](void* ptr) noexcept +{ + syscall(SYS_munmap, ptr, GetStackSize()) +} \ No newline at end of file diff --git a/src/EHS.cpp b/src/EHS.cpp index a12d78b..449578a 100644 --- a/src/EHS.cpp +++ b/src/EHS.cpp @@ -10,10 +10,6 @@ #include -#if defined(EHS_OS_LINUX) - #include -#endif - namespace ehs { constexpr Char_32 name_32[] = U"Event Horizon Suite"; @@ -636,7 +632,7 @@ void LogRaised(const ehs::Log& log) result += "} (" + ehs::Str_8::FromNum(log.GetCode()) + "): " + log.GetMsg(); - ehs::Console::Write_8(result); + ehs::BaseConsole::Write_8(result); } int main() @@ -685,5 +681,7 @@ int main() ehs::GarbageCollector::Stop(); + ehs::Console::Free(); + return code; } \ No newline at end of file diff --git a/src/GarbageCollector.cpp b/src/GarbageCollector.cpp index 67be746..1827945 100644 --- a/src/GarbageCollector.cpp +++ b/src/GarbageCollector.cpp @@ -7,7 +7,7 @@ namespace ehs while (GarbageCollector::IsRunning()) { GarbageCollector::Poll(); - Thread::SleepFor(50); + Thread::HardSleep(50); } GarbageCollector::Dump(); @@ -37,7 +37,7 @@ namespace ehs mutex.Initialize(); - thread.Start(GarbageCollectionThread, nullptr); + thread = Thread(1, nullptr, GarbageCollectionThread); running = true; } diff --git a/src/StrToHash.cpp b/src/StrToHash.cpp index adc9fee..3c7c6a8 100644 --- a/src/StrToHash.cpp +++ b/src/StrToHash.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include ehs::Int_32 Main(ehs::Str_8* appName, ehs::Str_8* appVerId, ehs::Version* appVer) { @@ -8,23 +8,23 @@ ehs::Int_32 Main(ehs::Str_8* appName, ehs::Str_8* appVerId, ehs::Version* appVer *appVerId = "Release"; *appVer = {1, 0, 0}; - ehs::Vector args = ehs::Console::GetArgs_8(); + ehs::Vector args = ehs::BaseConsole::GetArgs_8(); if (args.Size() > 1) { for (ehs::UInt_64 i = 1; i < args.Size(); ++i) - ehs::Console::Write_8("Result " + ehs::Str_8::FromNum(i) + ": " + ehs::Str_8::FromNum(args[i].Hash_64())); + ehs::BaseConsole::Write_8("Result " + ehs::Str_8::FromNum(i) + ": " + ehs::Str_8::FromNum(args[i].Hash_64())); } else { - ehs::Console::Write_8("String: ", false); - ehs::Str_8 in = ehs::Console::Read_8(); - ehs::Console::Write_8("Result: " + ehs::Str_8::FromNum(in.Hash_64())); + ehs::BaseConsole::Write_8("String: ", false); + ehs::Str_8 in = ehs::BaseConsole::Read_8(); + ehs::BaseConsole::Write_8("Result: " + ehs::Str_8::FromNum(in.Hash_64())); - ehs::Console::Read_8(); + ehs::BaseConsole::Read_8(); } - ehs::Console::Free(); + ehs::BaseConsole::Free(); return 0; } diff --git a/src/Task.cpp b/src/Task.cpp index e7d960d..ceacb3f 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -147,7 +147,7 @@ namespace ehs threadArgs->Write(callback); threadArgs->SetOffset(0); - thread.Start(TaskThread, threadArgs); + thread = Thread(1024, threadArgs, TaskThread); } void Task::Release() diff --git a/src/io/BaseConsole.cpp b/src/io/BaseConsole.cpp new file mode 100644 index 0000000..a8d4eea --- /dev/null +++ b/src/io/BaseConsole.cpp @@ -0,0 +1,85 @@ +#include "ehs/io/BaseConsole.h" + +namespace ehs +{ + void BaseConsole::Attach() + { + } + + void BaseConsole::Free() + { + } + + void BaseConsole::Write_32(const Str_32& str, const bool newLine) + { + } + + void BaseConsole::Write_16(const Str_16& str, const bool newLine) + { + } + + void BaseConsole::Write_8(const Str_8& str, const bool newLine) + { + } + + Str_32 BaseConsole::Read_32(const UInt_64 bufferSize) + { + return {}; + } + + Str_16 BaseConsole::Read_16(const UInt_64 bufferSize) + { + return {}; + } + + Str_8 BaseConsole::Read_8(const UInt_64 bufferSize) + { + return {}; + } + + void BaseConsole::Clear() + { + } + + void BaseConsole::SetTitle_32(const Str_32& title) + { + } + + void BaseConsole::SetTitle_16(const Str_16& title) + { + } + + void BaseConsole::SetTitle_8(const Str_8& title) + { + } + + Str_32 BaseConsole::GetTitle_32() + { + return {}; + } + + Str_16 BaseConsole::GetTitle_16() + { + return {}; + } + + Str_8 BaseConsole::GetTitle_8() + { + return {}; + } + + Vector BaseConsole::GetArgs_32(const UInt_64 bufferSize) + { + return {}; + } + + Vector BaseConsole::GetArgs_16(const UInt_64 bufferSize) + { + return {}; + } + + Vector BaseConsole::GetArgs_8(const UInt_64 bufferSize) + { + return {}; + } +} \ No newline at end of file diff --git a/src/io/Console.cpp b/src/io/Console.cpp deleted file mode 100644 index f980b91..0000000 --- a/src/io/Console.cpp +++ /dev/null @@ -1,799 +0,0 @@ -#include "ehs/io/Console.h" -#include "ehs/Log.h" -#include "ehs/io/File.h" - -#if defined(EHS_OS_LINUX) - #include - #include - #include -#endif - -namespace ehs -{ - ConsoleHdl Console::hdlOut = 0; - ConsoleHdl Console::hdlIn = 0; - - #if defined(EHS_OS_WINDOWS) - bool Console::isConsole = true; - #endif - - void Console::Attach() - { - #if defined(EHS_OS_WINDOWS) - if (!AttachConsole(ATTACH_PARENT_PROCESS)) - { - DWORD code = GetLastError(); - if (code == ERROR_INVALID_HANDLE) - return; - } - - hdlIn = GetStdHandle(STD_INPUT_HANDLE); - hdlOut = GetStdHandle(STD_OUTPUT_HANDLE); - - DWORD mode = 0; - - if (!GetConsoleMode(hdlOut, &mode)) - { - if (GetLastError() == ERROR_INVALID_HANDLE) - isConsole = false; - } - else - { - //DWORD code = WaitForSingleObject(hdlIn, 15000); - //if (code == WAIT_FAILED || code == WAIT_TIMEOUT || code == WAIT_ABANDONED) - // EHS_LOG_INT("Error", 0, "Failed to wait for console input."); - - isConsole = true; - } - #elif defined(EHS_OS_LINUX) - hdlOut = open("/dev/stdout", O_WRONLY | O_SYNC); - hdlIn = open("/dev/stdin", O_RDONLY); - #else - return; - #endif - } - - bool Console::Create() - { - #if defined(EHS_OS_WINDOWS) - if (!AllocConsole()) - return false; - - hdlIn = GetStdHandle(STD_INPUT_HANDLE); - hdlOut = GetStdHandle(STD_OUTPUT_HANDLE); - - if (WaitForSingleObject(hdlIn, EHS_INFINITE) == WAIT_FAILED) - EHS_LOG_INT("Error", 2, "Failed to wait for console input."); - - //if (!SetConsoleActiveScreenBuffer(hdlOut)) - // EHS_LOG_INT("Error", 3, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - isConsole = true; - #endif - - return true; - } - - void Console::Free() - { - #if defined(EHS_OS_WINDOWS) - if (!FreeConsole()) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - #elif defined(EHS_OS_LINUX) - int code = close(hdlOut); - if (code == -1) - EHS_LOG_INT("Error", 0, "Failed to free the console output with error #" + Str_8::FromNum(errno) + "."); - - code = close(hdlIn); - if (code == -1) - EHS_LOG_INT("Error", 0, "Failed to free the console input with error #" + Str_8::FromNum(errno) + "."); - #endif - - hdlOut = 0; - hdlIn = 0; - } - - bool Console::CanRead() - { - return hdlIn; - } - - bool Console::CanWrite() - { - return hdlOut; - } - - void Console::Write_32(const Str_32& str, const bool newLine) - { - #if defined(EHS_OS_WINDOWS) - if (isConsole) - { - Str_16 r = UTF::To_16(str); - if (newLine) - r += L"\r\n"; - - DWORD offset = 0; - - do - { - DWORD written = 0; - if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - offset += written; - } - while (offset < r.Size()); - } - else - { - Str_8 r = UTF::To_8(str); - if (newLine) - r += "\r\n"; - - DWORD offset = 0; - - do - { - DWORD written = 0; - if (!WriteFile(hdlOut, &((Char_8*)r)[offset], (DWORD)r.Size(true) - offset, &written, nullptr)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - offset += written; - } - while (offset < r.Size(true)); - } - #elif defined(EHS_OS_LINUX) - Str_32 result = str; - if (newLine) - result += U"\n"; - - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, result, result.Size(true)); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < result.Size(true)); - #else - return; - #endif - } - - void Console::Write_16(const Str_16& str, const bool newLine) - { - #if defined(EHS_OS_WINDOWS) - if (isConsole) - { - Str_16 r = str; - if (newLine) - r += L"\r\n"; - - DWORD offset = 0; - - do - { - DWORD written = 0; - if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - offset += written; - } - while (offset < r.Size()); - } - else - { - Str_8 r = UTF::To_8(str); - if (newLine) - r += "\r\n"; - - DWORD offset = 0; - - do - { - DWORD written = 0; - if (!WriteFile(hdlOut, &((Char_8*)r)[offset], (DWORD)r.Size(true) - offset, &written, nullptr)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - offset += written; - } - while (offset < r.Size(true)); - } - #elif defined(EHS_OS_LINUX) - Str_16 result = str; - if (newLine) - result += L"\n"; - - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, result, result.Size(true)); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < result.Size(true)); - #endif - } - - void Console::Write_8(const Str_8& str, const bool newLine) - { - #if defined(EHS_OS_WINDOWS) - if (isConsole) - { - Str_16 r = UTF::To_16(str); - if (newLine) - r += L"\r\n"; - - DWORD offset = 0; - - do - { - DWORD written = 0; - if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - offset += written; - } - while (offset < r.Size()); - } - else - { - Str_8 r = str; - if (newLine) - r += "\r\n"; - - DWORD offset = 0; - - do - { - DWORD written = 0; - if (!WriteFile(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - offset += written; - } - while (offset < r.Size()); - } - #elif defined(EHS_OS_LINUX) - Str_8 result = str; - if (newLine) - result += "\n"; - - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, result, result.Size()); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < result.Size()); - #endif - } - - Str_32 Console::Read_32(const UInt_64 bufferSize) - { - if (!hdlIn) - return U""; - - #if defined(EHS_OS_WINDOWS) - if (isConsole) - { - Str_16 result; - - DWORD offset = 0; - - do - { - result.Resize(result.Size() + bufferSize); - - DWORD read = 0; - - if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) - { - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - return U""; - } - - offset += read; - } - while (result[offset - 1] != L'\n'); - - if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n') - result.Resize(offset - 2); - else - result.Resize(offset - 1); - - return UTF::To_32(result); - } - else - { - Str_8 result; - - DWORD offset = 0; - - do - { - result.Resize(result.Size() + bufferSize); - - DWORD read = 0; - - if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) - { - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - return U""; - } - - offset += read; - } - while (result[offset - 1] != '\n'); - - if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n') - result.Resize(offset - 2); - else - result.Resize(offset - 1); - - return UTF::To_32(result); - } - #elif defined(EHS_OS_LINUX) - Str_32 result; - Str_32 input(bufferSize); - ssize_t read = 0; - - do - { - read = ::read(hdlIn, input, bufferSize); - if (read == -1) - { - EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + "."); - return result; - } - result.Push(input, read); - } - while (input[read - 1] != U'\n'); - - return result; - #else - return {}; - #endif - } - - Str_16 Console::Read_16(const UInt_64 bufferSize) - { - if (!hdlIn) - return L""; - - #if defined(EHS_OS_WINDOWS) - if (isConsole) - { - Str_16 result; - - DWORD offset = 0; - - do - { - result.Resize(result.Size() + bufferSize); - - DWORD read = 0; - - if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) - { - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - return L""; - } - - offset += read; - } - while (result[offset - 1] != L'\n'); - - if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n') - result.Resize(offset - 2); - else - result.Resize(offset - 1); - - return result; - } - else - { - Str_8 result; - - DWORD offset = 0; - - do - { - result.Resize(result.Size() + bufferSize); - - DWORD read = 0; - - if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) - { - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - return L""; - } - - offset += read; - } - while (result[offset - 1] != '\n'); - - if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n') - result.Resize(offset - 2); - else - result.Resize(offset - 1); - - return UTF::To_16(result); - } - #elif defined(EHS_OS_LINUX) - Str_16 result; - Str_16 input(bufferSize); - ssize_t read = 0; - - do - { - read = ::read(hdlIn, input, bufferSize); - if (read == -1) - { - EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + "."); - return result; - } - result.Push(input, read); - } - while (input[read - 1] != L'\n'); - - return result; - #else - return {}; - #endif - } - - Str_8 Console::Read_8(const UInt_64 bufferSize) - { - if (!hdlIn) - return ""; - - #if defined(EHS_OS_WINDOWS) - if (isConsole) - { - Str_16 result; - - DWORD offset = 0; - - do - { - result.Resize(result.Size() + bufferSize); - - DWORD read = 0; - - if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) - { - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - return ""; - } - - offset += read; - } - while (result[offset - 1] != L'\n'); - - if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n') - result.Resize(offset - 2); - else - result.Resize(offset - 1); - - return UTF::To_8(result); - } - else - { - Str_8 result; - - DWORD offset = 0; - - do - { - result.Resize(result.Size() + bufferSize); - - DWORD read = 0; - - if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) - { - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - - return ""; - } - - offset += read; - } - while (result[offset - 1] != '\n'); - - if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n') - result.Resize(offset - 2); - else - result.Resize(offset - 1); - - return result; - } - #elif defined(EHS_OS_LINUX) - Str_8 result; - Str_8 input(bufferSize); - ssize_t read = 0; - - do - { - read = ::read(hdlIn, input, bufferSize); - if (read == -1) - { - EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + "."); - return result; - } - result.Push(input, read); - } - while (input[read - 1] != '\n'); - - return result.Sub(0, result.Size() - 1); - #else - return {}; - #endif - } - - void Console::Clear() - { - #if defined(EHS_OS_WINDOWS) - CONSOLE_SCREEN_BUFFER_INFO info = {}; - if (!GetConsoleScreenBufferInfo(hdlOut, &info)) - return; - - DWORD size = info.dwSize.X * info.dwSize.Y; - - DWORD written = 0; - if (!FillConsoleOutputCharacterW(hdlOut, L' ', size, {0, 0}, &written)) - return; - - if (!GetConsoleScreenBufferInfo(hdlOut, &info)) - return; - - if (!FillConsoleOutputAttribute(hdlOut, info.wAttributes, size, {0, 0}, &written)) - return; - - SetConsoleCursorPosition(hdlOut, {0, 0}); - #elif defined(EHS_OS_LINUX) - const Char_8 code[] = "\033[2J\033[1;1H"; - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, code, sizeof(code)); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to clear console with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < sizeof(code)); - #endif - } - - void Console::SetTitle_32(const Str_32& title) - { - #if defined(EHS_OS_WINDOWS) - if (!SetConsoleTitleW(UTF::To_16(title))) - EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(GetLastError()) + "."); - #elif defined(EHS_OS_LINUX) - Str_32 code = U"\033]0;" + title + U"\007"; - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, code, code.Size(true)); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < code.Size(true)); - #endif - } - - void Console::SetTitle_16(const Str_16& title) - { - #if defined(EHS_OS_WINDOWS) - if (!SetConsoleTitleW(title)) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - #elif defined(EHS_OS_LINUX) - Str_16 code = L"\033]0;" + title + L"\007"; - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, code, code.Size(true)); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < code.Size(true)); - #endif - } - - void Console::SetTitle_8(const Str_8& title) - { - #if defined(EHS_OS_WINDOWS) - if (!SetConsoleTitleW(UTF::To_16(title))) - EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); - #elif defined(EHS_OS_LINUX) - Str_8 code = "\033]0;" + title + "\007"; - UInt_64 offset = 0; - do { - ssize_t written = write(hdlOut, code, code.Size()); - if (written == -1) - { - EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + "."); - return; - } - offset += written; - } - while (offset < code.Size()); - #endif - } - - Str_32 Console::GetTitle_32() - { - #if defined(EHS_OS_WINDOWS) - Str_16 title(EHS_MAX_PATH); - - DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH); - - title.Resize(size); - - return UTF::To_32(title); - #else - return {}; - #endif - } - - Str_16 Console::GetTitle_16() - { - #if defined(EHS_OS_WINDOWS) - Str_16 title(EHS_MAX_PATH); - - DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH); - - title.Resize(size); - - return title; - #else - return {}; - #endif - } - - Str_8 Console::GetTitle_8() - { - #if defined(EHS_OS_WINDOWS) - Str_16 title(EHS_MAX_PATH); - - DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH); - - title.Resize(size); - - return UTF::To_8(title); - #else - return {}; - #endif - } - - Vector Console::GetArgs_32(const UInt_64 bufferSize) - { - #if defined(EHS_OS_WINDOWS) - return UTF::To_32(GetCommandLineW()).Split(U" "); - #elif defined(EHS_OS_LINUX) - File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN); - Array data = cmdFile.ReadArray(bufferSize); - cmdFile.Release(); - - Vector args; - - UInt_64 o = 0; - for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8)) - { - if (data[i] != '\0') - continue; - - - - args.Push(UTF::To_32((Char_8*)&data[o], i - o)); - o = i + sizeof(Char_8); - } - - if (o < data.Size()) - args.Push(UTF::To_32((Char_8*)&data[o], data.Size() - o - 1)); - - return args; - #else - return {}; - #endif - } - - Vector Console::GetArgs_16(const UInt_64 bufferSize) - { - #if defined(EHS_OS_WINDOWS) - return Str_16(GetCommandLineW()).Split(L" "); - #elif defined(EHS_OS_LINUX) - File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN); - Array data = cmdFile.ReadArray(bufferSize); - cmdFile.Release(); - - Vector args; - - UInt_64 o = 0; - for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8)) - { - if (data[i] != '\0') - continue; - - args.Push(UTF::To_16((Char_8*)&data[o], i - o)); - o = i + sizeof(Char_8); - } - - if (o < data.Size()) - args.Push(UTF::To_16((Char_8*)&data[o], data.Size() - o - 1)); - - return args; - #else - return {}; - #endif - } - - Vector Console::GetArgs_8(const UInt_64 bufferSize) - { - #if defined(EHS_OS_WINDOWS) - return UTF::To_8(GetCommandLineW()).Split(" "); - #elif defined(EHS_OS_LINUX) - File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN); - Array data = cmdFile.ReadArray(bufferSize); - cmdFile.Release(); - - Vector args; - - UInt_64 o = 0; - for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8)) - { - if (data[i] != '\0') - continue; - - args.Push(Str_8((Char_8*)&data[o], i - o)); - o = i + sizeof(Char_8); - } - - if (o < data.Size()) - args.Push(Str_8((Char_8*)&data[o], data.Size() - o - 1)); - - return args; - #else - return {}; - #endif - } - - /* - void* Console::GetHandle() - { - #if defined(EHS_OS_WINDOWS) - void* hdl = FindWindowW(nullptr, GetTitle_16()); - if (hdl == nullptr) - EHS_LOG_INT("Error", 0, "Failed to retrieve native handle with error #" + Str_8::FromNum(GetLastError()) + "."); - - return hdl; - #else - return nullptr; - #endif - } - */ -} \ No newline at end of file diff --git a/src/io/Console_LNX.cpp b/src/io/Console_LNX.cpp new file mode 100644 index 0000000..6a15d3c --- /dev/null +++ b/src/io/Console_LNX.cpp @@ -0,0 +1,308 @@ +#include "ehs/io/Console_LNX.h" +#include "ehs/io/File.h" +#include "ehs/Log.h" + +#include +#include +#include +#include + +namespace ehs +{ + int Console::hdlOut = 0; + int Console::hdlIn = 0; + + void Console::Attach() + { + hdlOut = (int)syscall(SYS_open, "/dev/stdout", O_WRONLY | O_SYNC); + hdlIn = (int)syscall(SYS_open, "/dev/stdin", O_RDONLY); + } + + void Console::Free() + { + int code = (int)syscall(SYS_close, hdlOut); + if (code == -1) + EHS_LOG_INT("Error", 0, "Failed to free the console output with error #" + Str_8::FromNum(errno) + "."); + + hdlOut = 0; + + code = (int)syscall(SYS_close, hdlIn); + if (code == -1) + EHS_LOG_INT("Error", 0, "Failed to free the console input with error #" + Str_8::FromNum(errno) + "."); + + hdlIn = 0; + } + + void Console::Write_32(const Str_32& str, const bool newLine) + { + Str_32 result = str; + if (newLine) + result += U"\n"; + + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, &result[0], result.Size(true)); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < result.Size(true)); + } + + void Console::Write_16(const Str_16& str, const bool newLine) + { + Str_16 result = str; + if (newLine) + result += L"\n"; + + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, &result[0], result.Size(true)); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < result.Size(true)); + } + + void Console::Write_8(const Str_8& str, const bool newLine) + { + Str_8 result = str; + if (newLine) + result += "\n"; + + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, &result[0], result.Size()); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < result.Size()); + } + + Str_32 Console::Read_32(const UInt_64 bufferSize) + { + Str_32 result; + Str_32 input(bufferSize); + ssize_t read = 0; + + do + { + read = syscall(SYS_read, hdlIn, &input[0], bufferSize); + if (read == -1) + { + EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + "."); + return result; + } + result.Push(input, read); + } + while (input[read - 1] != U'\n'); + + return result; + } + + Str_16 Console::Read_16(const UInt_64 bufferSize) + { + Str_16 result; + Str_16 input(bufferSize); + ssize_t read = 0; + + do + { + read = syscall(SYS_read, hdlIn, &input[0], bufferSize); + if (read == -1) + { + EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + "."); + return result; + } + result.Push(input, read); + } + while (input[read - 1] != L'\n'); + + return result; + } + + Str_8 Console::Read_8(const UInt_64 bufferSize) + { + Str_8 result; + Str_8 input(bufferSize); + ssize_t read = 0; + + do + { + read = syscall(SYS_read, hdlIn, &input[0], bufferSize); + if (read == -1) + { + EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + "."); + return result; + } + result.Push(input, read); + } + while (input[read - 1] != '\n'); + + return result.Sub(0, result.Size() - 1); + } + + void Console::Clear() + { + const Char_8 code[] = "\033[2J\033[1;1H"; + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, code, sizeof(code)); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to clear console with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < sizeof(code)); + } + + void Console::SetTitle_32(const Str_32& title) + { + Str_32 code = U"\033]0;" + title + U"\007"; + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, &code[0], code.Size(true)); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < code.Size(true)); + } + + void Console::SetTitle_16(const Str_16& title) + { + Str_16 code = L"\033]0;" + title + L"\007"; + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, &code[0], code.Size(true)); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < code.Size(true)); + } + + void Console::SetTitle_8(const Str_8& title) + { + Str_8 code = "\033]0;" + title + "\007"; + UInt_64 offset = 0; + do { + ssize_t written = syscall(SYS_write, hdlOut, &code[0], code.Size()); + if (written == -1) + { + EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + "."); + return; + } + offset += written; + } + while (offset < code.Size()); + } + + Str_32 Console::GetTitle_32() + { + return {}; + } + + Str_16 Console::GetTitle_16() + { + return {}; + } + + Str_8 Console::GetTitle_8() + { + return {}; + } + + Vector Console::GetArgs_32(const UInt_64 bufferSize) + { + File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN); + Array data = cmdFile.ReadArray(bufferSize); + cmdFile.Release(); + + Vector args; + + UInt_64 o = 0; + for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8)) + { + if (data[i] != '\0') + continue; + + + + args.Push(UTF::To_32((Char_8*)&data[o], i - o)); + o = i + sizeof(Char_8); + } + + if (o < data.Size()) + args.Push(UTF::To_32((Char_8*)&data[o], data.Size() - o - 1)); + + return args; + } + + Vector Console::GetArgs_16(const UInt_64 bufferSize) + { + File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN); + Array data = cmdFile.ReadArray(bufferSize); + cmdFile.Release(); + + Vector args; + + UInt_64 o = 0; + for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8)) + { + if (data[i] != '\0') + continue; + + args.Push(UTF::To_16((Char_8*)&data[o], i - o)); + o = i + sizeof(Char_8); + } + + if (o < data.Size()) + args.Push(UTF::To_16((Char_8*)&data[o], data.Size() - o - 1)); + + return args; + } + + Vector Console::GetArgs_8(const UInt_64 bufferSize) + { + File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN); + Array data = cmdFile.ReadArray(bufferSize); + cmdFile.Release(); + + Vector args; + + UInt_64 o = 0; + for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8)) + { + if (data[i] != '\0') + continue; + + args.Push(Str_8((Char_8*)&data[o], i - o)); + o = i + sizeof(Char_8); + } + + if (o < data.Size()) + args.Push(Str_8((Char_8*)&data[o], data.Size() - o - 1)); + + return args; + } +} \ No newline at end of file diff --git a/src/io/Console_W32.cpp b/src/io/Console_W32.cpp new file mode 100644 index 0000000..f84207f --- /dev/null +++ b/src/io/Console_W32.cpp @@ -0,0 +1,442 @@ +#include "ehs/io/Console_W32.h" + +namespace ehs +{ + void* Console::hdlOut = nullptr; + void* Console::hdlIn = nullptr; + bool Console::isConsole = true; + + void Console::Attach() + { + if (!AttachConsole(ATTACH_PARENT_PROCESS)) + { + DWORD code = GetLastError(); + if (code == ERROR_INVALID_HANDLE) + return; + } + + hdlIn = GetStdHandle(STD_INPUT_HANDLE); + hdlOut = GetStdHandle(STD_OUTPUT_HANDLE); + + DWORD mode = 0; + + if (!GetConsoleMode(hdlOut, &mode)) + { + if (GetLastError() == ERROR_INVALID_HANDLE) + isConsole = false; + } + else + { + //DWORD code = WaitForSingleObject(hdlIn, 15000); + //if (code == WAIT_FAILED || code == WAIT_TIMEOUT || code == WAIT_ABANDONED) + // EHS_LOG_INT("Error", 0, "Failed to wait for console input."); + + isConsole = true; + } + } + + void Console::Free() + { + hdlOut = nullptr; + hdlIn = nullptr; + } + + void Console::Write_32(const Str_32& str, const bool newLine) + { + if (isConsole) + { + Str_16 r = UTF::To_16(str); + if (newLine) + r += L"\r\n"; + + DWORD offset = 0; + + do + { + DWORD written = 0; + if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + offset += written; + } + while (offset < r.Size()); + } + else + { + Str_8 r = UTF::To_8(str); + if (newLine) + r += "\r\n"; + + DWORD offset = 0; + + do + { + DWORD written = 0; + if (!WriteFile(hdlOut, &((Char_8*)r)[offset], (DWORD)r.Size(true) - offset, &written, nullptr)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + offset += written; + } + while (offset < r.Size(true)); + } + } + + void Console::Write_16(const Str_16& str, const bool newLine) + { + if (isConsole) + { + Str_16 r = str; + if (newLine) + r += L"\r\n"; + + DWORD offset = 0; + + do + { + DWORD written = 0; + if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + offset += written; + } + while (offset < r.Size()); + } + else + { + Str_8 r = UTF::To_8(str); + if (newLine) + r += "\r\n"; + + DWORD offset = 0; + + do + { + DWORD written = 0; + if (!WriteFile(hdlOut, &((Char_8*)r)[offset], (DWORD)r.Size(true) - offset, &written, nullptr)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + offset += written; + } + while (offset < r.Size(true)); + } + } + + void Console::Write_8(const Str_8& str, const bool newLine) + { + if (isConsole) + { + Str_16 r = UTF::To_16(str); + if (newLine) + r += L"\r\n"; + + DWORD offset = 0; + + do + { + DWORD written = 0; + if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + offset += written; + } + while (offset < r.Size()); + } + else + { + Str_8 r = str; + if (newLine) + r += "\r\n"; + + DWORD offset = 0; + + do + { + DWORD written = 0; + if (!WriteFile(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + offset += written; + } + while (offset < r.Size()); + } + } + + Str_32 Console::Read_32(const UInt_64 bufferSize) + { + if (isConsole) + { + Str_16 result; + + DWORD offset = 0; + + do + { + result.Resize(result.Size() + bufferSize); + + DWORD read = 0; + + if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) + { + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + return U""; + } + + offset += read; + } + while (result[offset - 1] != L'\n'); + + if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n') + result.Resize(offset - 2); + else + result.Resize(offset - 1); + + return UTF::To_32(result); + } + else + { + Str_8 result; + + DWORD offset = 0; + + do + { + result.Resize(result.Size() + bufferSize); + + DWORD read = 0; + + if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) + { + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + return U""; + } + + offset += read; + } + while (result[offset - 1] != '\n'); + + if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n') + result.Resize(offset - 2); + else + result.Resize(offset - 1); + + return UTF::To_32(result); + } + } + + Str_16 Console::Read_16(const UInt_64 bufferSize) + { + if (isConsole) + { + Str_16 result; + + DWORD offset = 0; + + do + { + result.Resize(result.Size() + bufferSize); + + DWORD read = 0; + + if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) + { + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + return L""; + } + + offset += read; + } + while (result[offset - 1] != L'\n'); + + if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n') + result.Resize(offset - 2); + else + result.Resize(offset - 1); + + return result; + } + else + { + Str_8 result; + + DWORD offset = 0; + + do + { + result.Resize(result.Size() + bufferSize); + + DWORD read = 0; + + if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) + { + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + return L""; + } + + offset += read; + } + while (result[offset - 1] != '\n'); + + if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n') + result.Resize(offset - 2); + else + result.Resize(offset - 1); + + return UTF::To_16(result); + } + } + + Str_8 Console::Read_8(const UInt_64 bufferSize) + { + if (isConsole) + { + Str_16 result; + + DWORD offset = 0; + + do + { + result.Resize(result.Size() + bufferSize); + + DWORD read = 0; + + if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) + { + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + return ""; + } + + offset += read; + } + while (result[offset - 1] != L'\n'); + + if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n') + result.Resize(offset - 2); + else + result.Resize(offset - 1); + + return UTF::To_8(result); + } + else + { + Str_8 result; + + DWORD offset = 0; + + do + { + result.Resize(result.Size() + bufferSize); + + DWORD read = 0; + + if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr)) + { + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + + return ""; + } + + offset += read; + } + while (result[offset - 1] != '\n'); + + if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n') + result.Resize(offset - 2); + else + result.Resize(offset - 1); + + return result; + } + } + + void Console::Clear() + { + CONSOLE_SCREEN_BUFFER_INFO info = {}; + if (!GetConsoleScreenBufferInfo(hdlOut, &info)) + return; + + DWORD size = info.dwSize.X * info.dwSize.Y; + + DWORD written = 0; + if (!FillConsoleOutputCharacterW(hdlOut, L' ', size, {0, 0}, &written)) + return; + + if (!GetConsoleScreenBufferInfo(hdlOut, &info)) + return; + + if (!FillConsoleOutputAttribute(hdlOut, info.wAttributes, size, {0, 0}, &written)) + return; + + SetConsoleCursorPosition(hdlOut, {0, 0}); + } + + void Console::SetTitle_32(const Str_32& title) + { + if (!SetConsoleTitleW(UTF::To_16(title))) + EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(GetLastError()) + "."); + } + + void Console::SetTitle_16(const Str_16& title) + { + if (!SetConsoleTitleW(title)) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + } + + void Console::SetTitle_8(const Str_8& title) + { + if (!SetConsoleTitleW(UTF::To_16(title))) + EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + "."); + } + + Str_32 Console::GetTitle_32() + { + Str_16 title(EHS_MAX_PATH); + + DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH); + + title.Resize(size); + + return UTF::To_32(title); + } + + Str_16 Console::GetTitle_16() + { + Str_16 title(EHS_MAX_PATH); + + DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH); + + title.Resize(size); + + return title; + } + + Str_8 Console::GetTitle_8() + { + Str_16 title(EHS_MAX_PATH); + + DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH); + + title.Resize(size); + + return UTF::To_8(title); + } + + Vector Console::GetArgs_32(const UInt_64 bufferSize) + { + return UTF::To_32(GetCommandLineW()).Split(U" "); + } + + Vector Console::GetArgs_16(const UInt_64 bufferSize) + { + return Str_16(GetCommandLineW()).Split(L" "); + } + + Vector Console::GetArgs_8(const UInt_64 bufferSize) + { + return UTF::To_8(GetCommandLineW()).Split(" "); + } +} \ No newline at end of file diff --git a/src/io/File_UNX.cpp b/src/io/File_UNX.cpp index 0cb1409..086f11c 100644 --- a/src/io/File_UNX.cpp +++ b/src/io/File_UNX.cpp @@ -7,15 +7,16 @@ #include #include #include +#include namespace ehs { File::~File() { - if (map != MAP_FAILED && munmap(map, mapSize) == -1) + if (map != MAP_FAILED && syscall(SYS_munmap, map, mapSize) == -1) EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + "."); - if (hdl >= 0 && close(hdl) == -1) + if (hdl >= 0 && syscall(SYS_close, hdl) == -1) EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(errno) + "."); } @@ -61,22 +62,22 @@ namespace ehs break; } - hdl = open64(path, linuxMode | linuxDisp, S_IRUSR | S_IWUSR); + hdl = (int)syscall(SYS_open, &path[0], linuxMode | linuxDisp, S_IRUSR | S_IWUSR); if (hdl == -1) { SInt_32 code = errno; if (code == EEXIST && (disposition == Disposition::CREATE_PERSISTENT || disposition == Disposition::OPEN_PERSISTENT)) { - hdl = open64(path, linuxMode, S_IRUSR | S_IWUSR); + hdl = (int)syscall(SYS_open, &path[0], linuxMode, S_IRUSR | S_IWUSR); if (hdl == -1) - EHS_LOG_INT("Error", 0, strerror(errno)); + EHS_LOG_INT("Error", 0, "Failed to create file."); } else { if (code == ENOENT) EHS_LOG_INT("Error", 0, "File at filepath, \"" + filePath + "\" not found."); else - EHS_LOG_INT("Error", 0, strerror(code)); + EHS_LOG_INT("Error", 0, "Failed to open file."); } } } @@ -136,12 +137,12 @@ namespace ehs void File::Release() { - if (IsMapped() && munmap(map, mapSize) == -1) + if (IsMapped() && syscall(SYS_munmap, map, mapSize) == -1) EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + "."); map = MAP_FAILED; mapSize = 0; - if (IsValid() && close(hdl) == -1) + if (IsValid() && syscall(SYS_close, hdl) == -1) EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(errno) + "."); hdl = -1; } @@ -175,7 +176,7 @@ namespace ehs break; } - map = mmap64(nullptr, size, linuxMode, MAP_SHARED, hdl, (off64_t)offset); + map = (void*)syscall(SYS_mmap, nullptr, size, linuxMode, MAP_SHARED, hdl, (off64_t)offset); if (map == MAP_FAILED) { EHS_LOG_INT("Error", 0, "Failed to map with error #" + Str_8::FromNum(errno) + "."); @@ -190,7 +191,7 @@ namespace ehs if (!IsValid() || !IsMapped()) return; - if (munmap(map, mapSize) == -1) + if (syscall(SYS_munmap, map, mapSize) == -1) EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + "."); map = MAP_FAILED; @@ -202,7 +203,7 @@ namespace ehs if (!IsValid() || !IsMapped()) return; - if (msync((void*)map, mapSize, MS_SYNC) == -1) + if (syscall(SYS_msync, (void*)map, mapSize, MS_SYNC) == -1) EHS_LOG_INT("Error", 0, "Failed to flush view with error #" + Str_8::FromNum(errno) + "."); } @@ -212,7 +213,7 @@ namespace ehs return 0; SInt_64 written = 0; - written = write(hdl, data, size); + written = syscall(SYS_write, hdl, data, size); if (written == -1) EHS_LOG_INT("Error", 0, "Failed to write to file, \"" + path + "\", with error #" + Str_8::FromNum(errno) + "."); @@ -225,7 +226,7 @@ namespace ehs return 0; SInt_64 read = 0; - read = ::read(hdl, data, (size_t)size); + read = syscall(SYS_read, hdl, data, (size_t)size); if (read == -1) EHS_LOG_INT("Error", 0, "Failed to read from file, \"" + path + "\", with error #" + Str_8::FromNum(errno) + "."); @@ -237,7 +238,7 @@ namespace ehs if (!IsValid() || IsMapped()) return; - if (lseek64(hdl, (off64_t)index, SEEK_SET) == -1) + if (syscall(SYS_lseek, hdl, index, SEEK_SET) == -1) EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + "."); } @@ -246,7 +247,7 @@ namespace ehs if (!IsValid() || IsMapped()) return; - if (lseek64(hdl, 0, SEEK_SET) == -1) + if (syscall(SYS_lseek, hdl, 0, SEEK_SET) == -1) EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + "."); } @@ -255,7 +256,7 @@ namespace ehs if (!IsValid() || IsMapped()) return; - if (lseek64(hdl, 0, SEEK_END) == -1) + if (syscall(SYS_lseek, hdl, 0, SEEK_END) == -1) EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + "."); } @@ -264,7 +265,7 @@ namespace ehs if (!IsValid() || IsMapped()) return; - if (ftruncate64(hdl, (off64_t)size) == -1) + if (syscall(SYS_ftruncate, hdl, (off64_t)size) == -1) EHS_LOG_INT("Error", 0, "Failed to truncate with error #" + Str_8::FromNum(errno) + "."); } @@ -272,7 +273,7 @@ namespace ehs { struct stat64 info = {}; - if (fstat64(hdl, &info) == -1) + if (syscall(SYS_fstat, hdl, &info) == -1) EHS_LOG_INT("Error", 0, "Failed to retrieve file size with error #" + Str_8::FromNum(errno) + "."); return info.st_size; @@ -301,7 +302,7 @@ namespace ehs if (filePath.Find("/", &index, SearchPattern::RIGHT_LEFT) || filePath.Find("\\", &index, SearchPattern::RIGHT_LEFT)) path = filePath.Sub(0, index); - if (rename(filePath, path + newName) == -1) + if (syscall(SYS_rename, &filePath[0], &(path + newName)[0]) == -1) EHS_LOG_INT("Error", 0, "Failed to rename file with error #" + Str_8::FromNum(errno) + "."); } } diff --git a/src/io/Window_W32.cpp b/src/io/Window_W32.cpp index 2ae1097..42203b5 100644 --- a/src/io/Window_W32.cpp +++ b/src/io/Window_W32.cpp @@ -1,7 +1,7 @@ #include "ehs/io/Window_W32.h" #include "ehs/io/hid/Keyboard.h" #include "ehs/io/hid/Mouse.h" -#include "ehs/system/Thread.h" +#include "ehs/system/OldThread.h" #include diff --git a/src/io/Window_Way.cpp b/src/io/Window_Way.cpp index b07d3e5..4f0b428 100644 --- a/src/io/Window_Way.cpp +++ b/src/io/Window_Way.cpp @@ -1,4 +1,4 @@ -#include "io/Window_Way.h" +#include "ehs/io/Window_Way.h" namespace ehs { diff --git a/src/io/Window_XCB.cpp b/src/io/Window_XCB.cpp index 52e8dff..0899607 100644 --- a/src/io/Window_XCB.cpp +++ b/src/io/Window_XCB.cpp @@ -3,7 +3,7 @@ #include "ehs/Vec2.h" #include "ehs/io/hid/Keyboard.h" #include "ehs/io/hid/Mouse.h" -#include "ehs/io/Console.h" +#include "ehs/io/BaseConsole.h" #include #include diff --git a/src/io/socket/rest/TwitchChat.cpp b/src/io/socket/rest/TwitchChat.cpp index 257a469..f4ff03d 100644 --- a/src/io/socket/rest/TwitchChat.cpp +++ b/src/io/socket/rest/TwitchChat.cpp @@ -1,6 +1,6 @@ #include "ehs/io/socket/rest/TwitchChat.h" #include "ehs/io/socket/DNS.h" -#include "ehs/io/Console.h" +#include "ehs/io/BaseConsole.h" namespace ehs { @@ -59,13 +59,13 @@ namespace ehs Str_8 r("PASS oauth:" + token + "\r\n"); - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); r = "NICK " + username + "\r\n"; - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); @@ -91,7 +91,7 @@ namespace ehs Str_8 r("Join #" + newChannel + "\r\n"); - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); } @@ -103,7 +103,7 @@ namespace ehs Str_8 r("PART #" + channel + "\r\n"); - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); } @@ -115,7 +115,7 @@ namespace ehs Str_8 r("PONG :tmi.twitch.tv\r\n"); - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); } @@ -127,7 +127,7 @@ namespace ehs Str_8 r("PRIVMSG #" + channel + " :" + msg + "\r\n"); - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); @@ -141,7 +141,7 @@ namespace ehs Str_8 r("PRIVMSG #jtv :/w " + user + " " + msg + "\r\n"); - Console::Write_8("< " + r, false); + BaseConsole::Write_8("< " + r, false); client.Send(r.ToBytes(), (int) r.Size()); } diff --git a/src/system/BaseThread.cpp b/src/system/BaseThread.cpp new file mode 100644 index 0000000..fc7d002 --- /dev/null +++ b/src/system/BaseThread.cpp @@ -0,0 +1,93 @@ +#include "ehs/system/BaseThread.h" +#include "ehs/system/CPU.h" + +namespace ehs +{ + BaseThread::BaseThread() + : stackSize(0), id(0) + { + } + + BaseThread::BaseThread(const UInt_64 stackSize) + : stackSize(stackSize), id(0) + { + } + + BaseThread::BaseThread(BaseThread&& thread) noexcept + : stackSize(thread.stackSize), id(thread.id) + { + thread.stackSize = 0; + thread.id = 0; + } + + BaseThread::BaseThread(const BaseThread& thread) + : stackSize(thread.stackSize), id(0) + { + } + + BaseThread& BaseThread::operator=(BaseThread&& thread) noexcept + { + if (this == &thread) + return *this; + + stackSize = thread.stackSize; + id = thread.id; + + thread.stackSize = 0; + thread.id = 0; + + return *this; + } + + BaseThread& BaseThread::operator=(const BaseThread& thread) + { + if (this == &thread) + return *this; + + stackSize = thread.stackSize; + id = 0; + + return *this; + } + + void BaseThread::Detach() + { + stackSize = 0; + id = 0; + } + + UInt_64 BaseThread::GetStackSize() const + { + return stackSize; + } + + UInt_32 BaseThread::GetId() const + { + return id; + } + + UInt_32 BaseThread::GetCurrentId() + { + return 0; + } + + bool BaseThread::IsValid() const + { + return stackSize && id; + } + + float BaseThread::SoftSleep(const float seconds) + { + UInt_64 freq = CPU::GetTSC_Freq(); + UInt_64 start = CPU::GetTSC(); + + float elapsed = 0.0f; + while ((elapsed = (float)(CPU::GetTSC() - start) / (float)freq) <= seconds); + + return elapsed; + } + + void BaseThread::HardSleep(const UInt_32 milliseconds) + { + } +} \ No newline at end of file diff --git a/src/system/CPU.cpp b/src/system/CPU.cpp index ccab72e..3a852e4 100644 --- a/src/system/CPU.cpp +++ b/src/system/CPU.cpp @@ -554,7 +554,7 @@ namespace ehs { UInt_64 result = GetTSC(); - Thread::SleepFor(10000); + Thread::HardSleep(10000); return (GetTSC() - result) / 10; } diff --git a/src/system/Lock_GCC_AMD64.asm b/src/system/Lock_GCC_AMD64.asm new file mode 100644 index 0000000..1973499 --- /dev/null +++ b/src/system/Lock_GCC_AMD64.asm @@ -0,0 +1,49 @@ +global _ZN3ehs4Lock3AddEPmm +global _ZN3ehs4Lock3SubEPmm +global _ZN3ehs4Lock7CmpXchgEPmS1_m +global _ZN3ehs4Lock3AndEPmm +global _ZN3ehs4Lock2OrEPmm +global _ZN3ehs4Lock3XOrEPmm +global _ZN3ehs4Lock3IncEPm +global _ZN3ehs4Lock3DecEPm +global _ZN3ehs4Lock3NotEPm + +section .text + _ZN3ehs4Lock3AddEPmm: + LOCK ADD [RDI], RSI + RET + + _ZN3ehs4Lock3SubEPmm: + LOCK SUB [RDI], RSI + RET + + _ZN3ehs4Lock7CmpXchgEPmS1_m: + MOV RAX, [RDI] + LOCK CMPXCHG [RSI], RDX + MOV [RDI], RAX + SETZ AL + RET + + _ZN3ehs4Lock3AndEPmm: + LOCK AND [RDI], RSI + RET + + _ZN3ehs4Lock2OrEPmm: + LOCK OR [RDI], RSI + RET + + _ZN3ehs4Lock3XOrEPmm: + LOCK XOR [RDI], RSI + RET + + _ZN3ehs4Lock3IncEPm: + LOCK INC QWORD [RDI] + RET + + _ZN3ehs4Lock3DecEPm: + LOCK DEC QWORD [RDI] + RET + + _ZN3ehs4Lock3NotEPm: + LOCK NOT QWORD [RDI] + RET \ No newline at end of file diff --git a/src/system/Mutex_PT.cpp b/src/system/Mutex_PT.cpp index 82ec5b5..f667739 100644 --- a/src/system/Mutex_PT.cpp +++ b/src/system/Mutex_PT.cpp @@ -6,17 +6,15 @@ namespace ehs { if (!initialized) return; - - pthread_mutex_destroy(&hdl); } Mutex::Mutex() - : hdl{} + : state(0) { } Mutex::Mutex(const Mutex& mutex) - : BaseMutex(mutex), hdl{} + : BaseMutex(mutex), state(0) { } @@ -27,7 +25,7 @@ namespace ehs BaseMutex::operator=(mutex); - hdl = {}; + state = 0; return *this; } @@ -37,10 +35,6 @@ namespace ehs if (initialized) return; - pthread_mutex_t hdl = {}; - - int code = pthread_mutex_init(&hdl, nullptr); - initialized = true; } @@ -49,28 +43,14 @@ namespace ehs if (!initialized) return; - pthread_mutex_destroy(&hdl); - initialized = false; } void Mutex::Lock() { - if (locked) - return; - - pthread_mutex_lock(&hdl); - - locked = true; } void Mutex::Unlock() { - if (!locked) - return; - - pthread_mutex_unlock(&hdl); - - locked = false; } } \ No newline at end of file diff --git a/src/system/System_LNX.cpp b/src/system/System_LNX.cpp index 49e3c98..d3a966a 100644 --- a/src/system/System_LNX.cpp +++ b/src/system/System_LNX.cpp @@ -15,8 +15,7 @@ namespace ehs void System::OpenURI(const Str_8& uri) { - Thread xdg; - xdg.Start(XDG_Thread, (void*)&uri); + Thread xdg(2, (void*)&uri, XDG_Thread); xdg.Detach(); } } \ No newline at end of file diff --git a/src/system/Thread.cpp b/src/system/Thread.cpp deleted file mode 100644 index 5b902ad..0000000 --- a/src/system/Thread.cpp +++ /dev/null @@ -1,284 +0,0 @@ -#include "ehs/system/Thread.h" -#include "ehs/system/CPU.h" - -#if defined(EHS_OS_WINDOWS) - #include -#elif defined(EHS_OS_LINUX) - #include - #include -#endif - -namespace ehs -{ - UInt_32 Thread::mainId = GetCurrentId(); - - #ifdef EHS_OS_WINDOWS - Handle Thread::mainTaskHdl = nullptr; - UInt_32 Thread::mainTaskIndex = 0; - #endif - - Thread::~Thread() - { - Join(); - } - - Thread::Thread(const UInt_64 stackSize) - : stackSize(stackSize), hdl(EHS_INVALID_THREAD), id(0) - #ifdef EHS_OS_WINDOWS - ,taskHdl(nullptr), taskIndex(0) - #endif - { - } - - Thread::Thread(const Thread& thread) - : stackSize(thread.stackSize), hdl(EHS_INVALID_THREAD), id(0) - #ifdef EHS_OS_WINDOWS - , taskHdl(nullptr), taskIndex(0) - #endif - { - } - - Thread& Thread::operator=(const Thread& thread) - { - if (this == &thread) - return *this; - - stackSize = thread.stackSize; - hdl = EHS_INVALID_THREAD; - id = 0; - - #ifdef EHS_OS_WINDOWS - taskHdl = nullptr; - taskIndex = 0; - #endif - - return* this; - } - - void Thread::Start(UInt_32 (*cb)(void*), void* args) - { - #if defined(EHS_OS_WINDOWS) - hdl = CreateThread(nullptr, stackSize, (LPTHREAD_START_ROUTINE)cb, args, 0, (DWORD*)&id); - if (!hdl) - EHS_LOG_INT("Error", 0, "Failed to start thread with error #" + Str_8::FromNum(GetLastError()) + "."); - #elif defined(EHS_OS_LINUX) - UInt_64* rArgs = new UInt_64[sizeof(UInt_64) * 2]; - rArgs[0] = (UInt_64)cb; - rArgs[1] = (UInt_64)args; - - pthread_create((pthread_t*)&hdl, nullptr, Redirect, (void*)rArgs); - #endif - } - - bool Thread::Join(const unsigned int timeout) - { - if (hdl == EHS_INVALID_THREAD) - return false; - - #if defined(EHS_WINDOWS) - unsigned int r = WaitForSingleObject(hdl, timeout); - if (r == WAIT_ABANDONED) - { - EHS_LOG_INT("Error", 0, "Abandoned wait because a mutex was not released."); - return false; - } - else if (r == WAIT_TIMEOUT) - { - return false; - } - else if (r == WAIT_FAILED) - { - EHS_LOG_INT("Error", 1, "Failed to wait for thread with error #" + Str_8::FromNum(GetLastError()) + "."); - return false; - } - - mainTaskIndex = 0; - #elif defined(EHS_OS_LINUX) - int code = pthread_join((pthread_t)hdl, nullptr); - if (code != 0) - EHS_LOG_INT("Error", 1, "Failed to wait for thread with error #" + Str_8::FromNum(code) + "."); - - hdl = EHS_INVALID_THREAD; - #endif - - return true; - } - - void Thread::Detach() - { - if (!hdl) - return; - - #if defined(EHS_OS_WINDOWS) - if (!CloseHandle(hdl)) - { - EHS_LOG_INT("Error", 0, "Failed to detach thread with error #" + Str_8::FromNum(GetLastError()) + "."); - return; - } - #elif defined(EHS_OS_LINUX) - pthread_detach(hdl); - - hdl = EHS_INVALID_THREAD; - #endif - } - - UInt_64 Thread::GetStackSize() const - { - return stackSize; - } - - THandle Thread::GetHandle() const - { - return hdl; - } - - UInt_32 Thread::GetId() const - { - return id; - } - - bool Thread::IsCurrent() const - { - return id == GetCurrentId(); - } - - bool Thread::IsValid() const - { - return hdl; - } - - #ifdef EHS_OS_WINDOWS - void Thread::SetTaskType_32(const Str_32& task) - { - if (!IsCurrent()) - return; - - taskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&taskIndex); - if (!taskHdl) - EHS_LOG_INT("Error", 0, "Failed to set the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - } - - void Thread::SetTaskType_16(const Str_16& task) - { - if (!IsCurrent()) - return; - - taskHdl = AvSetMmThreadCharacteristicsW(task, (LPDWORD)&taskIndex); - if (!taskHdl) - EHS_LOG_INT("Error", 0, "Failed to set the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - } - - void Thread::SetTaskType_8(const Str_8& task) - { - if (!IsCurrent()) - return; - - taskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&taskIndex); - if (!taskHdl) - EHS_LOG_INT("Error", 0, "Failed to set the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - } - - void Thread::RevertTaskType() - { - if (!IsCurrent()) - return; - - if (!AvRevertMmThreadCharacteristics(taskHdl)) - EHS_LOG_INT("Error", 0, "Failed to revert the thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - - taskIndex = 0; - } - #endif - - UInt_32 Thread::GetMainId() - { - return mainId; - } - - UInt_64 Thread::GetCurrentId() - { - #if defined(EHS_OS_WINDOWS) - return GetCurrentThreadId(); - #elif defined(EHS_OS_LINUX) - return pthread_self(); - #endif - } - - #ifdef EHS_OS_WINDOWS - void Thread::SetMainTaskType_32(const Str_32& task) - { - if (GetCurrentId() != mainId) - return; - - mainTaskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&mainTaskIndex); - if (!mainTaskHdl) - EHS_LOG_INT("Error", 0, "Failed to set the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - } - - void Thread::SetMainTaskType_16(const Str_16& task) - { - if (GetCurrentId() != mainId) - return; - - mainTaskHdl = AvSetMmThreadCharacteristicsW(task, (LPDWORD)&mainTaskIndex); - if (!mainTaskHdl) - EHS_LOG_INT("Error", 0, "Failed to set the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - } - - void Thread::SetMainTaskType_8(const Str_8& task) - { - if (GetCurrentId() != mainId) - return; - - mainTaskHdl = AvSetMmThreadCharacteristicsW(UTF::To_16(task), (LPDWORD)&mainTaskIndex); - if (!mainTaskHdl) - EHS_LOG_INT("Error", 0, "Failed to set the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - } - - void Thread::RevertMainTaskType() - { - if (GetCurrentId() != mainId) - return; - - if (!AvRevertMmThreadCharacteristics(mainTaskHdl)) - EHS_LOG_INT("Error", 0, "Failed to revert the main thread's characteristics with error #" + Str_8::FromNum(GetLastError()) + "."); - - mainTaskIndex = 0; - } - #endif - - float Thread::HardSleepFor(const float seconds) - { - UInt_64 freq = CPU::GetTSC_Freq(); - UInt_64 start = CPU::GetTSC(); - - float elapsed = 0.0f; - while ((elapsed = (float)(CPU::GetTSC() - start) / (float)freq) <= seconds); - - return elapsed; - } - - void Thread::SleepFor(const UInt_32 miliseconds) - { - #if defined(EHS_OS_WINDOWS) - Sleep(miliseconds); - #elif defined(EHS_OS_LINUX) - timespec req = {miliseconds / 1000, miliseconds % 1000 * 1000000}; - nanosleep(&req, nullptr); - #endif - } - - void* Thread::Redirect(void *args) - { - UInt_64* rArgs = (UInt_64*)args; - UInt_32 (*cb)(void*) = (UInt_32 (*)(void*))rArgs[0]; - void* params = (void*)rArgs[1]; - - UInt_32* code = new UInt_32(); - *code = cb(params); - - delete[] rArgs; - - return code; - } -} \ No newline at end of file diff --git a/src/system/Thread_LNX.cpp b/src/system/Thread_LNX.cpp new file mode 100644 index 0000000..ae227a0 --- /dev/null +++ b/src/system/Thread_LNX.cpp @@ -0,0 +1,161 @@ +#include "ehs/system/Thread_LNX.h" +#include "ehs/Serializer.h" + +#include +#include +#include +#include +#include + +namespace ehs +{ + Thread::~Thread() + { + if (detached && !*detached) + { + if (stack && syscall(SYS_munmap, stack, GetStackSize()) == -1) + EHS_LOG_INT("Error", 0, "Failed to deallocate stack for thread with error #" + Str_8::FromNum(errno) + "."); + + delete detached; + } + } + + Thread::Thread() + : BaseThread(0), stack(nullptr), hdl(0), detached(nullptr) + { + } + + Thread::Thread(UInt_64 stackSize, void* args, UInt_32 (*func)(void*)) + : BaseThread(1024 * stackSize), stack(nullptr), hdl(0), detached(new bool(false)) + { + stack = (void*)syscall(SYS_mmap, nullptr, GetStackSize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (stack == MAP_FAILED) + { + EHS_LOG_INT("Error", 0, "Failed to allocate stack for thread."); + return; + } + + Serializer* data = new Serializer(Endianness::LE); + data->Write(GetStackSize()); + data->Write(stack); + data->Write(detached); + data->Write(args); + data->Write(func); + + hdl = (pid_t)syscall(SYS_clone, Redirect, stackSize, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD, data); + id = hdl; + } + + Thread::Thread(Thread&& thread) noexcept + : BaseThread((BaseThread&&)thread), stack(thread.stack), hdl(thread.hdl), detached(thread.detached) + { + thread.stack = nullptr; + thread.hdl = 0; + thread.detached = nullptr; + } + + Thread::Thread(const Thread& thread) + : BaseThread(thread), stack(nullptr), hdl(0), detached(nullptr) + { + } + + Thread& Thread::operator=(Thread&& thread) noexcept + { + if (this == &thread) + return *this; + + Join(); + + BaseThread::operator=((BaseThread&&)thread); + + stack = thread.stack; + hdl = thread.hdl; + detached = thread.detached; + + thread.stack = nullptr; + thread.hdl = 0; + thread.detached = nullptr; + + return *this; + } + + Thread& Thread::operator=(const Thread& thread) + { + if (this == &thread) + return *this; + + Join(); + + BaseThread::operator=(thread); + + stack = nullptr; + hdl = 0; + detached = nullptr; + + return *this; + } + + void Thread::Detach() + { + BaseThread::Detach(); + + stack = nullptr; + *detached = true; + detached = nullptr; + hdl = 0; + } + + void Thread::Join() + { + if (detached && *detached) + return; + + syscall(SYS_wait4, hdl, nullptr, 0, nullptr); + hdl = 0; + + if (syscall(SYS_munmap, stack, GetStackSize()) == -1) + EHS_LOG_INT("Error", 0, "Failed to deallocate stack in detached thread with error #" + Str_8::FromNum(errno) + "."); + + stack = nullptr; + + delete detached; + detached = nullptr; + } + + UInt_32 Thread::GetCurrentId() + { + return syscall(SYS_gettid); + } + + void Thread::HardSleep(UInt_32 milliseconds) + { + timespec req = {milliseconds / 1000, milliseconds % 1000 * 1000000}; + syscall(SYS_nanosleep, &req, nullptr); + } + + UInt_32 Thread::Redirect(void* args) + { + Serializer* data = (Serializer*)args; + UInt_64 stackSize = data->Read(); + void* stack = data->Read(); + bool* detached = data->Read(); + void* inArgs = data->Read(); + UInt_32 (*func)(void*) = data->Read(); + delete data; + + UInt_32 error = func(inArgs); + + if (*detached) + { + if (syscall(SYS_munmap, stack, stackSize) == -1) + { + error = 1; + EHS_LOG_INT("Error", 0, "Failed to deallocate stack in detached thread with error #" + Str_8::FromNum(errno) + "."); + } + + delete detached; + } + + return error; + } +} \ No newline at end of file diff --git a/src/system/Thread_W32.cpp b/src/system/Thread_W32.cpp new file mode 100644 index 0000000..115dec7 --- /dev/null +++ b/src/system/Thread_W32.cpp @@ -0,0 +1,88 @@ +#include "ehs/system/Thread_W32.h" + +namespace ehs +{ + Thread::~Thread() + { + + } + + Thread::Thread() + { + + } + + Thread::Thread(UInt_64 stackSize, void* args, UInt_32 (* func)(void*)) + { + hdl = CreateThread(nullptr, stackSize, (LPTHREAD_START_ROUTINE)func, args, 0, (DWORD*)&id); + if (!hdl) + EHS_LOG_INT("Error", 0, "Failed to start thread with error #" + Str_8::FromNum(GetLastError()) + "."); + } + + Thread::Thread(Thread&& thread) noexcept + { + + } + + Thread::Thread(const Thread& thread) + { + + } + + Thread& Thread::operator=(Thread&& thread) noexcept + { + return <#initializer#>; + } + + Thread& Thread::operator=(const Thread& thread) + { + return <#initializer#>; + } + + void Thread::Detach() + { + BaseThread::Detach(); + + if (!CloseHandle(hdl)) + { + EHS_LOG_INT("Error", 0, "Failed to detach thread with error #" + Str_8::FromNum(GetLastError()) + "."); + return; + } + } + + void Thread::Join() + { + unsigned int r = WaitForSingleObject(hdl, timeout); + if (r == WAIT_ABANDONED) + { + EHS_LOG_INT("Error", 0, "Abandoned wait because a mutex was not released."); + return; + } + else if (r == WAIT_TIMEOUT) + { + return; + } + else if (r == WAIT_FAILED) + { + EHS_LOG_INT("Error", 1, "Failed to wait for thread with error #" + Str_8::FromNum(GetLastError()) + "."); + return; + } + + mainTaskIndex = 0; + } + + UInt_32 Thread::GetCurrentId() + { + return GetCurrentThreadId(); + } + + bool Thread::IsValid() const + { + return BaseThread::IsValid(); + } + + void Thread::HardSleep(UInt_32 milliseconds) + { + Sleep(milliseconds); + } +} \ No newline at end of file