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 <thread>
#include <atomic>

View File

@ -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<char>(file)), std::istreambuf_iterator<char>());
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;
}

View File

@ -51,6 +51,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
vm->__checkArgSize(args, 0);
ThreadedVM* tvm = dynamic_cast<ThreadedVM*>(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();
}
}

View File

@ -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<ThreadState> 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;
});
}

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