[Runtime] misc fixes to runtime and listener (#170)

* misc runtime fixes

* clang format
This commit is contained in:
water111
2020-12-28 18:37:05 -05:00
committed by GitHub
parent c811778d00
commit 4d713d5c8c
25 changed files with 192 additions and 126 deletions
+3 -1
View File
@@ -41,7 +41,9 @@ enum ListenerToTargetMsgKind : u16 {
LTT_MSG_PRINT = 6, //! Print an object
LTT_MSG_PRINT_SYMBOLS = 7, //! Print all symbols
LTT_MSG_RESET = 8, //! Reset the game
LTT_MSG_CODE = 9 //! Send code to patch into the game
LTT_MSG_CODE = 9, //! Send code to patch into the game
// below here are added
LTT_MSG_SHUTDOWN = 10 //! Shut down the runtime.
};
/*!
+7 -13
View File
@@ -8,7 +8,7 @@
#ifndef JAK_PTR_H
#define JAK_PTR_H
#include <stdexcept>
#include <cassert>
#include "game/runtime.h"
#include "common/common_types.h"
@@ -36,25 +36,19 @@ struct Ptr {
explicit Ptr(u32 v) { offset = v; }
/*!
* Dereference a pointer. Will throw if you do this on a null pointer.
* Dereference a pointer. Will error if you do this on a null pointer.
*/
T* operator->() {
if (offset) {
return (T*)(g_ee_main_mem + offset);
} else {
throw std::runtime_error("Ptr null dereference!");
}
assert(offset);
return (T*)(g_ee_main_mem + offset);
}
/*!
* Dereference a pointer. Will throw if you do this on a null pointer.
* Dereference a pointer. Will error if you do this on a null pointer.
*/
T& operator*() {
if (offset) {
return *(T*)(g_ee_main_mem + offset);
} else {
throw std::runtime_error("Ptr null dereference!");
}
assert(offset);
return *(T*)(g_ee_main_mem + offset);
}
// pointer math
-4
View File
@@ -8,7 +8,6 @@
#include <chrono>
#include <thread>
#include "common/cross_os_debug/xdbg.h"
#include "common/common_types.h"
#include "game/sce/libscf.h"
#include "kboot.h"
@@ -77,9 +76,6 @@ void kboot_init_globals() {
* Add call to sceDeci2Reset when GOAL shuts down.
*/
s32 goal_main(int argc, const char* const* argv) {
// Added for OpenGOAL's debugger
xdbg::allow_debugging();
// Initialize global variables based on command line parameters
// This call is not present in the retail version of the game
// but the function is, and it likely goes here.
+2 -2
View File
@@ -161,7 +161,7 @@ void GoalProtoHandler(int event, int param, void* opt) {
* 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) {
s32 SendFromBufferD(s32 msg_kind, u64 msg_id, char* data, s32 size) {
// wait for send to finish or error first...
while (protoBlock.send_status > 0) {
// on actual PS2, the kernel will run this in another thread.
@@ -190,7 +190,7 @@ s32 SendFromBufferD(s32 msg_kind, u64 p2, char* data, s32 size) {
header->msg_kind = (ListenerMessageKind)msg_kind;
header->u6 = 0;
header->msg_size = size;
header->msg_id = p2;
header->msg_id = msg_id;
// start send!
auto rv = sceDeci2ReqSend(protoBlock.socket, header->deci2_header.dst);
+1 -1
View File
@@ -68,7 +68,7 @@ void GoalProtoHandler(int event, int param, void* data);
* DONE, original version used an uncached address and had a FlushCache call, which were both
* removed
*/
s32 SendFromBufferD(s32 p1, u64 p2, char* data, s32 size);
s32 SendFromBufferD(s32 p1, u64 msg_id, char* data, s32 size);
/*!
* Print GOAL Protocol status
+43 -31
View File
@@ -8,6 +8,7 @@
#include <cstring>
#include <cassert>
#include <cstdio>
#include <common/versions.h>
#include "klink.h"
#include "fileio.h"
@@ -81,7 +82,7 @@ void link_control::begin(Ptr<uint8_t> object_file,
"VERSION ERROR: C Kernel built from GOAL %d.%d, but object file %s is from GOAL %d.%d\n",
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR, name, ofh->goal_version_major,
ofh->goal_version_minor);
exit(0);
assert(false);
}
if (link_debug_printfs) {
printf("Object file header:\n");
@@ -352,11 +353,20 @@ uint32_t cross_seg_dist_link_v3(Ptr<uint8_t> link,
// target seg, dist into mine, dist into target, patch loc in mine
uint8_t target_seg = *link;
assert(target_seg < ofh->segment_count);
uint32_t* link_data = (link + 1).cast<uint32_t>().c();
int32_t mine = link_data[0] + ofh->code_infos[current_seg].offset;
int32_t tgt = link_data[1] + ofh->code_infos[target_seg].offset;
int32_t diff = tgt - mine;
uint32_t offset_of_patch = link_data[2] + ofh->code_infos[current_seg].offset;
if (!ofh->code_infos[target_seg].offset) {
// we want to address GOAL 0. In the case where this is a rip-relative load or store, this
// will crash, which is what we want. If it's an lea and just getting an address, this will get
// us a nullptr. If you do a method-set! with a null pointer it does nothing, so it's safe to
// method-set! to things that are in unloaded segments and it'll just keep the old method.
diff = -mine;
}
// printf("link object in seg %d diff %d at %d (%d + %d)\n", target_seg, diff, offset_of_patch,
// link_data[2], ofh->code_infos[current_seg].offset);
@@ -367,7 +377,7 @@ uint32_t cross_seg_dist_link_v3(Ptr<uint8_t> link,
} else if (size == 8) {
*Ptr<int64_t>(offset_of_patch).c() = diff;
} else {
throw std::runtime_error("unknown size in cross_seg_dist_link_v3");
assert(false);
}
return 1 + 3 * 4;
@@ -463,36 +473,38 @@ uint32_t link_control::work_v3() {
// state 1: linking. For now all links are done at once. This is probably going to be fine on a
// modern computer. But the game broke this into multiple steps.
if (m_segment_process < ofh->segment_count) {
Ptr<u8> lp(ofh->link_infos[m_segment_process].offset);
if (ofh->code_infos[m_segment_process].offset) {
Ptr<u8> lp(ofh->link_infos[m_segment_process].offset);
while (*lp) {
switch (*lp) {
case LINK_TABLE_END:
break;
case LINK_SYMBOL_OFFSET:
lp = lp + 1;
lp = lp + symlink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
break;
case LINK_TYPE_PTR:
lp = lp + 1; // seek past id
lp = lp + typelink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
break;
case LINK_DISTANCE_TO_OTHER_SEG_64:
lp = lp + 1;
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 8);
break;
case LINK_DISTANCE_TO_OTHER_SEG_32:
lp = lp + 1;
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 4);
break;
case LINK_PTR:
lp = lp + 1;
lp = lp + ptr_link_v3(lp, ofh, m_segment_process);
break;
default:
printf("unknown link table thing %d\n", *lp);
exit(0);
break;
while (*lp) {
switch (*lp) {
case LINK_TABLE_END:
break;
case LINK_SYMBOL_OFFSET:
lp = lp + 1;
lp = lp + symlink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
break;
case LINK_TYPE_PTR:
lp = lp + 1; // seek past id
lp = lp + typelink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
break;
case LINK_DISTANCE_TO_OTHER_SEG_64:
lp = lp + 1;
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 8);
break;
case LINK_DISTANCE_TO_OTHER_SEG_32:
lp = lp + 1;
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 4);
break;
case LINK_PTR:
lp = lp + 1;
lp = lp + ptr_link_v3(lp, ofh, m_segment_process);
break;
default:
printf("unknown link table thing %d\n", *lp);
assert(false);
break;
}
}
}
+5 -3
View File
@@ -5,6 +5,8 @@
*/
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "klisten.h"
#include "kboot.h"
#include "kprint.h"
@@ -133,9 +135,9 @@ void ProcessListenerMessage(Ptr<char> msg) {
break;
case LTT_MSG_RESET:
MasterExit = 1;
if (protoBlock.msg_id == UINT64_MAX) {
MasterExit = 2;
}
break;
case LTT_MSG_SHUTDOWN:
MasterExit = 2;
break;
case LTT_MSG_CODE: {
auto buffer = kmalloc(kdebugheap, MessCount, 0, "listener-link-block");
+1 -1
View File
@@ -366,7 +366,7 @@ int ShutdownMachine() {
CloseListener();
ShutdownSound();
ShutdownGoalProto();
Msg(6, "kernel: machine shutdown");
Msg(6, "kernel: machine shutdown\n");
return 0;
}
+1
View File
@@ -6,6 +6,7 @@
*/
#include <cstring>
#include <cstdio>
#include "common/goal_constants.h"
#include "kmalloc.h"
#include "kprint.h"
+15 -18
View File
@@ -7,6 +7,7 @@
#include <cmath>
#include <cstdarg>
#include <cstdio>
#include <cassert>
#include "common/goal_constants.h"
#include "common/common_types.h"
@@ -348,10 +349,9 @@ s32 cvt_float(float x, s32 precision, s32* lead_char, char* buff_start, char* bu
value = (char)rounder;
} else if (!(ru32 >> 31)) { // sign bit
value = 0;
throw std::runtime_error("got very large exponent in rounding calculation");
assert(false); // not sure what happens here.
} else {
value = -1; // happens on NaN's
// throw std::runtime_error("got negative sign bit in rounding calculation");
}
// place number at the end of the buffer and move pointer back
@@ -396,10 +396,9 @@ s32 cvt_float(float x, s32 precision, s32* lead_char, char* buff_start, char* bu
value = (char)next_int;
} else if (!(ru32 >> 0x1f)) {
value = 0;
throw std::runtime_error("got very large exponent in rounding calculation");
assert(false); // not sure what happens here.
} else {
value = -1; // happens on NaN's
// throw std::runtime_error("got negative sign bit in rounding calculation");
}
*count_chrp = value + '0';
count_chrp++;
@@ -411,7 +410,7 @@ s32 cvt_float(float x, s32 precision, s32* lead_char, char* buff_start, char* bu
// however, the rounding flag is always disabled and the rounding code doesn't work.
if ((fraction_part != 0.f) && ((flags & 1) != 0)) {
start_ptr = round(fraction_part, nullptr, start_ptr, count_chrp - 1, 0, lead_char);
throw std::runtime_error("cvt_float called round!");
assert(false);
}
}
@@ -563,7 +562,7 @@ char* kitoa(char* buffer, s64 value, u64 base, s32 length, char pad, u32 flag) {
* uses C varags, but 128-bit varags don't work, so "format" always passes 0 for quadword printing.
*/
void kqtoa() {
throw std::runtime_error("kqtoa not implemented");
assert(false);
}
struct format_struct {
@@ -801,7 +800,7 @@ s32 format_impl(uint64_t* args) {
}
kstrinsert(output_ptr, pad, desired_length - print_len);
} else {
throw std::runtime_error("unsupported justify in format");
assert(false);
// output_ptr = strend(output_ptr);
// while(0 < (desired_length - print_len)) {
// char pad = ' ';
@@ -852,7 +851,7 @@ s32 format_impl(uint64_t* args) {
kstrinsert(output_ptr, pad, desired_length - print_len);
} else {
throw std::runtime_error("unsupported justify in format");
assert(false);
// output_ptr = strend(output_ptr);
// u32 l140 = 0;
// while(l140 < (desired_length - print_len)) {
@@ -893,9 +892,7 @@ s32 format_impl(uint64_t* args) {
call_method_of_type(in, type, GOAL_PRINT_METHOD);
}
} else {
// TODO - if we can't throw exceptions, what is the option?
// log, break and continue?
throw std::runtime_error("failed to find symbol in format!");
assert(false); // bad type.
}
}
output_ptr = strend(output_ptr);
@@ -916,7 +913,7 @@ s32 format_impl(uint64_t* args) {
call_method_of_type(in, type, GOAL_INSPECT_METHOD);
}
} else {
throw std::runtime_error("failed to find symbol in format!");
assert(false); // bad type
}
}
output_ptr = strend(output_ptr);
@@ -924,7 +921,7 @@ s32 format_impl(uint64_t* args) {
case 'Q': // not yet implemented. hopefully andy gavin finishes this one soon.
case 'q':
throw std::runtime_error("nyi q format string");
assert(false);
break;
case 'X': // hex, 64 bit, pad padchar
@@ -1021,7 +1018,7 @@ s32 format_impl(uint64_t* args) {
precision = 4;
float value;
if (in < 0) {
throw std::runtime_error("time seconds format error negative.\n");
assert(false); // i don't get this one
} else {
value = in;
}
@@ -1037,7 +1034,7 @@ s32 format_impl(uint64_t* args) {
default:
MsgErr("format: unknown code 0x%02x\n", format_ptr[1]);
throw std::runtime_error("format error");
assert(false);
break;
}
format_ptr++;
@@ -1079,13 +1076,13 @@ s32 format_impl(uint64_t* args) {
*PrintPendingLocal3 = 0;
return 0;
} else if (type == *Ptr<Ptr<Type>>(s7.offset + FIX_SYM_FILE_STREAM_TYPE)) {
throw std::runtime_error("FORMAT into a file stream not supported");
assert(false); // file stream nyi
}
}
throw std::runtime_error("unknown format destination");
assert(false); // unknown destination
return 0;
}
throw std::runtime_error("how did we get here?");
assert(false); // ??????
return 7;
}
+6 -7
View File
@@ -126,9 +126,7 @@ u64 goal_malloc(u32 heap, u32 size, u32 flags, u32 name) {
* completely defined.
*/
u64 alloc_from_heap(u32 heapSymbol, u32 type, s32 size) {
if (size <= 0) {
throw std::runtime_error("got <= 0 size allocation in alloc_from_heap!");
}
assert(size > 0);
// align to 16 bytes (part one)
s32 alignedSize = size + 0xf;
@@ -165,7 +163,7 @@ u64 alloc_from_heap(u32 heapSymbol, u32 type, s32 size) {
return kmalloc(*Ptr<Ptr<kheapinfo>>(heapSymbol), size, KMALLOC_MEMSET, gstr->data()).offset;
} else if (heapOffset == FIX_SYM_PROCESS_TYPE) {
throw std::runtime_error("this type of process allocation is not supported yet!\n");
assert(false); // nyi
// allocate on current process heap
// Ptr start = *ptr<Ptr>(getS6() + 0x4c + 8);
// Ptr heapEnd = *ptr<Ptr>(getS6() + 0x4c + 4);
@@ -181,7 +179,7 @@ u64 alloc_from_heap(u32 heapSymbol, u32 type, s32 size) {
// alignedSize); return 0;
// }
} else if (heapOffset == FIX_SYM_SCRATCH) {
throw std::runtime_error("this type of scratchpad allocation is not used!\n");
assert(false); // nyi, I think unused.
} else {
memset(Ptr<u8>(heapSymbol).c(), 0, (size_t)alignedSize); // treat it as a stack address
return heapSymbol;
@@ -1122,8 +1120,8 @@ u64 call_method_of_type(u32 arg, Ptr<Type> type, u32 method_id) {
(*type_tag).offset);
}
}
// throw std::runtime_error("call_method_of_type failed!\n");
printf("[ERROR] call_method_of_type failed!\n");
assert(false);
return arg;
}
@@ -1159,7 +1157,8 @@ u64 call_method_of_type_arg2(u32 arg, Ptr<Type> type, u32 method_id, u32 a1, u32
(*type_tag).offset);
}
}
throw std::runtime_error("call_method_of_type failed!\n");
printf("[ERROR] call_method_of_type_arg2 failed!\n");
assert(false);
return arg;
}
-1
View File
@@ -16,7 +16,6 @@ void setup_logging(bool verbose) {
auto game_logger = spdlog::stdout_color_mt("GOAL Runtime");
spdlog::set_default_logger(game_logger);
spdlog::flush_on(spdlog::level::info);
spdlog::set_pattern("%v");
spdlog::info("Verbose logging enabled");
} else {
auto game_logger = spdlog::basic_logger_mt("GOAL Runtime", "logs/runtime.log");
+3
View File
@@ -273,6 +273,9 @@ uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len) {
const char* path = get_file_path(fd->fr);
FILE* fp = fopen(path, "rb");
if (!fp) {
spdlog::error("[OVERLORD] fake iso could not open the file \"{}\"", path);
}
assert(fp);
fseek(fp, 0, SEEK_END);
uint32_t file_len = ftell(fp);
+5 -1
View File
@@ -47,6 +47,7 @@
#include "game/overlord/stream.h"
#include "common/goal_constants.h"
#include "common/cross_os_debug/xdbg.h"
u8* g_ee_main_mem = nullptr;
@@ -75,7 +76,7 @@ void deci2_runner(SystemThreadInterface& iface) {
server.wait_for_protos_ready();
// then allow the server to accept connections
if (!server.init()) {
throw std::runtime_error("DECI2 server init failed");
assert(false);
}
spdlog::debug("[DECI2] Waiting for listener...");
@@ -148,6 +149,9 @@ void ee_runner(SystemThreadInterface& iface) {
kmemcard_init_globals();
kprint_init_globals();
// Added for OpenGOAL's debugger
xdbg::allow_debugging();
goal_main(g_argc, g_argv);
spdlog::debug("[EE] Done!");
+4 -2
View File
@@ -203,12 +203,14 @@ s32 CreateSema(SemaParam* param) {
s32 WaitSema(s32 sema) {
(void)sema;
throw std::runtime_error("NYI");
assert(false); // nyi
return 0;
}
s32 SignalSema(s32 sema) {
(void)sema;
throw std::runtime_error("NYI");
assert(false); // nyi
return 0;
}
s32 WakeupThread(s32 thid) {
-1
View File
@@ -217,7 +217,6 @@ void Deci2Server::run() {
printf("[DECI2] Warning: no handler for this message, ignoring...\n");
unlock();
return;
// throw std::runtime_error("no handler!");
}
auto& driver = d2_drivers[handler];
+14 -21
View File
@@ -7,17 +7,17 @@
* Create a new thread. Will not run the thread.
*/
s32 IOP_Kernel::CreateThread(std::string name, u32 (*func)()) {
if (_currentThread != -1)
throw std::runtime_error("tried to create thread from thread");
assert(_currentThread == -1); // can only create thread from kernel thread.
u32 ID = (u32)_nextThID++;
if (threads.size() != ID)
throw std::runtime_error("thread number error?");
assert(ID == threads.size());
// add entry
threads.emplace_back(name, func, ID, this);
// setup the thread!
// printf("[IOP Kernel] SetupThread %s...\n", name.c_str());
// hack to allow creating a "null thread" which doesn't/can't run but occupies slot 0.
// allow creating a "null thread" which doesn't/can't run but occupies slot 0.
if (func) {
_currentThread = ID;
// create OS thread, will run the setupThread function
@@ -47,11 +47,9 @@ void IOP_Kernel::setupThread(s32 id) {
returnToKernel();
threads.at(id).waitForDispatch();
// printf("[IOP Kernel] Thread %s first dispatch!\n", threads.at(id).name.c_str());
if (_currentThread != id) {
throw std::runtime_error("the wrong thread has run!\n");
}
assert(_currentThread == id); // should run in the thread.
(threads.at(id).function)();
printf("Thread %s has returned!\n", threads.at(id).name.c_str());
// printf("Thread %s has returned!\n", threads.at(id).name.c_str());
threads.at(id).done = true;
returnToKernel();
}
@@ -60,8 +58,7 @@ void IOP_Kernel::setupThread(s32 id) {
* Run a thread (call from kernel)
*/
void IOP_Kernel::runThread(s32 id) {
if (_currentThread != -1)
throw std::runtime_error("tried to runThread in a thread");
assert(_currentThread == -1); // should run in the kernel thread
_currentThread = id;
threads.at(id).dispatch();
threads.at(id).waitForReturnToKernel();
@@ -77,9 +74,8 @@ void IOP_Kernel::SuspendThread() {
s32 oldThread = getCurrentThread();
threads.at(oldThread).returnToKernel();
threads.at(oldThread).waitForDispatch();
if (_currentThread != oldThread) {
throw std::runtime_error("bad resume");
}
// check kernel resumed us correctly
assert(_currentThread == oldThread);
}
/*!
@@ -130,8 +126,8 @@ void IOP_Kernel::dispatchAll() {
*/
void IopThreadRecord::returnToKernel() {
runThreadReady = false;
if (kernel->getCurrentThread() != thID)
throw std::runtime_error("tried to sleep the wrong thread!");
// should be called from the correct thread
assert(kernel->getCurrentThread() == thID);
{
std::lock_guard<std::mutex> lck(*threadToKernelMutex);
@@ -145,8 +141,8 @@ void IopThreadRecord::returnToKernel() {
*/
void IopThreadRecord::dispatch() {
syscallReady = false;
if (kernel->getCurrentThread() != thID)
throw std::runtime_error("tried to dispatch the wrong thread!");
assert(kernel->getCurrentThread() == thID);
{
std::lock_guard<std::mutex> lck(*kernelToThreadMutex);
runThreadReady = true;
@@ -160,17 +156,14 @@ void IopThreadRecord::dispatch() {
void IopThreadRecord::waitForReturnToKernel() {
std::unique_lock<std::mutex> lck(*threadToKernelMutex);
threadToKernelCV->wait(lck, [this] { return syscallReady; });
// syscallReady = false;
}
/*!
* Thread waits for kernel to dispatch it.
*/
void IopThreadRecord::waitForDispatch() {
// if(kernel->getCurrentThread() == -1) throw std::runtime_error("tried to suspend main!\n");
std::unique_lock<std::mutex> lck(*kernelToThreadMutex);
kernelToThreadCV->wait(lck, [this] { return runThreadReady; });
// runThreadReady = false;
}
void IOP_Kernel::set_rpc_queue(iop::sceSifQueueData* qd, u32 thread) {
+9 -11
View File
@@ -10,6 +10,7 @@
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <cassert>
#include "common/common_types.h"
class IOP_Kernel;
@@ -98,8 +99,7 @@ class IOP_Kernel {
* Resume the kernel.
*/
void returnToKernel() {
if (_currentThread < 0)
throw std::runtime_error("tried to return to kernel not in a thread");
assert(_currentThread >= 0); // must be in a thread
threads[_currentThread].returnToKernel();
}
@@ -126,15 +126,16 @@ class IOP_Kernel {
// total hack - returning this value causes the ISO thread to error out and quit.
return -0x1a9;
}
// printf("poll %d %ld\n", mbx, mbxs.size());
if (mbx >= (s32)mbxs.size())
throw std::runtime_error("invalid PollMbx");
assert(mbx < (s32)mbxs.size());
s32 gotSomething = mbxs[mbx].empty() ? 0 : 1;
if (gotSomething) {
void* thing = mbxs[mbx].front();
// printf("pop from msgbox %d %p\n", mbx, thing);
if (msg)
if (msg) {
*msg = thing;
}
mbxs[mbx].pop();
}
@@ -145,11 +146,8 @@ class IOP_Kernel {
* Push something into a mbx
*/
s32 SendMbx(s32 mbx, void* value) {
if (mbx >= (s32)mbxs.size())
throw std::runtime_error("invalid SendMbx");
assert(mbx < (s32)mbxs.size());
mbxs[mbx].push(value);
// printf("push into messagebox %d %p\n", mbx, value);
// printf("mbx size %ld\n", mbxs.size());
return 0;
}
+1 -1
View File
@@ -15,7 +15,7 @@
SystemThread& SystemThreadManager::create_thread(const std::string& name) {
if (thread_count >= MAX_SYSTEM_THREADS) {
spdlog::critical("Out of System Threads! MAX_SYSTEM_THREADS is ", MAX_SYSTEM_THREADS);
throw std::runtime_error("Out of System Threads! Please increase MAX_SYSTEM_THREADS");
assert(false);
}
auto& thread = threads[thread_count];
+30 -7
View File
@@ -182,6 +182,9 @@ bool Listener::connect_to_target(int n_tries, const std::string& ip, int port) {
listen_socket = -1;
return false;
}
last_recvd_id = 0;
last_sent_id = 0;
}
/*!
@@ -218,7 +221,17 @@ void Listener::receive_func() {
case ListenerMessageKind::MSG_ACK:
// an "ack" message, sent by the target to indicate it got something.
if (!waiting_for_ack) {
printf("[Listener] Got an ack message when we weren't expecting one.");
if (hdr->msg_id == last_sent_id) {
printf("[Listener] Received ACK for most recent message late.\n");
if (last_recvd_id != hdr->msg_id - 1) {
printf(
"[Listener] WARNING: message ID jumped from %ld to %ld. Some messages may have "
"been lost. You must wait for an ACK before sending the next message.\n",
last_recvd_id, hdr->msg_id);
}
} else {
printf("[Listener] Got an unexpcted ACK message.");
}
}
if (hdr->deci2_header.len < 512) {
@@ -236,6 +249,13 @@ void Listener::receive_func() {
ack_recv_buff[ack_recv_prog] = '\0';
assert(ack_recv_prog < 512);
got_ack = true;
last_recvd_id = hdr->msg_id;
if (last_recvd_id > last_sent_id) {
printf(
"[Listener] ERROR: Got an ack message with id of %ld, but the last message sent "
"had an ID of %ld.\n",
last_recvd_id, last_sent_id);
}
} else {
printf("[Listener] got invalid ack!\n");
}
@@ -245,6 +265,7 @@ void Listener::receive_func() {
case ListenerMessageKind::MSG_PRINT: {
auto* str_buff = new char[hdr->msg_size + 1]; // plus one for the null terminator
int msg_prog = 0;
assert(hdr->msg_id == 0);
while (rcvd < hdr->deci2_header.len) {
if (!m_connected) {
return;
@@ -338,7 +359,8 @@ void Listener::send_code(std::vector<uint8_t>& code) {
header->msg_size = code.size();
header->ltt_msg_kind = LTT_MSG_CODE;
header->u6 = 0;
header->msg_id = 0;
last_sent_id++;
header->msg_id = last_sent_id;
memcpy(buffer_data, code.data(), code.size());
send_buffer(total_size);
}
@@ -365,9 +387,10 @@ void Listener::send_reset(bool shutdown) {
header->deci2_header.src = 'H';
header->deci2_header.dst = 'E';
header->msg_size = 0;
header->ltt_msg_kind = LTT_MSG_RESET;
header->ltt_msg_kind = shutdown ? LTT_MSG_SHUTDOWN : LTT_MSG_RESET;
header->u6 = 0;
header->msg_id = shutdown ? UINT64_MAX : 0;
last_sent_id++;
header->msg_id = last_sent_id;
send_buffer(sizeof(ListenerMessageHeader));
disconnect();
close_socket(listen_socket);
@@ -392,7 +415,8 @@ void Listener::send_poke() {
header->msg_size = 0;
header->ltt_msg_kind = LTT_MSG_POKE;
header->u6 = 0;
header->msg_id = 0;
last_sent_id++;
header->msg_id = last_sent_id;
send_buffer(sizeof(ListenerMessageHeader));
}
@@ -426,8 +450,7 @@ void Listener::send_buffer(int sz) {
printf(" OK\n");
}
} else {
printf(
" Error - target has timed out. If it is stuck in a loop, it must be manually killed.\n");
printf(" Timed out waiting for ack.\n");
}
}
+2
View File
@@ -65,6 +65,8 @@ class Listener {
std::vector<std::string> message_record;
std::unordered_map<std::string, LoadEntry> m_load_entries;
char ack_recv_buff[512];
uint64_t last_sent_id = 0;
uint64_t last_recvd_id = 0;
};
} // namespace listener
+1
View File
@@ -3,6 +3,7 @@
set(GOALC_TEST_CASES
"goalc/all_goalc_template_tests.cpp"
goalc/test_debugger.cpp
goalc/test_game_no_debug.cpp
)
set(GOALC_TEST_FRAMEWORK_SOURCES
+6
View File
@@ -102,6 +102,12 @@ void runtime_with_kernel() {
exec_runtime(argc, const_cast<char**>(argv));
}
void runtime_with_kernel_no_debug_segment() {
constexpr int argc = 3;
const char* argv[argc] = {"", "-fakeiso", "-debug-mem"};
exec_runtime(argc, const_cast<char**>(argv));
}
void createDirIfAbsent(const std::string& path) {
if (!std::filesystem::is_directory(path) || !std::filesystem::exists(path)) {
std::filesystem::create_directory(path);
+1
View File
@@ -41,6 +41,7 @@ struct CompilerTestRunner {
void runtime_no_kernel();
void runtime_with_kernel();
void runtime_with_kernel_no_debug_segment();
void createDirIfAbsent(const std::string& path);
std::string getTemplateDir(const std::string& category);
+32
View File
@@ -0,0 +1,32 @@
// Test the game running without loading debug segments.
#include "gtest/gtest.h"
#include "goalc/compiler/Compiler.h"
#include "test/goalc/framework/test_runner.h"
TEST(GameNoDebugSegment, Init) {
Compiler compiler;
compiler.run_front_end_on_string("(build-kernel)");
std::thread runtime_thread = std::thread(GoalTest::runtime_with_kernel_no_debug_segment);
// this shouldn't crash
compiler.run_test_from_string("(inspect *kernel-context*)");
// these should be equal, both the fallback inspect method
EXPECT_TRUE(compiler.run_test_from_string(
"(print (eq? (method kernel-context inspect) (method cpu-thread inspect))) 0") ==
std::vector<std::string>{"#t\n0\n"});
// should be below the debug heap.
EXPECT_TRUE(
compiler.run_test_from_string(
"(print (< (the uint (method kernel-context inspect)) (the uint (-> debug base)))) 0") ==
std::vector<std::string>{"#t\n0\n"});
// debug segment flag should be disabled.
EXPECT_TRUE(compiler.run_test_from_string("(print *debug-segment*) 0") ==
std::vector<std::string>{"#f\n0\n"});
compiler.shutdown_target();
runtime_thread.join();
}