From ef09eb12c8d329e9d26f430bed96a1beeb3d2be6 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Thu, 3 Sep 2020 22:24:50 -0400 Subject: [PATCH] Add a bunch of #ifdefs to keep things working as expected on linux --- .github/workflows/linux-workflow.yaml | 2 +- CMakeLists.txt | 12 +- game/CMakeLists.txt | 6 +- game/kernel/kboot.cpp | 17 ++- game/kernel/kdsnetm.cpp | 21 ++- game/kernel/kdsnetm.h | 8 +- game/kernel/klisten.cpp | 16 ++- game/kernel/kmachine.cpp | 12 +- game/kernel/kmemcard.cpp | 2 +- game/kernel/kmemcard.h | 2 +- game/kernel/kprint.h | 10 +- game/kernel/kscheme.cpp | 4 +- game/kernel/ksocket.cpp | 9 +- game/overlord/fake_iso.cpp | 7 +- game/runtime.cpp | 107 +++++++-------- game/sce/deci2.cpp | 165 +++++++++++++---------- game/system/Deci2Server.cpp | 33 +++-- game/system/Deci2Server.h | 6 +- game/system/SystemThread.cpp | 37 +++++- game/system/SystemThread.h | 4 +- game/system/iop_thread.cpp | 6 +- goalc/emitter/CodeTester.cpp | 9 +- goalc/listener/Listener.cpp | 25 ++-- mman.c | 180 -------------------------- test/test_goos.cpp | 53 ++++---- third-party/json.hpp | 2 +- 26 files changed, 336 insertions(+), 419 deletions(-) delete mode 100644 mman.c diff --git a/.github/workflows/linux-workflow.yaml b/.github/workflows/linux-workflow.yaml index c72db11797..c8e67b0cc1 100644 --- a/.github/workflows/linux-workflow.yaml +++ b/.github/workflows/linux-workflow.yaml @@ -1,5 +1,5 @@ name: Linux Workflow -on: [push] +on: [push, pull_request] jobs: build: diff --git a/CMakeLists.txt b/CMakeLists.txt index 28c2792700..4eb4c9bc27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,8 @@ project(jak) set(CMAKE_CXX_STANDARD 14) -# optimization level can be set here. Note that game/ overwrites this for building game C++ code. -set(CMAKE_CXX_FLAGS "-O3 -ggdb /EHsc") - # Set default compile flags for GCC +# optimization level can be set here. Note that game/ overwrites this for building game C++ code. if(CMAKE_COMPILER_IS_GNUCXX) message(STATUS "GCC detected, adding compile flags") set(CMAKE_CXX_FLAGS @@ -23,13 +21,15 @@ if(CMAKE_COMPILER_IS_GNUCXX) -Wredundant-decls -Wshadow -Wsign-promo") +else() + set(CMAKE_CXX_FLAGS "/EHsc") endif(CMAKE_COMPILER_IS_GNUCXX) IF (WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ENDIF() # includes relative to top level jak-project folder diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 468b2bb6fa..8e5dfa28f3 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -1,9 +1,8 @@ # We define our own compilation flags here. set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_FLAGS "-O3 -ggdb") - # Set default compile flags for GCC +# optimization level can be set here. Note that game/ overwrites this for building game C++ code. if(CMAKE_COMPILER_IS_GNUCXX) message(STATUS "GCC detected, adding compile flags") set(CMAKE_CXX_FLAGS @@ -19,10 +18,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) -Wredundant-decls -Wshadow -Wsign-promo") +else() + set(CMAKE_CXX_FLAGS "/EHsc") endif(CMAKE_COMPILER_IS_GNUCXX) enable_language(ASM_NASM) -#set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} asm) set(CMAKE_ASM_NASM_COMPILE_OBJECT " -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o ") set_source_files_properties(kernel/asm_funcs.asm PROPERTIES COMPILE_FLAGS "-g") diff --git a/game/kernel/kboot.cpp b/game/kernel/kboot.cpp index babb26f3b2..b9545ceaaf 100644 --- a/game/kernel/kboot.cpp +++ b/game/kernel/kboot.cpp @@ -4,7 +4,6 @@ * DONE! */ -#include #include #include "common/common_types.h" #include "game/sce/libscf.h" @@ -13,7 +12,14 @@ #include "kscheme.h" #include "ksocket.h" #include "klisten.h" + +#ifdef _WIN32 #include "Windows.h" +#include +#elif __linux__ +#include +#endif + using namespace ee; // Level to load on boot @@ -128,14 +134,21 @@ void KernelCheckAndDispatch() { // dispatch the kernel //(**kernel_dispatcher)(); call_goal(Ptr(kernel_dispatcher->value), 0, 0, 0, s7.offset, g_ee_main_mem); - //ClearPending(); + // TODO-WINDOWS +#ifdef __linux__ + ClearPending(); +#endif // if the listener function changed, it means the kernel ran it, so we should notify compiler. if (MasterDebug && ListenerFunction->value != old_listener) { SendAck(); } +#ifdef _WIN32 Sleep(1000); // todo - remove this +#elif __linux__ + usleep(1000); +#endif } } diff --git a/game/kernel/kdsnetm.cpp b/game/kernel/kdsnetm.cpp index 00f1080c7e..2d06a93160 100644 --- a/game/kernel/kdsnetm.cpp +++ b/game/kernel/kdsnetm.cpp @@ -1,6 +1,3 @@ - - -/* /*! * @file kdsnetm.cpp * Low-level DECI2 wrapper for ksocket @@ -30,10 +27,12 @@ void kdsnetm_init_globals() { protoBlock.reset(); } +// TODO-WINDOWS +#ifdef __linux__ /*! * Register GOAL DECI2 Protocol Driver with DECI2 service * DONE, EXACT - + */ void InitGoalProto() { protoBlock.socket = sceDeci2Open(DECI2_PROTOCOL, &protoBlock, GoalProtoHandler); if (protoBlock.socket < 0) { @@ -49,12 +48,10 @@ void InitGoalProto() { } } -*/ - /*! * Close the DECI2 Protocol Driver * DONE, EXACT - + */ void ShutdownGoalProto() { if (protoBlock.socket > 0) { sceDeci2Close(protoBlock.socket); @@ -65,7 +62,7 @@ void ShutdownGoalProto() { * Handle a DECI2 Protocol Event for the GOAL Proto. * Called by the DECI2 Protocol driver * DONE, added print statements on errors for debugging, EI and SYNC at the end were removed - + */ void GoalProtoHandler(int event, int param, void* opt) { // verify we got the correct opt pointer. It's not clear why the opt pointer is used // like this? @@ -165,7 +162,7 @@ void GoalProtoHandler(int event, int param, void* opt) { * Will block until send is complete. * DONE, original version used an uncached address and had a FlushCache call, which were both * removed - + */ s32 SendFromBufferD(s32 msg_kind, u64 p2, char* data, s32 size) { // wait for send to finish or error first... while (protoBlock.send_status > 0) { @@ -220,11 +217,9 @@ s32 SendFromBufferD(s32 msg_kind, u64 p2, char* data, s32 size) { /*! * Print GOAL Protocol status - + */ void GoalProtoStatus() { Msg(6, "gproto: got %d %d\n", protoBlock.most_recent_event, protoBlock.most_recent_param); Msg(6, "gproto: %d %d\n", protoBlock.last_receive_size, protoBlock.send_remaining); } - - -*/ \ No newline at end of file +#endif \ No newline at end of file diff --git a/game/kernel/kdsnetm.h b/game/kernel/kdsnetm.h index f49a5132ae..60b6f3715d 100644 --- a/game/kernel/kdsnetm.h +++ b/game/kernel/kdsnetm.h @@ -51,17 +51,21 @@ extern GoalProtoBlock protoBlock; */ void kdsnetm_init_globals(); +// TODO-WINDOWS +#ifdef __linux__ /*! * Register GOAL DECI2 Protocol Driver with DECI2 service * DONE, EXACT */ -//void InitGoalProto(); +void InitGoalProto(); /*! * Close the DECI2 Protocol Driver * DONE, EXACT */ -//void ShutdownGoalProto(); +void ShutdownGoalProto(); + +#endif /*! * Handle a DECI2 Protocol Event for the GOAL Proto. diff --git a/game/kernel/klisten.cpp b/game/kernel/klisten.cpp index ed78cd297d..198858c2ca 100644 --- a/game/kernel/klisten.cpp +++ b/game/kernel/klisten.cpp @@ -71,7 +71,10 @@ void ClearPending() { Ptr msg = OutputBufArea.cast() + sizeof(GoalMessageHeader); auto size = strlen(msg.c()); // note - if size is ever greater than 2^16 this will cause an issue. - // SendFromBuffer(msg.c(), size); + // TODO-WINDOWS + #ifdef __linux__ + SendFromBuffer(msg.c(), size); + #endif clear_output(); } @@ -84,7 +87,10 @@ void ClearPending() { if (send_size > 64000) { send_size = 64000; } -// SendFromBufferD(2, 0, msg, send_size); + // TODO-WINDOWS + #ifdef __linux__ + SendFromBufferD(2, 0, msg, send_size); + #endif size -= send_size; msg += send_size; } @@ -103,9 +109,9 @@ void ClearPending() { */ void SendAck() { if (MasterDebug) { -// SendFromBufferD(u16(ListenerMessageKind::MSG_ACK), protoBlock.msg_id, - // AckBufArea + sizeof(GoalMessageHeader), - // strlen(AckBufArea + sizeof(GoalMessageHeader))); + #ifdef __linux__ + SendFromBufferD(u16(ListenerMessageKind::MSG_ACK), protoBlock.msg_id, AckBufArea + sizeof(GoalMessageHeader), strlen(AckBufArea + sizeof(GoalMessageHeader))); + #endif } } diff --git a/game/kernel/kmachine.cpp b/game/kernel/kmachine.cpp index c72ef5e66c..c1d820a6e2 100644 --- a/game/kernel/kmachine.cpp +++ b/game/kernel/kmachine.cpp @@ -153,7 +153,7 @@ void InitCD() { /*! * Initialize the I/O Processor - * Removed calls to exit(0) if loading modules fails. + * Removed calls to exit(0) if loading modules fails. */ void InitIOP() { // before doing anything with the I/O Processor, we need to set up SIF RPC @@ -329,7 +329,10 @@ int InitMachine() { // } if (MasterDebug) { // connect to GOAL compiler -// InitGoalProto(); + // TODO-WINDOWS + #ifdef __linux__ + InitGoalProto(); + #endif } printf("InitSound\n"); @@ -359,7 +362,10 @@ int ShutdownMachine() { StopIOP(); CloseListener(); ShutdownSound(); -// ShutdownGoalProto(); + // TODO-WINDOWS + #ifdef __linux__ + ShutdownGoalProto(); + #endif Msg(6, "kernel: machine shutdown"); return 0; } diff --git a/game/kernel/kmemcard.cpp b/game/kernel/kmemcard.cpp index 111a6d24e7..e8279830dd 100644 --- a/game/kernel/kmemcard.cpp +++ b/game/kernel/kmemcard.cpp @@ -1,6 +1,6 @@ /*! * @file kmemcard.cpp - * Memory card interfaces. Very messy code. + * Memory card interface. Very messy code. */ //#include "ps2/SCE_MC.h" diff --git a/game/kernel/kmemcard.h b/game/kernel/kmemcard.h index 2ac954bb82..e22474b24c 100644 --- a/game/kernel/kmemcard.h +++ b/game/kernel/kmemcard.h @@ -1,6 +1,6 @@ /*! * @file kmemcard.h - * Memory card interfaces. Very messy code. + * Memory card interface. Very messy code. */ #ifndef JAK_KMEMCARD_H diff --git a/game/kernel/kprint.h b/game/kernel/kprint.h index b7995d7a4d..049a66d35c 100644 --- a/game/kernel/kprint.h +++ b/game/kernel/kprint.h @@ -13,8 +13,6 @@ constexpr u32 DEBUG_OUTPUT_BUFFER_SIZE = 0x80000; constexpr u32 DEBUG_PRINT_BUFFER_SIZE = 0x200000; constexpr u32 PRINT_BUFFER_SIZE = 0x2000; -#define __attribute__(A) /* do nothing */ - /////////// // SDATA /////////// @@ -67,25 +65,25 @@ void output_segment_load(const char* name, Ptr link_block, u32 flags); /*! * Print to the GOAL print buffer from C */ -void cprintf(const char* format, ...) __attribute__((format(printf, 1, 2))); +void cprintf(const char* format, ...); /*! * Print directly to the C stdout * The "k" parameter is ignored, so this is just like printf */ -void Msg(s32 k, const char* format, ...) __attribute__((format(printf, 2, 3))); +void Msg(s32 k, const char* format, ...); /*! * Print directly to the C stdout * This is identical to Msg. */ -void MsgWarn(const char* format, ...) __attribute__((format(printf, 1, 2))); +void MsgWarn(const char* format, ...); /*! * Print directly to the C stdout * This is identical to Msg. */ -void MsgErr(const char* format, ...) __attribute__((format(printf, 1, 2))); +void MsgErr(const char* format, ...); /*! * Reverse string in place. diff --git a/game/kernel/kscheme.cpp b/game/kernel/kscheme.cpp index af98ad8422..9981f78f4c 100644 --- a/game/kernel/kscheme.cpp +++ b/game/kernel/kscheme.cpp @@ -318,8 +318,6 @@ u64 make_string_from_c(const char* c_str) { * creates a function object on the global heap. * * The implementation is to create a simple trampoline function which jumps to the C function. - * - * */ Ptr make_function_from_c(void* func) { // allocate a function object on the global heap @@ -1804,7 +1802,7 @@ s32 InitHeapAndSymbol() { // setup deci2count for message counter. protoBlock.deci2count = intern_from_c("*deci-count*").cast(); - // load stuff for the listener interfaces + // load stuff for the listener interface InitListener(); // Do final initialization, including loading and initializing the engine. diff --git a/game/kernel/ksocket.cpp b/game/kernel/ksocket.cpp index cf6faf5e7d..b66fc1dd7e 100644 --- a/game/kernel/ksocket.cpp +++ b/game/kernel/ksocket.cpp @@ -52,14 +52,17 @@ u32 ReceiveToBuffer(char* buff) { return msg_size; } +// TODO-WINDOWS +#ifdef __linux__ /*! * Do a DECI2 send and block until it is complete. * The message type is OUTPUT * DONE, EXACT */ -//s32 SendFromBuffer(char* buff, s32 size) { -// return SendFromBufferD(u16(ListenerMessageKind::MSG_OUTPUT), 0, buff, size); - +s32 SendFromBuffer(char* buff, s32 size) { + return SendFromBufferD(u16(ListenerMessageKind::MSG_OUTPUT), 0, buff, size); +} +#endif /*! * Just prepare the Ack buffer, doesn't actually connect. diff --git a/game/overlord/fake_iso.cpp b/game/overlord/fake_iso.cpp index cccc27025a..2330d732e7 100644 --- a/game/overlord/fake_iso.cpp +++ b/game/overlord/fake_iso.cpp @@ -73,6 +73,7 @@ void fake_iso_init_globals() { //! will hold prefix for the source folder. static const char* next_dir = nullptr; +static const char* fake_iso_path = nullptr; /*! * Initialize the file system. @@ -98,7 +99,7 @@ int FS_Init(u8* buffer) { rewind(fp); char* fakeiso = (char*)malloc(len); if (fread(fakeiso, len, 1, fp) != 1) { - assert(true); + assert(false); } // loop over lines @@ -192,7 +193,7 @@ FileRecord* FS_FindIN(const char* iso_name) { static const char* get_file_path(FileRecord* fr) { assert(fr->location < fake_iso_entry_count); static char path_buffer[1024]; - strcpy(path_buffer, "C:\\Users\\Shalen\\Documents\\GitHub\\jak-project\\"); + strcpy(path_buffer, next_dir); strcat(path_buffer, fake_iso_entries[fr->location].file_path); return path_buffer; } @@ -344,7 +345,6 @@ uint32_t FS_LoadMusic(char* name, void* buffer) { (void)name; (void)buffer; assert(false); - return 0; } // TODO FS_LoadSoundBank @@ -352,5 +352,4 @@ uint32_t FS_LoadSoundBank(char* name, void* buffer) { (void)name; (void)buffer; assert(false); - return 0; } \ No newline at end of file diff --git a/game/runtime.cpp b/game/runtime.cpp index fd0557600e..05622de93c 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -3,10 +3,15 @@ * Setup and launcher for the runtime. */ +#ifdef __linux__ +#include +#include +#elif _WIN32 #include #include -#include #include +#endif +#include #include "runtime.h" #include "system/SystemThread.h" @@ -40,8 +45,9 @@ u8* g_ee_main_mem = nullptr; /*! -* runtime.cpp - Deci2Listener has been disabled for now, pending rewriting for Windows. -*/ + * TODO-WINDOWS + * runtime.cpp - Deci2Listener has been disabled for now, pending rewriting for Windows. + */ namespace { @@ -49,49 +55,45 @@ namespace { * SystemThread function for running the DECI2 communication with the GOAL compiler. */ - - void deci2_runner(SystemThreadInterface& interfaces) { - interfaces.initialization_complete(); - while (true) { + // TODO-WINDOWS + #ifdef __linux__ + // callback function so the server knows when to give up and shutdown + std::function shutdown_callback = [&]() { return interface.get_want_exit(); }; + + // create and register server + Deci2Server server(shutdown_callback); + ee::LIBRARY_sceDeci2_register(&server); + + // now its ok to continue with initialization + interface.initialization_complete(); + + // in our own thread, wait for the EE to register the first protocol driver + printf("[DECI2] waiting for EE to register protos\n"); + server.wait_for_protos_ready(); + // then allow the server to accept connections + if (!server.init()) { + throw std::runtime_error("DECI2 server init failed"); } - // // callback function so the server knows when to give up and shutdown -// std::function shutdown_callback = [&]() { return interfaces.get_want_exit(); }; -// -// // create and register server -//// Deci2Server server(shutdown_callback); -//// ee::LIBRARY_sceDeci2_register(&server); -// -// // now its ok to continue with initialization -// interfaces.initialization_complete(); -// -// // in our own thread, wait for the EE to register the first protocol driver -// printf("[DECI2] waiting for EE to register protos\n"); -// server.wait_for_protos_ready(); -// // then allow the server to accept connections -// if (!server.init()) { -// throw std::runtime_error("DECI2 server init failed"); -// } -// -// printf("[DECI2] waiting for listener...\n"); -// bool saw_listener = false; -// while (!interfaces.get_want_exit()) { -// if (server.check_for_listener()) { -// if (!saw_listener) { -// printf("[DECI2] Connected!\n"); -// } -// saw_listener = true; -// // we have a listener, run! -// server.run(); -// } else { -// // no connection yet. Do a sleep so we don't spam checking the listener. -// Sleep(1000); -// } -// } + printf("[DECI2] waiting for listener...\n"); + bool saw_listener = false; + while (!interface.get_want_exit()) { + if (server.check_for_listener()) { + if (!saw_listener) { + printf("[DECI2] Connected!\n"); + } + saw_listener = true; + // we have a listener, run! + server.run(); + } else { + // no connection yet. Do a sleep so we don't spam checking the listener. + usleep(50000); + } + } + #endif } - // EE System constexpr int EE_MAIN_MEM_SIZE = 128 * (1 << 20); // 128 MB, same as PS2 TOOL constexpr u64 EE_MAIN_MEM_MAP = 0x2000000000; // intentionally > 32-bit to catch pointer bugs @@ -108,7 +110,7 @@ constexpr int GOAL_ARGC = 4; /*! * SystemThread Function for the EE (PS2 Main CPU) */ -void ee_runner(SystemThreadInterface& interfaces) { +void ee_runner(SystemThreadInterface& iface) { // Allocate Main RAM. Must have execute enabled. if (EE_MEM_LOW_MAP) { g_ee_main_mem = @@ -122,7 +124,7 @@ void ee_runner(SystemThreadInterface& interfaces) { if (g_ee_main_mem == (u8*)(-1)) { printf(" Failed to initialize main memory! %s\n", strerror(errno)); - interfaces.initialization_complete(); + iface.initialization_complete(); return; } @@ -131,7 +133,7 @@ void ee_runner(SystemThreadInterface& interfaces) { (double)EE_MAIN_MEM_SIZE / (1 << 20)); printf("[EE] Initialization complete!\n"); - interfaces.initialization_complete(); + iface.initialization_complete(); printf("[EE] Run!\n"); memset((void*)g_ee_main_mem, 0, EE_MAIN_MEM_SIZE); @@ -158,13 +160,13 @@ void ee_runner(SystemThreadInterface& interfaces) { munmap(g_ee_main_mem, EE_MAIN_MEM_SIZE); // after main returns, trigger a shutdown. - interfaces.trigger_shutdown(); + iface.trigger_shutdown(); } /*! * SystemThread function for running the IOP (separate I/O Processor) */ -void iop_runner(SystemThreadInterface& interfaces) { +void iop_runner(SystemThreadInterface& iface) { IOP iop; printf("\n\n\n[IOP] Restart!\n"); iop.reset_allocator(); @@ -187,7 +189,7 @@ void iop_runner(SystemThreadInterface& interfaces) { // ssound // stream - interfaces.initialization_complete(); + iface.initialization_complete(); printf("[IOP] Wait for OVERLORD to be started...\n"); iop.wait_for_overlord_start_cmd(); @@ -208,7 +210,7 @@ void iop_runner(SystemThreadInterface& interfaces) { iop.signal_overlord_init_finish(); // IOP Kernel loop - while (!interfaces.get_want_exit() && !iop.want_exit) { + while (!iface.get_want_exit() && !iop.want_exit) { // the IOP kernel just runs at full blast, so we only run the IOP when the EE is waiting on the // IOP. Each time the EE is waiting on the IOP, it will run an iteration of the IOP kernel. iop.wait_run_iop(); @@ -233,7 +235,10 @@ void exec_runtime(int argc, char** argv) { // step 1: sce library prep iop::LIBRARY_INIT(); ee::LIBRARY_INIT_sceCd(); - //ee::LIBRARY_INIT_sceDeci2(); + // TODO-WINDOWS + #ifdef __linux__ + ee::LIBRARY_INIT_sceDeci2(); + #endif ee::LIBRARY_INIT_sceSif(); // step 2: system prep @@ -246,7 +251,7 @@ void exec_runtime(int argc, char** argv) { iop_thread.start(iop_runner); ee_thread.start(ee_runner); deci_thread.start(deci2_runner); - + // step 4: wait for EE to signal a shutdown, which will cause the DECI thread to join. deci_thread.join(); // DECI has been killed, shutdown! @@ -257,4 +262,4 @@ void exec_runtime(int argc, char** argv) { // join and exit tm.join(); printf("GOAL Runtime Shutdown\n"); -} \ No newline at end of file +} diff --git a/game/sce/deci2.cpp b/game/sce/deci2.cpp index 541eb5db3e..6cb5a84058 100644 --- a/game/sce/deci2.cpp +++ b/game/sce/deci2.cpp @@ -12,47 +12,59 @@ namespace ee { namespace { -// constexpr int MAX_DECI2_PROTOCOLS = 4; -// Deci2Driver protocols[MAX_DECI2_PROTOCOLS]; // info for each deci2 protocol registered -// int protocol_count; // number of registered protocols -// Deci2Driver* sending_driver; // currently sending protocol driver -//::Deci2Server* server; // the server to send data to +// TODO-WINDOWS +#ifdef __linux__ +constexpr int MAX_DECI2_PROTOCOLS = 4; +Deci2Driver protocols[MAX_DECI2_PROTOCOLS]; // info for each deci2 protocol registered +int protocol_count; // number of registered protocols +Deci2Driver* sending_driver; // currently sending protocol driver +::Deci2Server* server; // the server to send data to +#endif + } // namespace /* * Initialize the library. */ void LIBRARY_INIT_sceDeci2() { - // // reset protocols - // for (auto& p : protocols) { - // p = Deci2Driver(); - // } - // protocol_count = 0; - // server = nullptr; - // sending_driver = nullptr; +// TODO-WINDOWS +#ifdef __linux__ + // reset protocols + for (auto& p : protocols) { + p = Deci2Driver(); + } + protocol_count = 0; + server = nullptr; + sending_driver = nullptr; +#endif } /*! * Run any pending requested sends. */ void LIBRARY_sceDeci2_run_sends() { - return; - // for (auto& prot : protocols) { - // if (prot.active && prot.pending_send == 'H') { - // sending_driver = &prot; - // (prot.handler)(DECI2_WRITE, 0, prot.opt); - // sending_driver = nullptr; - // prot.pending_send = 0; - // (prot.handler)(DECI2_WRITEDONE, 0, prot.opt); - // } - //} +// TODO-WINDOWS +#ifdef __linux__ + for (auto& prot : protocols) { + if (prot.active && prot.pending_send == 'H') { + sending_driver = &prot; + (prot.handler)(DECI2_WRITE, 0, prot.opt); + sending_driver = nullptr; + prot.pending_send = 0; + (prot.handler)(DECI2_WRITEDONE, 0, prot.opt); + } + } +#endif } /*! * Register a Deci2Server with this library. */ void LIBRARY_sceDeci2_register(::Deci2Server* s) { - // server = s; +// TODO-WINDOWS +#ifdef __linux__ + server = s; +#endif } /*! @@ -61,34 +73,40 @@ void LIBRARY_sceDeci2_register(::Deci2Server* s) { * I don't know why it's like this. */ s32 sceDeci2Open(u16 protocol, void* opt, void (*handler)(s32 event, s32 param, void* opt)) { - // server->lock(); - // Deci2Driver drv; - // drv.protocol = protocol; - // drv.opt = opt; - // drv.handler = handler; - // drv.id = protocol_count + 1; - // drv.active = true; - // protocols[protocol_count++] = drv; - // printf("[DECI2] Add new protocol driver %d for 0x%x\n", drv.id, drv.protocol); - // server->unlock(); +// TODO-WINDOWS +#ifdef __linux__ + server->lock(); + Deci2Driver drv; + drv.protocol = protocol; + drv.opt = opt; + drv.handler = handler; + drv.id = protocol_count + 1; + drv.active = true; + protocols[protocol_count++] = drv; + printf("[DECI2] Add new protocol driver %d for 0x%x\n", drv.id, drv.protocol); + server->unlock(); - // if (protocol_count == 1) { - // // if we have our first protocol, inform the server we are ready to receive! - // // then the server will accept incoming data. - // server->send_proto_ready(protocols, &protocol_count); - //} + if (protocol_count == 1) { + // if we have our first protocol, inform the server we are ready to receive! + // then the server will accept incoming data. + server->send_proto_ready(protocols, &protocol_count); + } - // return drv.id; + return drv.id; +#elif _WIN32 return 0; +#endif } /*! * Deactivate a DECI2 protocol by socket descriptor. */ s32 sceDeci2Close(s32 s) { - // assert(s - 1 < protocol_count); - // protocols[s - 1].active = false; - // return 1; +// TODO-WINDOWS +#ifdef __linux__ + assert(s - 1 < protocol_count); + protocols[s - 1].active = false; +#endif return 1; } @@ -96,10 +114,12 @@ s32 sceDeci2Close(s32 s) { * Start a send. */ s32 sceDeci2ReqSend(s32 s, char dest) { - // assert(s - 1 < protocol_count); - // auto& proto = protocols[s - 1]; - // proto.pending_send = dest; - // return 0; +// TODO-WINDOWS +#ifdef __linux__ + assert(s - 1 < protocol_count); + auto& proto = protocols[s - 1]; + proto.pending_send = dest; +#endif return 0; } @@ -108,35 +128,42 @@ s32 sceDeci2ReqSend(s32 s, char dest) { * Returns after data is copied. */ s32 sceDeci2ExRecv(s32 s, void* buf, u16 len) { - // assert(s - 1 < protocol_count); - // protocols[s - 1].recv_size = len; - // auto avail = protocols[s - 1].available_to_receive; - // if (len <= avail) { - // memcpy(buf, protocols[s - 1].recv_buffer, len); - // return len; - //} else { - // printf("[DECI2] Error: ExRecv %d, only %d available!\n", len, avail); - // return -1; - //} +// TODO-WINDOWS +#ifdef __linux__ + assert(s - 1 < protocol_count); + protocols[s - 1].recv_size = len; + auto avail = protocols[s - 1].available_to_receive; + if (len <= avail) { + memcpy(buf, protocols[s - 1].recv_buffer, len); + return len; + } else { + printf("[DECI2] Error: ExRecv %d, only %d available!\n", len, avail); + return -1; + } +#elif _WIN32 return 0; +#endif } /*! * Do a send. */ s32 sceDeci2ExSend(s32 s, void* buf, u16 len) { - // assert(s - 1 < protocol_count); - // if (!sending_driver) { - // printf("sceDeci2ExSend called at illegal time!\n"); - // } - // - // if (&protocols[s - 1] != sending_driver) { - // printf("sceDeci2ExSend called with the wrong socket!\n"); - // } - // - // server->send_data(buf, len); - // return len; - return 0; -} +// TODO-WINDOWS +#ifdef __linux__ + assert(s - 1 < protocol_count); + if (!sending_driver) { + printf("sceDeci2ExSend called at illegal time!\n"); + } + if (&protocols[s - 1] != sending_driver) { + printf("sceDeci2ExSend called with the wrong socket!\n"); + } + + server->send_data(buf, len); + return len; +#elif _WIN32 + return 0; +#endif +} } // namespace ee diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index f6606d7196..56122c5ae7 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -2,8 +2,14 @@ * @file Deci2Server.cpp * Basic implementation of a DECI2 server. * Works with deci2.cpp (sceDeci2) to implement the networking on target - + */ +// TODO-WINDOWS +#ifdef __linux__ + +#include +#include +#include #include #include #include @@ -42,7 +48,7 @@ Deci2Server::~Deci2Server() { /*! * Start waiting for the Listener to connect - + */ bool Deci2Server::init() { server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { @@ -51,7 +57,7 @@ bool Deci2Server::init() { } const char opt = 1; - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_BROADCAST, &opt, sizeof(opt))) { + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { printf("[Deci2Server] Failed to setsockopt 1\n"); close(server_fd); server_fd = -1; @@ -59,7 +65,7 @@ bool Deci2Server::init() { } const char one = 1; - if (setsockopt(server_fd, SOL_SOCKET, TCP_NODELAY, &one, sizeof(one))) { + if (setsockopt(server_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { printf("[Deci2Server] Failed to setsockopt 2\n"); close(server_fd); server_fd = -1; @@ -104,7 +110,7 @@ bool Deci2Server::init() { /*! * Return true if the listener is connected. - + */ bool Deci2Server::check_for_listener() { if (server_connected) { if (accept_thread_running) { @@ -119,7 +125,7 @@ bool Deci2Server::check_for_listener() { /*! * Send data from buffer. User must provide appropriate headers. - + */ void Deci2Server::send_data(void* buf, u16 len) { lock(); if (!server_connected) { @@ -140,14 +146,14 @@ void Deci2Server::send_data(void* buf, u16 len) { /*! * Lock the DECI mutex. Should be done before modifying protocols. - + */ void Deci2Server::lock() { deci_mutex.lock(); } /*! * Unlock the DECI mutex. Should be done after modifying protocols. - + */ void Deci2Server::unlock() { deci_mutex.unlock(); } @@ -155,7 +161,7 @@ void Deci2Server::unlock() { /*! * Wait for protocols to become ready. * This avoids the case where we receive messages before protocol handlers are set up. - + */ void Deci2Server::wait_for_protos_ready() { if (protocols_ready) return; @@ -168,7 +174,7 @@ void Deci2Server::wait_for_protos_ready() { * Will unblock wait_for_protos_ready and incoming messages will be dispatched to these * protocols. You can change the protocol handlers, but you should lock the mutex before * doing so. - + */ void Deci2Server::send_proto_ready(Deci2Driver* drivers, int* driver_count) { lock(); d2_drivers = drivers; @@ -250,18 +256,17 @@ void Deci2Server::run() { /*! * Background thread for waiting for the listener. - + */ void Deci2Server::accept_thread_func() { socklen_t l = sizeof(addr); while (!kill_accept_thread) { new_sock = accept(server_fd, (sockaddr*)&addr, &l); if (new_sock >= 0) { - const char versions = {versions::GOAL_VERSION_MAJOR}; + u32 versions[2] = {versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR}; send(new_sock, &versions, 8, 0); // todo, check result? server_connected = true; return; } } } - -*/ \ No newline at end of file +#endif \ No newline at end of file diff --git a/game/system/Deci2Server.h b/game/system/Deci2Server.h index e57b267466..388ee5ec7a 100644 --- a/game/system/Deci2Server.h +++ b/game/system/Deci2Server.h @@ -2,8 +2,9 @@ * @file Deci2Server.h * Basic implementation of a DECI2 server. * Works with deci2.cpp (sceDeci2) to implement the networking on target - + */ +#ifdef __linux__ #ifndef JAK1_DECI2SERVER_H #define JAK1_DECI2SERVER_H @@ -51,5 +52,4 @@ class Deci2Server { }; #endif // JAK1_DECI2SERVER_H - -*/ \ No newline at end of file +#endif diff --git a/game/system/SystemThread.cpp b/game/system/SystemThread.cpp index a601902bde..5159dd0920 100644 --- a/game/system/SystemThread.cpp +++ b/game/system/SystemThread.cpp @@ -71,8 +71,8 @@ void SystemThreadManager::join() { */ void* bootstrap_thread_func(void* x) { SystemThread* thd = (SystemThread*)x; - SystemThreadInterface interfaces(thd); - thd->function(interfaces); + SystemThreadInterface interface(thd); + thd->function(interface); printf("[SYSTEM] Thread %s is returning\n", thd->name.c_str()); return nullptr; } @@ -135,3 +135,36 @@ bool SystemThreadInterface::get_want_exit() const { void SystemThreadInterface::trigger_shutdown() { thread.manager->shutdown(); } + +// TODO-Windows +#ifdef __linux__ +#include +#include + +/*! + * Get thread performance statistics and report them. + */ +void SystemThreadInterface::report_perf_stats() { + if (thread.stat_diff_timer.getMs() > 16.f) { + thread.stat_diff_timer.start(); + + uint64_t current_ns = thread.stats_timer.getNs(); + rusage stats; + getrusage(RUSAGE_THREAD, &stats); + + uint64_t current_kernel = stats.ru_stime.tv_usec + (1000000 * stats.ru_stime.tv_sec); + uint64_t current_user = stats.ru_utime.tv_usec + (1000000 * stats.ru_utime.tv_sec); + + uint64_t ns_dt = current_ns - thread.last_collection_nanoseconds; + uint64_t dt_kernel = current_kernel - thread.last_cpu_kernel; + uint64_t dt_user = current_user - thread.last_cpu_user; + + thread.cpu_kernel = dt_kernel * 1000. / (double)ns_dt; + thread.cpu_user = dt_user * 1000. / (double)ns_dt; + + thread.last_cpu_kernel = current_kernel; + thread.last_cpu_user = current_user; + thread.last_collection_nanoseconds = current_ns; + } +} +#endif \ No newline at end of file diff --git a/game/system/SystemThread.h b/game/system/SystemThread.h index 522b0f9925..c9dc513312 100644 --- a/game/system/SystemThread.h +++ b/game/system/SystemThread.h @@ -20,7 +20,7 @@ class SystemThreadManager; /*! * Runs a function in a thread and provides a SystemThreadInterface to that function. - * Once the thread is ready, it should tell the interfaces with intitialization_complete(). + * Once the thread is ready, it should tell the interface with intitialization_complete(). * Thread functions should try to return when get_want_exit() returns true. * Thread functions should also call report_perf_stats every now and then to update performance * statistics. @@ -55,7 +55,7 @@ class SystemThread { }; /*! - * The interfaces used by a thread in the runtime. + * The interface used by a thread in the runtime. */ class SystemThreadInterface { public: diff --git a/game/system/iop_thread.cpp b/game/system/iop_thread.cpp index bf6cf4e396..67998ab879 100644 --- a/game/system/iop_thread.cpp +++ b/game/system/iop_thread.cpp @@ -1,6 +1,10 @@ #include "iop_thread.h" +#ifdef __linux__ +#include +#elif _WIN32 #include +#endif #include "SystemThread.h" //#include "shared_config.h" //#include "ps2/SCE_IOP.h" @@ -117,7 +121,7 @@ IOP::~IOP() { // //// SCE_IOP::PS2_RegisterIOP(&iop); //// PS2_RegisterIOP_EE(&iop); -// interfaces.initialization_complete(); +// interface.initialization_complete(); // // printf("[IOP] Wait for OVERLORD to be started...\n"); // iop.wait_for_overlord_start_cmd(); diff --git a/goalc/emitter/CodeTester.cpp b/goalc/emitter/CodeTester.cpp index 4a07915d57..920c86605e 100644 --- a/goalc/emitter/CodeTester.cpp +++ b/goalc/emitter/CodeTester.cpp @@ -6,10 +6,13 @@ * The CodeTester can't be used for tests requiring the full GOAL language/linking. */ -#include -#include - +#ifdef __linux__ #include +#elif _WIN32 +#include +#endif + +#include #include "CodeTester.h" #include "IGen.h" diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index 143f95e082..b19ddf011c 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -1,9 +1,15 @@ /*! * @file Listener.cpp * The Listener can connect to a Deci2Server for debugging. - + */ + +// TODO-Windows +#ifdef __linux__ #include +#include +#include +#include #include #include #include @@ -39,8 +45,6 @@ bool Listener::is_connected() const { return m_connected; } - -/* bool Listener::connect_to_target(const std::string& ip, int port) { if (m_connected) { throw std::runtime_error("attempted a Listener::connect_to_target when already connected!"); @@ -71,7 +75,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { // set nodelay, which makes small rapid messages faster, but large messages slower const char one = 1; - if (setsockopt(socket_fd, SOL_SOCKET, TCP_NODELAY, &one, sizeof(one))) { + if (setsockopt(socket_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { printf("[Listener] failed to TCP_NODELAY\n"); close(socket_fd); socket_fd = -1; @@ -141,15 +145,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { /*! * Runs in a separate thread to receive messages. * Will print messages to stdout, or optionally save them. - - - - -/*! - * Attempt to connect to the target. If the target isn't running, this should fail quickly. - * Returns true if successfully connected. - - + */ void Listener::receive_func() { while (m_connected) { // attempt to receive a ListenerMessageHeader @@ -244,5 +240,4 @@ void Listener::receive_func() { } } // namespace listener - -*/ +#endif diff --git a/mman.c b/mman.c deleted file mode 100644 index 486ed94d88..0000000000 --- a/mman.c +++ /dev/null @@ -1,180 +0,0 @@ - -#include -#include -#include - -#include "mman.h" - -#ifndef FILE_MAP_EXECUTE -#define FILE_MAP_EXECUTE 0x0020 -#endif /* FILE_MAP_EXECUTE */ - -static int __map_mman_error(const DWORD err, const int deferr) -{ - if (err == 0) - return 0; - //TODO: implement - return err; -} - -static DWORD __map_mmap_prot_page(const int prot) -{ - DWORD protect = 0; - - if (prot == PROT_NONE) - return protect; - - if ((prot & PROT_EXEC) != 0) - { - protect = ((prot & PROT_WRITE) != 0) ? - PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; - } - else - { - protect = ((prot & PROT_WRITE) != 0) ? - PAGE_READWRITE : PAGE_READONLY; - } - - return protect; -} - -static DWORD __map_mmap_prot_file(const int prot) -{ - DWORD desiredAccess = 0; - - if (prot == PROT_NONE) - return desiredAccess; - - if ((prot & PROT_READ) != 0) - desiredAccess |= FILE_MAP_READ; - if ((prot & PROT_WRITE) != 0) - desiredAccess |= FILE_MAP_WRITE; - if ((prot & PROT_EXEC) != 0) - desiredAccess |= FILE_MAP_EXECUTE; - - return desiredAccess; -} - -void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) -{ - HANDLE fm, h; - - void * map = MAP_FAILED; - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4293) -#endif - - const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ? - (DWORD)off : (DWORD)(off & 0xFFFFFFFFL); - const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ? - (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL); - const DWORD protect = __map_mmap_prot_page(prot); - const DWORD desiredAccess = __map_mmap_prot_file(prot); - - const off_t maxSize = off + (off_t)len; - - const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ? - (DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL); - const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ? - (DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL); - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - errno = 0; - - if (len == 0 - /* Unsupported flag combinations */ - || (flags & MAP_FIXED) != 0 - /* Usupported protection combinations */ - || prot == PROT_EXEC) - { - errno = EINVAL; - return MAP_FAILED; - } - - h = ((flags & MAP_ANONYMOUS) == 0) ? - (HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE; - - if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE) - { - errno = EBADF; - return MAP_FAILED; - } - - fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL); - - if (fm == NULL) - { - errno = __map_mman_error(GetLastError(), EPERM); - return MAP_FAILED; - } - - map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len); - - CloseHandle(fm); - - if (map == NULL) - { - errno = __map_mman_error(GetLastError(), EPERM); - return MAP_FAILED; - } - - return map; -} - -int munmap(void *addr, size_t len) -{ - if (UnmapViewOfFile(addr)) - return 0; - - errno = __map_mman_error(GetLastError(), EPERM); - - return -1; -} - -int mprotect(void *addr, size_t len, int prot) -{ - DWORD newProtect = __map_mmap_prot_page(prot); - DWORD oldProtect = 0; - - if (VirtualProtect(addr, len, newProtect, &oldProtect)) - return 0; - - errno = __map_mman_error(GetLastError(), EPERM); - - return -1; -} - -int msync(void *addr, size_t len, int flags) -{ - if (FlushViewOfFile(addr, len)) - return 0; - - errno = __map_mman_error(GetLastError(), EPERM); - - return -1; -} - -int mlock(const void *addr, size_t len) -{ - if (VirtualLock((LPVOID)addr, len)) - return 0; - - errno = __map_mman_error(GetLastError(), EPERM); - - return -1; -} - -int munlock(const void *addr, size_t len) -{ - if (VirtualUnlock((LPVOID)addr, len)) - return 0; - - errno = __map_mman_error(GetLastError(), EPERM); - - return -1; -} diff --git a/test/test_goos.cpp b/test/test_goos.cpp index 18117b1a76..6b67bf3354 100644 --- a/test/test_goos.cpp +++ b/test/test_goos.cpp @@ -942,30 +942,33 @@ TEST(GoosObject, char_to_string) { EXPECT_EQ("#\\{17}", goos::fixed_to_string(char(17))); } -///*! -// * Test the EmptyListObject -// */ -//TEST(GoosObject, EmptyList) { -// // create two empty lists -// Object nil = EmptyListObject::make_new(); -// Object nil2 = EmptyListObject::make_new(); -// -// // check type is set -// EXPECT_TRUE(nil.is_empty_list()); -// -// // check equality operator -// EXPECT_TRUE(nil == nil2); -// -// // check we get the same heap allocated object -// auto elo = std::dynamic_pointer_cast(nil.heap_obj); -// auto elo2 = std::dynamic_pointer_cast(nil2.heap_obj); -// EXPECT_TRUE(elo); -// EXPECT_TRUE(elo == elo2); -// -// // check print and inspect -// EXPECT_EQ(nil.print(), "()"); -// EXPECT_EQ(nil.inspect(), "[empty list] ()\n"); -//} +/*! + * Test the EmptyListObject + */ +TEST(GoosObject, EmptyList) { +// TODO-Windows +#ifdef __linux__ + // create two empty lists + Object nil = EmptyListObject::make_new(); + Object nil2 = EmptyListObject::make_new(); + + // check type is set + EXPECT_TRUE(nil.is_empty_list()); + + // check equality operator + EXPECT_TRUE(nil == nil2); + + // check we get the same heap allocated object + auto elo = std::dynamic_pointer_cast(nil.heap_obj); + auto elo2 = std::dynamic_pointer_cast(nil2.heap_obj); + EXPECT_TRUE(elo); + EXPECT_TRUE(elo == elo2); + + // check print and inspect + EXPECT_EQ(nil.print(), "()"); + EXPECT_EQ(nil.inspect(), "[empty list] ()\n"); +#endif +} /*! * Test IntegerObject @@ -1286,4 +1289,4 @@ TEST(GoosSpecialForms, And) { for (auto x : {"(and)"}) { EXPECT_ANY_THROW(e(i, x)); } -} \ No newline at end of file +} diff --git a/third-party/json.hpp b/third-party/json.hpp index b37b2a5f1f..9c66a8457f 100644 --- a/third-party/json.hpp +++ b/third-party/json.hpp @@ -12636,7 +12636,7 @@ template struct output_adapter_protocol virtual ~output_adapter_protocol() = default; }; -/// a type to simplify interface +/// a type to simplify interfaces template using output_adapter_t = std::shared_ptr>;