Răsfoiți Sursa

add threaded support

blueloveTH 3 ani în urmă
părinte
comite
20b608fe7e
6 a modificat fișierele cu 85 adăugiri și 41 ștergeri
  1. 1 1
      build_cpp.sh
  2. 2 1
      src/__stl__.h
  3. 25 10
      src/main.cpp
  4. 37 4
      src/pocketpy.h
  5. 20 14
      src/vm.h
  6. 0 11
      test_cpp.sh

+ 1 - 1
build_cpp.sh

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

+ 2 - 1
src/__stl__.h

@@ -17,4 +17,5 @@
 #include <queue>
 #include <iomanip>
 
-#include <thread>
+#include <thread>
+#include <atomic>

+ 25 - 10
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(){
+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();
+    });
+    return vm;
+}
+
+VM* new_vm_with_callbacks(){
     VM* vm = pkpy_new_vm([](const VM* vm, const char* str) { 
-        std::cout << str;
-        std::cout.flush();
+        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;
 }
@@ -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;
     }

+ 37 - 4
src/pocketpy.h

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

+ 20 - 14
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;
         });
     }
 

+ 0 - 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
-
-
-