Skip to content
This repository was archived by the owner on Jun 10, 2024. It is now read-only.

Commit b1942bd

Browse files
committed
:erlang.spawn_link/3
1 parent aeb75ec commit b1942bd

File tree

30 files changed

+1174
-185
lines changed

30 files changed

+1174
-185
lines changed

liblumen_alloc/src/erts/term/term.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,15 @@ impl Term {
938938
typecheck::is_list(self.0)
939939
}
940940

941+
pub fn is_proper_list(&self) -> bool {
942+
self.is_nil()
943+
|| (self.is_non_empty_list() && {
944+
let cons: Boxed<Cons> = (*self).try_into().unwrap();
945+
946+
cons.is_proper()
947+
})
948+
}
949+
941950
/// Returns true if this a term that the runtime should accept as an argument.
942951
pub fn is_runtime(&self) -> bool {
943952
self.is_immediate() || self.is_boxed() || self.is_non_empty_list()

liblumen_eir_interpreter/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use liblumen_alloc::erts::process::{heap, next_heap_size, Status};
88
use liblumen_alloc::erts::term::{atom_unchecked, Atom, Term};
99
use liblumen_alloc::erts::ModuleFunctionArity;
1010

11+
use lumen_runtime::process::Linkage;
1112
use lumen_runtime::scheduler::Scheduler;
1213
use lumen_runtime::system;
1314

@@ -66,8 +67,9 @@ pub fn call_erlang(
6667
// if this fails the entire tab is out-of-memory
6768
let heap = heap(heap_size).unwrap();
6869

69-
let run_arc_process = Scheduler::spawn_apply_3(
70+
let run_arc_process = Scheduler::spawn_linkage_apply_3(
7071
&proc,
72+
Linkage::None,
7173
module,
7274
function,
7375
arguments,

liblumen_eir_interpreter/src/vm.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use libeir_ir::FunctionIdent;
66
use liblumen_alloc::erts::exception;
77
use liblumen_alloc::erts::process::{heap, next_heap_size, Status};
88
use liblumen_alloc::erts::term::{atom_unchecked, Atom, Term};
9+
10+
use lumen_runtime::process::Linkage;
911
use lumen_runtime::scheduler::Scheduler;
1012
use lumen_runtime::system;
1113

@@ -48,8 +50,9 @@ impl VMState {
4850
// if this fails the entire tab is out-of-memory
4951
let heap = heap(heap_size).unwrap();
5052

51-
let run_arc_process = Scheduler::spawn_apply_3(
53+
let run_arc_process = Scheduler::spawn_linkage_apply_3(
5254
&init_arc_process,
55+
Linkage::None,
5356
module,
5457
function,
5558
arguments,

lumen_runtime/src/otp/erlang.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub mod process_flag_2;
1111
pub mod self_0;
1212
pub mod send_2;
1313
pub mod spawn_3;
14+
pub mod spawn_link_3;
15+
pub mod spawn_linkage_3;
1416
pub mod subtract_2;
1517
pub mod unlink_1;
1618

lumen_runtime/src/otp/erlang/link_1/test/with_local_pid.rs

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn with_existing_linked_pid_returns_true() {
6969
}
7070

7171
#[test]
72-
fn when_a_linked_process_exits_the_process_exits_too() {
72+
fn when_a_linked_process_exits_normal_the_process_does_not_exit() {
7373
with_process(|process| {
7474
let other_arc_process = process::test(process);
7575

@@ -92,13 +92,101 @@ fn when_a_linked_process_exits_the_process_exits_too() {
9292

9393
assert!(Scheduler::current().run_through(&other_arc_process));
9494

95+
assert!(other_arc_process.is_exiting());
96+
assert!(!process.is_exiting())
97+
});
98+
}
99+
100+
#[test]
101+
fn when_a_linked_process_exits_shutdown_the_process_does_not_exit() {
102+
with_process(|process| {
103+
let other_arc_process = process::test(process);
104+
105+
assert_eq!(
106+
native(process, other_arc_process.pid_term()),
107+
Ok(true.into())
108+
);
109+
110+
assert!(Scheduler::current().run_through(&other_arc_process));
111+
112+
assert!(!other_arc_process.is_exiting());
113+
assert!(!process.is_exiting());
114+
115+
erlang::exit_1::place_frame_with_arguments(
116+
&other_arc_process,
117+
Placement::Replace,
118+
atom_unchecked("shutdown"),
119+
)
120+
.unwrap();
121+
122+
assert!(Scheduler::current().run_through(&other_arc_process));
123+
124+
assert!(other_arc_process.is_exiting());
125+
assert!(!process.is_exiting())
126+
});
127+
}
128+
129+
#[test]
130+
fn when_a_linked_process_exits_with_shutdown_tuple_the_process_does_not_exit() {
131+
with_process(|process| {
132+
let other_arc_process = process::test(process);
133+
134+
assert_eq!(
135+
native(process, other_arc_process.pid_term()),
136+
Ok(true.into())
137+
);
138+
139+
assert!(Scheduler::current().run_through(&other_arc_process));
140+
141+
assert!(!other_arc_process.is_exiting());
142+
assert!(!process.is_exiting());
143+
144+
let tag = atom_unchecked("shutdown");
145+
let shutdown_reason = atom_unchecked("test");
146+
let reason = other_arc_process
147+
.tuple_from_slice(&[tag, shutdown_reason])
148+
.unwrap();
149+
erlang::exit_1::place_frame_with_arguments(&other_arc_process, Placement::Replace, reason)
150+
.unwrap();
151+
152+
assert!(Scheduler::current().run_through(&other_arc_process));
153+
154+
assert!(other_arc_process.is_exiting());
155+
assert!(!process.is_exiting())
156+
});
157+
}
158+
159+
#[test]
160+
fn when_a_linked_process_exits_unexpected_the_process_does_not_exit() {
161+
with_process(|process| {
162+
let other_arc_process = process::test(process);
163+
164+
assert_eq!(
165+
native(process, other_arc_process.pid_term()),
166+
Ok(true.into())
167+
);
168+
169+
assert!(Scheduler::current().run_through(&other_arc_process));
170+
171+
assert!(!other_arc_process.is_exiting());
172+
assert!(!process.is_exiting());
173+
174+
erlang::exit_1::place_frame_with_arguments(
175+
&other_arc_process,
176+
Placement::Replace,
177+
atom_unchecked("abnormal"),
178+
)
179+
.unwrap();
180+
181+
assert!(Scheduler::current().run_through(&other_arc_process));
182+
95183
assert!(other_arc_process.is_exiting());
96184
assert!(process.is_exiting())
97185
});
98186
}
99187

100188
#[test]
101-
fn when_the_process_exits_linked_processes_exit_too() {
189+
fn when_the_process_exits_unexpected_linked_processes_exit_too() {
102190
with_process_arc(|arc_process| {
103191
let other_arc_process = process::test(&arc_process);
104192

@@ -115,7 +203,7 @@ fn when_the_process_exits_linked_processes_exit_too() {
115203
erlang::exit_1::place_frame_with_arguments(
116204
&arc_process,
117205
Placement::Replace,
118-
atom_unchecked("normal"),
206+
atom_unchecked("abnormal"),
119207
)
120208
.unwrap();
121209

lumen_runtime/src/otp/erlang/process_flag_2/test/with_atom_flag/with_trap_exit_flag.rs

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use liblumen_alloc::erts::term::{atom_unchecked, Term};
66
use crate::otp::erlang;
77
use crate::process;
88
use crate::scheduler::Scheduler;
9-
use crate::test::has_message;
9+
use crate::test::{has_message, has_no_message};
1010

1111
#[test]
1212
fn without_boolean_value_errors_badarg() {
@@ -53,6 +53,91 @@ fn with_true_value_then_boolean_value_returns_old_value_true() {
5353
.unwrap();
5454
}
5555

56+
#[test]
57+
fn with_true_value_with_linked_and_does_not_exit_when_linked_process_exits_normal() {
58+
with_process(|process| {
59+
let other_arc_process = process::test(process);
60+
61+
process.link(&other_arc_process);
62+
63+
assert_eq!(native(process, flag(), true.into()), Ok(false.into()));
64+
65+
assert!(Scheduler::current().run_through(&other_arc_process));
66+
67+
assert!(!other_arc_process.is_exiting());
68+
assert!(!process.is_exiting());
69+
70+
let reason = atom_unchecked("normal");
71+
72+
erlang::exit_1::place_frame_with_arguments(&other_arc_process, Placement::Replace, reason)
73+
.unwrap();
74+
75+
assert!(Scheduler::current().run_through(&other_arc_process));
76+
77+
assert!(other_arc_process.is_exiting());
78+
assert!(!process.is_exiting());
79+
assert!(has_no_message(process));
80+
});
81+
}
82+
83+
#[test]
84+
fn with_true_value_with_linked_and_does_not_exit_when_linked_process_exits_shutdown() {
85+
with_process(|process| {
86+
let other_arc_process = process::test(process);
87+
88+
process.link(&other_arc_process);
89+
90+
assert_eq!(native(process, flag(), true.into()), Ok(false.into()));
91+
92+
assert!(Scheduler::current().run_through(&other_arc_process));
93+
94+
assert!(!other_arc_process.is_exiting());
95+
assert!(!process.is_exiting());
96+
97+
let reason = atom_unchecked("shutdown");
98+
99+
erlang::exit_1::place_frame_with_arguments(&other_arc_process, Placement::Replace, reason)
100+
.unwrap();
101+
102+
assert!(Scheduler::current().run_through(&other_arc_process));
103+
104+
assert!(other_arc_process.is_exiting());
105+
assert!(!process.is_exiting());
106+
assert!(has_no_message(process));
107+
});
108+
}
109+
110+
#[test]
111+
fn with_true_value_with_linked_and_does_not_exit_when_linked_process_exits_with_shutdown_tuple() {
112+
with_process(|process| {
113+
let other_arc_process = process::test(process);
114+
115+
process.link(&other_arc_process);
116+
117+
assert_eq!(native(process, flag(), true.into()), Ok(false.into()));
118+
119+
assert!(Scheduler::current().run_through(&other_arc_process));
120+
121+
assert!(!other_arc_process.is_exiting());
122+
assert!(!process.is_exiting());
123+
124+
let tag = atom_unchecked("shutdown");
125+
let shutdown_reason = atom_unchecked("shutdown_reason");
126+
let reason = other_arc_process
127+
.tuple_from_slice(&[tag, shutdown_reason])
128+
.unwrap();
129+
130+
erlang::exit_1::place_frame_with_arguments(&other_arc_process, Placement::Replace, reason)
131+
.unwrap();
132+
133+
assert!(Scheduler::current().run_through(&other_arc_process));
134+
135+
assert!(other_arc_process.is_exiting());
136+
assert!(!process.is_exiting());
137+
assert!(has_no_message(process));
138+
});
139+
}
140+
56141
#[test]
57142
fn with_true_value_with_linked_receive_exit_message_and_does_not_exit_when_linked_process_exits() {
58143
with_process(|process| {

0 commit comments

Comments
 (0)