Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programatic use of Machine / Scryer as library #1880

Merged
merged 73 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
95b3114
Add Machine::set_user_input(&mut self, input: String) and get_user_ou…
lucksus Jul 11, 2023
112d398
Add Machine::run_input_once() which reads one goal from user input an…
lucksus Jul 11, 2023
2f45f0c
Add convenience methods Machine::load_module_string() and Machine::ru…
lucksus Jul 11, 2023
703efdb
Make run_input_once/0 match and print all results
lucksus Jul 11, 2023
568abef
Parsed QueryResult
lucksus Jul 11, 2023
3347f83
Remove debug println!s
lucksus Jul 11, 2023
f324c95
Refactor result parsing to idiomatic Rust and extract into parsed_res…
lucksus Jul 12, 2023
f656758
Fix build warnings
lucksus Jul 12, 2023
c0dd94c
Add test for programatic queries
lucksus Jul 12, 2023
5f8cc3c
WIP: refactor to generalize Machine::run_top_level()
lucksus Jul 17, 2023
e7f1e32
fmt machine/parsed_results.rs
lucksus Jul 17, 2023
3947390
Use lib constructor in lib tests
lucksus Jul 17, 2023
bb95ed3
Add back all needed predicates to lib_toplevel.pl
lucksus Jul 17, 2023
644559b
Add back newline at end of toplevel.pl
lucksus Jul 17, 2023
836f6c1
Don't panic when parsing results fails
lucksus Jul 20, 2023
cae32d6
Error handling
lucksus Jul 20, 2023
7c93450
type QueryResult = Result<QueryResolution, String>
lucksus Jul 20, 2023
0b833bd
Add missing write_goal/3 to lib_toplevel.pl
lucksus Jul 20, 2023
9e85be1
Fix result parsing for complex string results
lucksus Jul 21, 2023
d8a9475
Add missing list_last_item to lib_toplevel.pl and increase MaxDepth o…
lucksus Jul 21, 2023
9fd6e18
Dedupe machine results
lucksus Jul 21, 2023
2f99bb0
Add consult that works with streams / strings in library use-case
lucksus Jul 27, 2023
0d28404
Add special case when parsing
lucksus Jul 27, 2023
30dac8e
HashSet -> BTreeSet: Make parsing or results and thus tests determini…
lucksus Jul 27, 2023
c2658dc
Try triska's toplevel and add some debugging println!s.
lucksus Jul 27, 2023
21c3688
Fix build
lucksus Aug 2, 2023
df048a4
Switch back to run_input_once and use duplicated write_eqs/2 without …
lucksus Aug 2, 2023
3ff02da
Deactivate some debugging outputs
lucksus Aug 2, 2023
65eb937
dont spawn a runtime in machine; inherit from outside with runtime::h…
jdeepee Aug 3, 2023
ac61055
Remove some unused code from lib_toplevel.pl
lucksus Aug 3, 2023
3cf3c0e
Integration stress test showing Machine blocking on query
lucksus Aug 3, 2023
48a4835
Merge branch 'master' into library-use-case
lucksus Aug 3, 2023
cc04872
Merge branch 'master' into library-use-case
lucksus Aug 7, 2023
579816a
Use new `double_quotes` write-option
lucksus Aug 7, 2023
4e8f7f0
Remove unused toplevel predicate
lucksus Aug 7, 2023
cf63b58
Ignore stress test because it fails on windows
lucksus Aug 7, 2023
72ceceb
Updated hyper to 1.0.0-rc.4
fayeed Aug 8, 2023
ce1c8aa
Fixed libffi dep
fayeed Aug 8, 2023
7e97f16
Fix list result parsing
lucksus Aug 22, 2023
bfb3164
Enable multiple Machines per process by having ATOM_TABLE_BUF_BASE al…
lucksus Aug 23, 2023
c258882
Fix parsing of floats
lucksus Aug 24, 2023
afbadd9
Revert "Enable multiple Machines per process by having ATOM_TABLE_BUF…
lucksus Aug 24, 2023
d131739
Cargo feature "multi_thread" for thread-local ATOM_TABLE_BUF_BASE
lucksus Aug 24, 2023
77394ba
Remove debug println!s
lucksus Aug 24, 2023
44c274b
WIP: Pure Rust impl. of run_query
lucksus Aug 30, 2023
4d19c43
Merge branch 'master' into library-use-case
lucksus Aug 30, 2023
2b018be
Add back needed dep. hyper-util and upgrade hyper to rc4
lucksus Aug 30, 2023
8a0685a
Debug print value of register 6 which leads to failing heap dereference
lucksus Aug 30, 2023
ef56193
Use write_term_to_heap as suggest, clean up, and include error in com…
lucksus Sep 13, 2023
136463c
Merge branch 'master' into library-use-case
lucksus Sep 13, 2023
5fa68e2
lib_machine tests should not be tokio/async
lucksus Sep 13, 2023
6bdd7f3
mthom's revised run_query with manually created printer and some cleanup
lucksus Sep 14, 2023
48283c4
mthom's changes to run_query with backtracking
lucksus Sep 15, 2023
f02728a
Construct QueryResult from printer output
lucksus Sep 15, 2023
7c83a1f
Cleanup code that's not needed anymore
lucksus Sep 15, 2023
c86304b
Remove lib_toplevel.pl
lucksus Sep 15, 2023
d2f5291
mthom's changes fixing the panic
lucksus Sep 18, 2023
65f64e4
Construct and return exception string
lucksus Sep 18, 2023
5e55625
Remove some debug println!s
lucksus Sep 18, 2023
4968fa0
Remove debugging println!
lucksus Sep 18, 2023
7b128a9
Handle stub_b = b as false
lucksus Oct 3, 2023
fab5ca9
Fix nested List parsing
lucksus Oct 3, 2023
640c637
Merge branch 'master' into library-use-case
lucksus Oct 5, 2023
69cf2c3
Deactivate tokio runtime respawning on interrupt
lucksus Oct 5, 2023
9990780
Merge branch 'master' into library-use-case
lucksus Oct 16, 2023
bfa7d3c
Remove unuse import
lucksus Oct 16, 2023
025412a
Revert "Remove unuse import"
lucksus Oct 16, 2023
d7fa6c0
Fix signalling of success/failure (by @mthom)
lucksus Oct 16, 2023
2776beb
Use std::sync::RwLock instead of tokio::sync::RwLock (by @aarroyoc)
lucksus Oct 16, 2023
0c9740f
Fix wasm warnings
lucksus Oct 17, 2023
69a0725
Cleanup Cargo.toml
lucksus Oct 17, 2023
ee1bd9e
Merge branch 'master' into library-use-case
lucksus Nov 2, 2023
59264c0
Check for target_arch = “wasm32”
lucksus Nov 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ smallvec = "1.8.0"
static_assertions = "1.1.0"
ryu = "1.0.9"
futures = "0.3"
regex = "1.9.1"
libloading = "0.7"
derive_deref = "1.1.1"
bytes = "1"
Expand All @@ -84,7 +85,7 @@ tokio = { version = "1.28.2", features = ["full"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2.10", features = ["js"] }
tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt"] }
tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] }

[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
console_error_panic_hook = "0.1"
Expand All @@ -107,6 +108,7 @@ ring = { version = "0.16.13" }
[dev-dependencies]
assert_cmd = "1.0.3"
predicates-core = "1.0.2"
maplit = "1.0.2"
serial_test = "2.0.0"

[patch.crates-io]
Expand Down
9 changes: 5 additions & 4 deletions src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::read::*;

use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat;
use tokio::sync::RwLock;

use std::alloc;
use std::cell::UnsafeCell;
Expand All @@ -20,6 +19,7 @@ use std::mem;
use std::net::TcpListener;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::sync::RwLock;

#[macro_export]
macro_rules! arena_alloc {
Expand Down Expand Up @@ -90,7 +90,8 @@ pub fn lookup_float(
offset: F64Offset,
) -> RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>> {
let f64table = global_f64table()
.blocking_read()
.read()
.unwrap()
.upgrade()
.expect("We should only be looking up floats while there is a float table");

Expand All @@ -108,12 +109,12 @@ pub fn lookup_float(
impl F64Table {
#[inline]
pub fn new() -> Arc<Self> {
let upgraded = global_f64table().blocking_read().upgrade();
let upgraded = global_f64table().read().unwrap().upgrade();
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
if let Some(atom_table) = upgraded {
atom_table
} else {
let mut guard = global_f64table().blocking_write();
let mut guard = global_f64table().write().unwrap();
// try to upgrade again in case we lost the race on the write lock
if let Some(atom_table) = guard.upgrade() {
atom_table
Expand Down
8 changes: 4 additions & 4 deletions src/atom_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ use std::slice;
use std::str;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
use std::sync::Weak;

use indexmap::IndexSet;

use modular_bitfield::prelude::*;
use tokio::sync::RwLock;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Atom {
Expand Down Expand Up @@ -74,7 +74,7 @@ fn global_atom_table() -> &'static RwLock<Weak<AtomTable>> {

#[inline(always)]
fn arc_atom_table() -> Option<Arc<AtomTable>> {
global_atom_table().blocking_read().upgrade()
global_atom_table().read().unwrap().upgrade()
}

impl RawBlockTraits for AtomTable {
Expand Down Expand Up @@ -310,12 +310,12 @@ impl InnerAtomTable {
impl AtomTable {
#[inline]
pub fn new() -> Arc<Self> {
let upgraded = global_atom_table().blocking_read().upgrade();
let upgraded = global_atom_table().read().unwrap().upgrade();
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
if let Some(atom_table) = upgraded {
atom_table
} else {
let mut guard = global_atom_table().blocking_write();
let mut guard = global_atom_table().write().unwrap();
// try to upgrade again in case we lost the race on the write lock
if let Some(atom_table) = guard.upgrade() {
atom_table
Expand Down
19 changes: 17 additions & 2 deletions src/bin/scryer-prolog.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
fn main() -> std::process::ExitCode {
use scryer_prolog::*;
use scryer_prolog::atom_table::Atom;
use std::sync::atomic::Ordering;

#[cfg(feature = "repl")]
Expand All @@ -8,6 +9,20 @@ fn main() -> std::process::ExitCode {
})
.unwrap();

let mut wam = machine::Machine::new();
wam.run_top_level()
#[cfg(target_arch = "wasm32")]
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();

#[cfg(not(target_arch = "wasm32"))]
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();

runtime.block_on(async move {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what's the purpose of this if everything inside is sync (?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block seems to be the issue of the errors reported by @mthom . Removing it makes all the test pass, but of course http_listen/2 crashes. There are two options that I see:

  • Go full mode async. This a more disruptive change I think. It's making the Machine async-aware, so system calls can be async, which could imply rewriting the http_listen/2 parts (but I don't mind)
  • Return to the old system of having a runtime attached to a Machine, which can be used to launch async tasks in sync contexts.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know enough about async or tokio to make a judgment as to which course is best. Can there not be simultaneous tokio runtimes? Or runtimes within runtimes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After tinkering more with this, there's a third option. Change the tokio::sync::RwLock to std::sync::RwLock. This is a very small change (see https://github.com/aarroyoc/scryer-prolog/tree/library-use-case) and everything seems to work again (both tests and http_listen/2). The ultimate reason seems to be that the machine executes now in an async environment (I still don't know why) and RwLock::blocking_read/blocking_write are expected to panic when called in an async environment since they're designed for sync code (https://docs.rs/tokio/latest/tokio/sync/struct.RwLock.html#method.blocking_read)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rust Futures need be polled in order to execute anything. That means you need at least one Future executor like block_on to keep polling the Futures to completion. If you would have this async block here in this main function, the app would return and never even start processing the async code.

let mut wam = machine::Machine::new(Default::default());
wam.run_top_level(atom!("$toplevel"), (atom!("$repl"), 1))
})
}
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#[macro_use]
extern crate static_assertions;
#[cfg(test)]
#[macro_use] extern crate maplit;

#[macro_use]
pub mod macros;
Expand Down Expand Up @@ -47,7 +49,6 @@ use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn eval_code(s: &str) -> String {
use web_sys::console;
use machine::mock_wam::*;

let mut wam = Machine::with_test_streams();
Expand Down
4 changes: 4 additions & 0 deletions src/loader.pl
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,10 @@
)
).

consult_stream(Stream, PathFileName) :-
'$push_load_state_payload'(Evacuable),
file_load(Stream, PathFileName, Subevacuable),
'$use_module'(Evacuable, Subevacuable, _).

:- non_counted_backtracking check_predicate_property/5.

Expand Down
32 changes: 32 additions & 0 deletions src/machine/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pub struct MachineConfig {
pub streams: StreamConfig,
pub toplevel: &'static str,
}

pub enum StreamConfig {
Stdio,
Memory,
}

impl Default for MachineConfig {
fn default() -> Self {
MachineConfig {
streams: StreamConfig::Stdio,
toplevel: include_str!("../toplevel.pl"),
}
}
}

impl MachineConfig {
pub fn in_memory() -> Self {
MachineConfig {
streams: StreamConfig::Memory,
..Default::default()
}
}

pub fn with_toplevel(mut self, toplevel: &'static str) -> Self {
self.toplevel = toplevel;
self
}
}
26 changes: 16 additions & 10 deletions src/machine/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5221,16 +5221,22 @@ impl Machine {
self.machine_st.throw_interrupt_exception();
self.machine_st.backtrack();

#[cfg(not(target_arch = "wasm32"))]
let runtime = tokio::runtime::Runtime::new().unwrap();
#[cfg(target_arch = "wasm32")]
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();

let old_runtime = std::mem::replace(&mut self.runtime, runtime);
old_runtime.shutdown_background();
// We have extracted controll over the Tokio runtime to the calling context for enabling library use case
// (see https://github.com/mthom/scryer-prolog/pull/1880)
// So we only have access to a runtime handle in here and can't shut it down.
// Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880
// was not merged, I'm only deactivating it for now.

//#[cfg(not(target_arch = "wasm32"))]
//let runtime = tokio::runtime::Runtime::new().unwrap();
//#[cfg(target_arch = "wasm32")]
//let runtime = tokio::runtime::Builder::new_current_thread()
// .enable_all()
// .build()
// .unwrap();

//let old_runtime = tokio::runtime::Handle::current();
//old_runtime.shutdown_background();
}
}
Err(_) => unreachable!(),
Expand Down
Loading
Loading