diff --git a/build_cpp.sh b/build_cpp.sh index 88aae3f9..b34d05d9 100644 --- a/build_cpp.sh +++ b/build_cpp.sh @@ -1 +1 @@ -g++ -o pocketpy src/main.cpp --std=c++17 -O1 \ No newline at end of file +g++ -o pocketpy src/main.cpp --std=c++17 -O1 -pthread \ No newline at end of file diff --git a/src/__stl__.h b/src/__stl__.h index 6157f02d..a0fb2c48 100644 --- a/src/__stl__.h +++ b/src/__stl__.h @@ -17,4 +17,5 @@ #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 948a4374..f13da9b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,7 +3,7 @@ #include "pocketpy.h" -//#define PK_DEBUG_TIME +#define PK_DEBUG_TIME struct Timer{ const char* title; @@ -19,13 +19,20 @@ struct Timer{ } }; -VM* newVM(){ - VM* vm = pkpy_new_vm([](const VM* vm, const char* str) { - std::cout << str; - std::cout.flush(); +ThreadedVM* new_tvm_with_callbacks(){ + ThreadedVM* vm = pkpy_new_tvm([](const VM* vm, const char* str) { + std::cout << str; std::cout.flush(); }, [](const VM* vm, const char* str) { - std::cerr << str; - std::cerr.flush(); + std::cerr << str; std::cerr.flush(); + }); + return vm; +} + +VM* new_vm_with_callbacks(){ + VM* vm = pkpy_new_vm([](const VM* vm, const char* str) { + std::cout << str; std::cout.flush(); + }, [](const VM* vm, const char* str) { + std::cerr << str; std::cerr.flush(); }); return vm; } @@ -40,7 +47,7 @@ REPL* _repl; extern "C" { __EXPORT void repl_start(){ - _repl = pkpy_new_repl(newVM(), false); + _repl = pkpy_new_repl(new_vm_with_callbacks(), false); } __EXPORT @@ -54,7 +61,7 @@ extern "C" { int main(int argc, char** argv){ if(argc == 1){ - REPL repl(newVM()); + REPL repl(new_vm_with_callbacks()); while(true){ std::string line; std::getline(std::cin, line); @@ -74,7 +81,7 @@ int main(int argc, char** argv){ } std::string src((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - VM* vm = newVM(); + ThreadedVM* vm = new_tvm_with_callbacks(); _Code code; Timer("Compile time").run([&]{ code = compile(vm, src.c_str(), filename); @@ -82,7 +89,15 @@ int main(int argc, char** argv){ if(code == nullptr) return 1; //std::cout << code->toString() << std::endl; Timer("Running time").run([=]{ - vm->exec(code); + vm->startExec(code); + while(pkpy_tvm_get_state(vm) != THREAD_FINISHED){ + if(pkpy_tvm_get_state(vm) == THREAD_SUSPENDED){ + std::string line; + std::getline(std::cin, line); + pkpy_tvm_write_stdin(vm, line.c_str()); + pkpy_tvm_resume(vm); + } + } }); return 0; } diff --git a/src/pocketpy.h b/src/pocketpy.h index 1d581901..23669a42 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -51,6 +51,7 @@ void __initializeBuiltinFunctions(VM* _vm) { vm->__checkArgSize(args, 0); ThreadedVM* tvm = dynamic_cast(vm); if(tvm == nullptr) vm->typeError("input() can only be called in threaded mode"); + tvm->suspend(); return vm->PyStr(tvm->readStdin()); }); @@ -634,9 +635,7 @@ extern "C" { return vm->exec(code, _m) != nullptr; } - __EXPORT - VM* pkpy_new_vm(PrintFn _stdout, PrintFn _stderr){ - VM* vm = new VM(); + void __vm_init(VM* vm, PrintFn _stdout, PrintFn _stderr){ __initializeBuiltinFunctions(vm); vm->_stdout = _stdout; vm->_stderr = _stderr; @@ -647,8 +646,42 @@ extern "C" { __addModuleSys(vm); __addModuleTime(vm); - pkpy_add_module(vm, "random", __RANDOM_CODE); + } + + __EXPORT + VM* pkpy_new_vm(PrintFn _stdout, PrintFn _stderr){ + VM* vm = new VM(); + __vm_init(vm, _stdout, _stderr); return vm; } + + __EXPORT + ThreadedVM* pkpy_new_tvm(PrintFn _stdout, PrintFn _stderr){ + ThreadedVM* vm = new ThreadedVM(); + __vm_init(vm, _stdout, _stderr); + return vm; + } + + __EXPORT + int pkpy_tvm_get_state(ThreadedVM* vm){ + return vm->getState(); + } + + __EXPORT + void pkpy_tvm_start_exec(ThreadedVM* vm, const char* source){ + _Code code = compile(vm, source, "main.py"); + if(code == nullptr) return; + return vm->startExec(code); + } + + __EXPORT + void pkpy_tvm_write_stdin(ThreadedVM* vm, const char* line){ + vm->_stdin = _Str(line); + } + + __EXPORT + void pkpy_tvm_resume(ThreadedVM* vm){ + vm->resume(); + } } \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index 64b472ec..5779a894 100644 --- a/src/vm.h +++ b/src/vm.h @@ -906,25 +906,26 @@ PyVar StringIterator::next(){ return vm->PyStr(str->u8_getitem(index++)); } +enum ThreadState { + THREAD_READY, + THREAD_RUNNING, + THREAD_SUSPENDED, + THREAD_FINISHED +}; class ThreadedVM : public VM { std::thread* _thread; - bool _flag_thread_sleeping = false; + std::atomic state = THREAD_READY; public: _Str _stdin; - void sleep(){ + void suspend(){ if(_thread == nullptr) UNREACHABLE(); - _flag_thread_sleeping = true; + if(state != THREAD_RUNNING) UNREACHABLE(); + state = THREAD_SUSPENDED; // 50 fps is enough - while(!_flag_thread_sleeping) std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } - - void writeStdin(const _Str& s){ - if(_thread == nullptr) UNREACHABLE(); - _stdin = s; - wakeUp(); + while(state == THREAD_SUSPENDED) std::this_thread::sleep_for(std::chrono::milliseconds(20)); } _Str readStdin(){ @@ -934,20 +935,25 @@ public: return copy; } - bool isSleeping(){ + /***** For outer use *****/ + + ThreadState getState(){ if(_thread == nullptr) UNREACHABLE(); - return _flag_thread_sleeping; + return state; } - void wakeUp(){ + void resume(){ if(_thread == nullptr) UNREACHABLE(); - _flag_thread_sleeping = false; + if(state != THREAD_SUSPENDED) UNREACHABLE(); + state = THREAD_RUNNING; } void startExec(const _Code& code){ if(_thread != nullptr) UNREACHABLE(); _thread = new std::thread([this, code](){ + this->state = THREAD_RUNNING; this->exec(code); + this->state = THREAD_FINISHED; }); } diff --git a/test_cpp.sh b/test_cpp.sh deleted file mode 100644 index 7c316a84..00000000 --- a/test_cpp.sh +++ /dev/null @@ -1,11 +0,0 @@ -g++ -o pocketpy src/main.cpp --std=c++17 -pg -O1 - -./pocketpy tests/1.py - -gprof pocketpy gmon.out > gprof.txt - -#gprof pocketpy | gprof2dot | dot -Tsvg -o output.svg -rm gmon.out - - -