mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
add threaded support
This commit is contained in:
parent
7079b66a64
commit
20b608fe7e
@ -1 +1 @@
|
||||
g++ -o pocketpy src/main.cpp --std=c++17 -O1
|
||||
g++ -o pocketpy src/main.cpp --std=c++17 -O1 -pthread
|
@ -18,3 +18,4 @@
|
||||
#include <iomanip>
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
37
src/main.cpp
37
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<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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
34
src/vm.h
34
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<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;
|
||||
});
|
||||
}
|
||||
|
||||
|
11
test_cpp.sh
11
test_cpp.sh
@ -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
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user