add threaded support

This commit is contained in:
blueloveTH 2022-11-14 16:08:04 +08:00
parent 7079b66a64
commit 20b608fe7e
6 changed files with 86 additions and 42 deletions

View File

@ -1 +1 @@
g++ -o pocketpy src/main.cpp --std=c++17 -O1 g++ -o pocketpy src/main.cpp --std=c++17 -O1 -pthread

View File

@ -18,3 +18,4 @@
#include <iomanip> #include <iomanip>
#include <thread> #include <thread>
#include <atomic>

View File

@ -3,7 +3,7 @@
#include "pocketpy.h" #include "pocketpy.h"
//#define PK_DEBUG_TIME #define PK_DEBUG_TIME
struct Timer{ struct Timer{
const char* title; const char* title;
@ -19,13 +19,20 @@ struct Timer{
} }
}; };
VM* newVM(){ ThreadedVM* new_tvm_with_callbacks(){
VM* vm = pkpy_new_vm([](const VM* vm, const char* str) { ThreadedVM* vm = pkpy_new_tvm([](const VM* vm, const char* str) {
std::cout << str; std::cout << str; std::cout.flush();
std::cout.flush();
}, [](const VM* vm, const char* str) { }, [](const VM* vm, const char* str) {
std::cerr << str; std::cerr << str; std::cerr.flush();
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; return vm;
} }
@ -40,7 +47,7 @@ REPL* _repl;
extern "C" { extern "C" {
__EXPORT __EXPORT
void repl_start(){ void repl_start(){
_repl = pkpy_new_repl(newVM(), false); _repl = pkpy_new_repl(new_vm_with_callbacks(), false);
} }
__EXPORT __EXPORT
@ -54,7 +61,7 @@ extern "C" {
int main(int argc, char** argv){ int main(int argc, char** argv){
if(argc == 1){ if(argc == 1){
REPL repl(newVM()); REPL repl(new_vm_with_callbacks());
while(true){ while(true){
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
@ -74,7 +81,7 @@ int main(int argc, char** argv){
} }
std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
VM* vm = newVM(); ThreadedVM* vm = new_tvm_with_callbacks();
_Code code; _Code code;
Timer("Compile time").run([&]{ Timer("Compile time").run([&]{
code = compile(vm, src.c_str(), filename); code = compile(vm, src.c_str(), filename);
@ -82,7 +89,15 @@ int main(int argc, char** argv){
if(code == nullptr) return 1; if(code == nullptr) return 1;
//std::cout << code->toString() << std::endl; //std::cout << code->toString() << std::endl;
Timer("Running time").run([=]{ 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; return 0;
} }

View File

@ -51,6 +51,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
vm->__checkArgSize(args, 0); vm->__checkArgSize(args, 0);
ThreadedVM* tvm = dynamic_cast<ThreadedVM*>(vm); ThreadedVM* tvm = dynamic_cast<ThreadedVM*>(vm);
if(tvm == nullptr) vm->typeError("input() can only be called in threaded mode"); if(tvm == nullptr) vm->typeError("input() can only be called in threaded mode");
tvm->suspend();
return vm->PyStr(tvm->readStdin()); return vm->PyStr(tvm->readStdin());
}); });
@ -634,9 +635,7 @@ extern "C" {
return vm->exec(code, _m) != nullptr; return vm->exec(code, _m) != nullptr;
} }
__EXPORT void __vm_init(VM* vm, PrintFn _stdout, PrintFn _stderr){
VM* pkpy_new_vm(PrintFn _stdout, PrintFn _stderr){
VM* vm = new VM();
__initializeBuiltinFunctions(vm); __initializeBuiltinFunctions(vm);
vm->_stdout = _stdout; vm->_stdout = _stdout;
vm->_stderr = _stderr; vm->_stderr = _stderr;
@ -647,8 +646,42 @@ extern "C" {
__addModuleSys(vm); __addModuleSys(vm);
__addModuleTime(vm); __addModuleTime(vm);
pkpy_add_module(vm, "random", __RANDOM_CODE); 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; 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();
}
} }

View File

@ -906,25 +906,26 @@ PyVar StringIterator::next(){
return vm->PyStr(str->u8_getitem(index++)); return vm->PyStr(str->u8_getitem(index++));
} }
enum ThreadState {
THREAD_READY,
THREAD_RUNNING,
THREAD_SUSPENDED,
THREAD_FINISHED
};
class ThreadedVM : public VM { class ThreadedVM : public VM {
std::thread* _thread; std::thread* _thread;
bool _flag_thread_sleeping = false; std::atomic<ThreadState> state = THREAD_READY;
public: public:
_Str _stdin; _Str _stdin;
void sleep(){ void suspend(){
if(_thread == nullptr) UNREACHABLE(); if(_thread == nullptr) UNREACHABLE();
_flag_thread_sleeping = true; if(state != THREAD_RUNNING) UNREACHABLE();
state = THREAD_SUSPENDED;
// 50 fps is enough // 50 fps is enough
while(!_flag_thread_sleeping) std::this_thread::sleep_for(std::chrono::milliseconds(20)); while(state == THREAD_SUSPENDED) std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
void writeStdin(const _Str& s){
if(_thread == nullptr) UNREACHABLE();
_stdin = s;
wakeUp();
} }
_Str readStdin(){ _Str readStdin(){
@ -934,20 +935,25 @@ public:
return copy; return copy;
} }
bool isSleeping(){ /***** For outer use *****/
ThreadState getState(){
if(_thread == nullptr) UNREACHABLE(); if(_thread == nullptr) UNREACHABLE();
return _flag_thread_sleeping; return state;
} }
void wakeUp(){ void resume(){
if(_thread == nullptr) UNREACHABLE(); if(_thread == nullptr) UNREACHABLE();
_flag_thread_sleeping = false; if(state != THREAD_SUSPENDED) UNREACHABLE();
state = THREAD_RUNNING;
} }
void startExec(const _Code& code){ void startExec(const _Code& code){
if(_thread != nullptr) UNREACHABLE(); if(_thread != nullptr) UNREACHABLE();
_thread = new std::thread([this, code](){ _thread = new std::thread([this, code](){
this->state = THREAD_RUNNING;
this->exec(code); this->exec(code);
this->state = THREAD_FINISHED;
}); });
} }

View File

@ -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