mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40: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 <iomanip>
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <atomic>
|
37
src/main.cpp
37
src/main.cpp
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
34
src/vm.h
34
src/vm.h
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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