-
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathsuspend_thread_demo.cpp
More file actions
120 lines (93 loc) · 4.35 KB
/
suspend_thread_demo.cpp
File metadata and controls
120 lines (93 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* === TeaScript Demo Program ===
* SPDX-FileCopyrightText: Copyright (C) 2024 Florian Thake <contact |at| tea-age.solutions>.
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/
*/
// The following demo code demostrates how a running script can be suspended by another thread.
// This demo code uses the low level components of TeaScript which may change often in its API, structure, layout, etc.
// An alternactive way would be to derive from the Engine class and use its members.
// Or have a look at class CoroutineScriptEngine and the demo code in coroutine_demo.cpp
// NOTE: This feature relies on the C++20 library feature std::stop_source|token.
// Unfortunately, clang does not have this actually.
// It might be possible with the last recent version 18 combined with -fexperimental-library or
// when use libstdc++ instead of libc++.
// We opt-out for header only (must be in each TU (Translation Unit) where teascript includes are used, or project wide).
// NOTE: The default is header only, which does not require to do anything special.
#define TEASCRIPT_DISABLE_HEADER_ONLY 1
#include "teascript/StackMachine.hpp"
#include "teascript/CoreLibrary.hpp" // we don't need the core lib for the demo TeaScript code, but because usually at least the minimal config is needed, it is here as well.
#include "teascript/Parser.hpp"
#include "teascript/StackVMCompiler.hpp"
#include <thread>
namespace {
constexpr char endless_loop_code[] = R"_SCRIPT_(
def c := 0
repeat {
c := c + 1
}
)_SCRIPT_";
// the thread function, it will compile a program with an endless loop and execute it.
void thread_func( std::shared_ptr<teascript::StackVM::Machine<true>> the_machine, teascript::Context &rContext, std::exception_ptr &ep )
{
try {
teascript::Parser p;
teascript::StackVM::Compiler c;
auto const prog = c.Compile( p.Parse( endless_loop_code ) );
the_machine->Exec( prog, rContext );
} catch( ... ) {
ep = std::current_exception();
}
}
} // anonymous
void teascript_thread_suspend_demo()
{
#if TEASCRIPT_SUSPEND_REQUEST_POSSIBLE
std::exception_ptr ep; // for error propagating.
teascript::Context context;
teascript::CoreLibrary().Bootstrap( context, teascript::config::minimal() );
auto machine = std::make_shared< teascript::StackVM::Machine<true> >();
try {
// launch the thread
std::cout << "Launching thread with a TeaScript endless loop..." << std::endl;
std::thread t(thread_func, machine, std::ref(context), std::ref(ep));
// and sleep zZzZzZzZz
std::cout << "... and going to sleep 5 seconds..." << std::endl;
std::this_thread::sleep_for( std::chrono::seconds( 5 ) );
// send the suspend request
std::cout << "woke up, sending suspend request now..." << std::endl;
if( not machine->Suspend() ) [[unlikely]] { // can only fail if std::stop_source::request_stop() fails.
throw std::runtime_error( "Could not send suspend request!" );
}
std::cout << "waiting for join...";
// wait for the thread.
t.join();
std::cout << "joined." << std::endl;
// are there errors?
if( ep ) {
std::rethrow_exception( ep );
}
machine->ThrowPossibleErrorException();
// just some state checking
if( not machine->IsSuspended() ) [[unlikely]] {
throw std::runtime_error( "Unexpected state!" );
}
// lets see where the endless loop was suspended....
auto const c = context.FindValueObject( "c" );
std::cout << "the endless loop counted until " << c.PrintValue() << " before was suspended." << std::endl;
} catch( teascript::exception::runtime_error const &ex ) {
#if TEASCRIPT_FMTFORMAT // you need libfmt for pretty colored output
teascript::util::pretty_print_colored( ex );
#else
teascript::util::pretty_print( ex );
#endif
} catch( std::exception const &ex ) {
std::cout << "Exception caught: " << ex.what() << std::endl;
}
#else
(void)thread_func;
std::cout << "You need C++20 std::stop_source in your C++ library for be able to run this demo." << std::endl;
#endif
}