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

Commit 3cff054

Browse files
committed
:erlang.process_flag(:trap_exit, boolean)
1 parent 68bbeb1 commit 3cff054

File tree

17 files changed

+529
-105
lines changed

17 files changed

+529
-105
lines changed

liblumen_alloc/src/borrow/clone_to_process.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use core::alloc::Layout;
21
use core::mem;
32
use core::ptr::NonNull;
43

@@ -45,12 +44,8 @@ pub trait CloneToProcess {
4544
///
4645
/// If unable to allocate a heap fragment that fits this value, `Err(Alloc)` is returned
4746
fn clone_to_fragment(&self) -> Result<(Term, NonNull<HeapFragment>), Alloc> {
48-
let need = self.size_in_words();
49-
let layout = unsafe {
50-
let size = need * mem::size_of::<usize>();
51-
Layout::from_size_align_unchecked(size, mem::align_of::<Term>())
52-
};
53-
let mut frag = unsafe { HeapFragment::new(layout)? };
47+
let word_size = self.size_in_words();
48+
let mut frag = unsafe { HeapFragment::new_from_word_size(word_size)? };
5449
let frag_ref = unsafe { frag.as_mut() };
5550
let term = self.clone_to_heap(frag_ref)?;
5651
Ok((term, frag))

liblumen_alloc/src/erts/fragment.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use intrusive_collections::{LinkedListLink, UnsafeRef};
77
use liblumen_core::util::pointer::{distance_absolute, in_area};
88

99
use crate::erts::exception::system::Alloc;
10-
use crate::erts::term::Term;
10+
use crate::erts::term::{layout_from_word_size, Term, Tuple};
1111
use crate::std_alloc;
1212

1313
use super::HeapAlloc;
@@ -97,6 +97,22 @@ impl HeapFragment {
9797
);
9898
Ok(NonNull::new_unchecked(ptr))
9999
}
100+
101+
pub unsafe fn new_from_word_size(word_size: usize) -> Result<NonNull<Self>, Alloc> {
102+
let layout = layout_from_word_size(word_size);
103+
104+
Self::new(layout)
105+
}
106+
107+
/// Creates a new `HeapFragment` that can hold a tuple
108+
pub fn tuple_from_slice(elements: &[Term]) -> Result<(Term, NonNull<HeapFragment>), Alloc> {
109+
let need_in_words = Tuple::need_in_words_from_elements(elements);
110+
let mut non_null_heap_fragment = unsafe { Self::new_from_word_size(need_in_words)? };
111+
let heap_fragment = unsafe { non_null_heap_fragment.as_mut() };
112+
let term = Tuple::clone_to_heap_from_elements(heap_fragment, elements)?;
113+
114+
Ok((term, non_null_heap_fragment))
115+
}
100116
}
101117
impl Drop for HeapFragment {
102118
fn drop(&mut self) {

liblumen_alloc/src/erts/process.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,40 @@ impl ProcessControlBlock {
159159

160160
// Flags
161161

162-
/// Set the given process flag
162+
pub fn are_flags_set(&self, flags: ProcessFlags) -> bool {
163+
self.flags.are_set(flags)
164+
}
165+
166+
/// Set the given process flags
163167
#[inline]
164-
pub fn set_flags(&self, flags: ProcessFlags) {
165-
self.flags.set(flags);
168+
pub fn set_flags(&self, flags: ProcessFlags) -> ProcessFlags {
169+
self.flags.set(flags)
166170
}
167171

168-
/// Unset the given process flag
172+
/// Unset the given process flags
169173
#[inline]
170-
pub fn clear_flags(&self, flags: ProcessFlags) {
171-
self.flags.clear(flags);
174+
pub fn clear_flags(&self, flags: ProcessFlags) -> ProcessFlags {
175+
self.flags.clear(flags)
172176
}
173177

178+
pub fn trap_exit(&self, value: bool) -> bool {
179+
let flag = ProcessFlags::TrapExit;
180+
181+
let old_flags = if value {
182+
self.set_flags(flag)
183+
} else {
184+
self.clear_flags(flag)
185+
};
186+
187+
old_flags.are_set(flag)
188+
}
189+
190+
pub fn traps_exit(&self) -> bool {
191+
self.are_flags_set(ProcessFlags::TrapExit)
192+
}
193+
194+
// Alloc
195+
174196
/// Acquires exclusive access to the process heap, blocking the current thread until it is able
175197
/// to do so.
176198
///

liblumen_alloc/src/erts/process/flags.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@ impl ProcessFlags {
2323
pub const DisableGC: Self = Self(1 << 4);
2424
/// This flag indicates that GC should be delayed temporarily
2525
pub const DelayGC: Self = Self(1 << 5);
26+
/// This flag indicates the processes linked to this process should send exit messages instead
27+
/// of causing this process to exit when they exit
28+
pub const TrapExit: Self = Self(1 << 6);
2629

27-
// Internal value used to validate conversions from raw u32 values
28-
const MAX_VALUE: u32 = 1 << 5;
30+
pub fn are_set(&self, flags: ProcessFlags) -> bool {
31+
(*self & flags) == flags
32+
}
2933
}
3034
impl Into<u32> for ProcessFlags {
3135
#[inline]
@@ -36,7 +40,6 @@ impl Into<u32> for ProcessFlags {
3640
impl From<u32> for ProcessFlags {
3741
#[inline]
3842
fn from(n: u32) -> Self {
39-
assert!(n <= Self::MAX_VALUE);
4043
Self(n)
4144
}
4245
}

liblumen_alloc/src/erts/process/heap.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ impl ProcessHeap {
6363
// Run the collector
6464
gc.collect(need)
6565
}
66+
67+
pub fn heap_available(&self) -> usize {
68+
self.young.unused()
69+
}
6670
}
6771
impl HeapAlloc for ProcessHeap {
6872
#[inline]

liblumen_alloc/src/erts/process/test.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,55 @@ fn gc_fullsweep_after_tenuring_test() {
4848
tenuring_gc_test(process, true);
4949
}
5050

51+
mod are_flags_set {
52+
use super::*;
53+
54+
#[test]
55+
fn trap_exit_is_not_set_by_default() {
56+
let process = process();
57+
58+
assert_eq!(process.are_flags_set(ProcessFlags::TrapExit), false);
59+
}
60+
}
61+
62+
mod trap_exit {
63+
use super::*;
64+
65+
#[test]
66+
fn returns_true_for_the_default_old_value() {
67+
let process = process();
68+
69+
assert_eq!(process.trap_exit(true), false);
70+
}
71+
72+
#[test]
73+
fn returns_old_value() {
74+
let process = process();
75+
76+
assert_eq!(process.trap_exit(true), false);
77+
assert_eq!(process.trap_exit(false), true);
78+
}
79+
}
80+
81+
mod traps_exit {
82+
use super::*;
83+
84+
#[test]
85+
fn returns_false_by_default() {
86+
let process = process();
87+
88+
assert_eq!(process.traps_exit(), false);
89+
}
90+
91+
#[test]
92+
fn returns_true_after_trap_exit_true() {
93+
let process = process();
94+
95+
assert_eq!(process.trap_exit(true), false);
96+
assert_eq!(process.traps_exit(), true);
97+
}
98+
}
99+
51100
mod integer {
52101
use super::*;
53102

liblumen_alloc/src/erts/term.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ pub use term::*;
2929
pub use tuple::*;
3030
pub use typed_term::*;
3131

32+
use core::alloc::Layout;
3233
use core::fmt;
34+
use core::mem;
3335
use core::str::Utf8Error;
3436

3537
use crate::erts::exception::system::Alloc;
@@ -204,15 +206,19 @@ pub(crate) fn follow_moved(term: Term) -> Term {
204206
/// needed to hold that number of bytes, rounding up if necessary
205207
#[inline]
206208
pub(crate) fn to_word_size(bytes: usize) -> usize {
207-
use core::mem;
208209
use liblumen_core::alloc::alloc_utils::round_up_to_multiple_of;
209210

210211
round_up_to_multiple_of(bytes, mem::size_of::<usize>()) / mem::size_of::<usize>()
211212
}
212213

214+
pub(crate) fn layout_from_word_size(word_size: usize) -> Layout {
215+
let byte_size = word_size * mem::size_of::<Term>();
216+
217+
unsafe { Layout::from_size_align_unchecked(byte_size, mem::align_of::<Term>()) }
218+
}
219+
213220
/// Returns the size in words required to hold the non-header fields of type `T`
214221
#[inline]
215222
pub(crate) fn arity_of<T: Sized>() -> usize {
216-
use core::mem;
217223
to_word_size(mem::size_of::<T>() - mem::size_of::<Term>())
218224
}

liblumen_alloc/src/erts/term/tuple.rs

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,39 @@ pub struct Tuple {
5656
header: Term,
5757
}
5858
impl Tuple {
59+
pub fn clone_to_heap_from_elements<A: HeapAlloc>(
60+
heap: &mut A,
61+
elements: &[Term],
62+
) -> Result<Term, Alloc> {
63+
// The result of calling this will be a Tuple with everything located
64+
// contiguously in memory
65+
unsafe {
66+
// Allocate the space needed for the header and all the elements
67+
let len = elements.len();
68+
let words = Self::need_in_words_from_len(len);
69+
70+
let tuple_ptr = heap.alloc(words)?.as_ptr() as *mut Self;
71+
// Write the header
72+
tuple_ptr.write(Tuple::new(len));
73+
74+
let mut element_ptr = tuple_ptr.offset(1) as *mut Term;
75+
// Write each element
76+
for element in elements {
77+
if element.is_immediate() {
78+
element_ptr.write(*element);
79+
} else {
80+
// Recursively call clone_to_heap, and then write the box header here
81+
let boxed = element.clone_to_heap(heap)?;
82+
element_ptr.write(boxed);
83+
}
84+
85+
element_ptr = element_ptr.offset(1);
86+
}
87+
88+
Ok(Term::make_boxed(tuple_ptr))
89+
}
90+
}
91+
5992
/// Create a new `Tuple` struct
6093
///
6194
/// NOTE: This does not allocate space for the tuple, it simply
@@ -91,10 +124,34 @@ impl Tuple {
91124
/// the memory needed by elements of the tuple
92125
#[inline]
93126
pub fn layout(num_elements: usize) -> Layout {
94-
let size = mem::size_of::<Self>() + (num_elements * mem::size_of::<Term>());
127+
let size = Self::need_in_bytes_from_len(num_elements);
95128
unsafe { Layout::from_size_align_unchecked(size, mem::align_of::<Term>()) }
96129
}
97130

131+
/// The number of bytes for the header and immediate terms or box term pointer to elements
132+
/// allocated elsewhere.
133+
pub fn need_in_bytes_from_len(len: usize) -> usize {
134+
mem::size_of::<Self>() + (len * mem::size_of::<Term>())
135+
}
136+
137+
/// The number of words for the header and immediate terms or box term pointer to elements
138+
/// allocated elsewhere.
139+
pub fn need_in_words_from_len(len: usize) -> usize {
140+
to_word_size(Self::need_in_bytes_from_len(len))
141+
}
142+
143+
/// The number of words for the header and immediate terms or box term pointer and the data
144+
/// the box is pointing to.
145+
pub fn need_in_words_from_elements(elements: &[Term]) -> usize {
146+
let mut words = Self::need_in_words_from_len(elements.len());
147+
148+
for element in elements {
149+
words += element.size_in_words();
150+
}
151+
152+
words
153+
}
154+
98155
/// Constructs an iterator over elements of the tuple
99156
#[inline]
100157
pub fn iter(&self) -> Iter {
@@ -185,47 +242,11 @@ unsafe impl AsTerm for Tuple {
185242
}
186243
impl CloneToProcess for Tuple {
187244
fn clone_to_heap<A: HeapAlloc>(&self, heap: &mut A) -> Result<Term, Alloc> {
188-
// The result of calling this will be a Tuple with everything located
189-
// contigously in memory
190-
unsafe {
191-
// Allocate the space needed for the header and all the elements
192-
let num_elements = self.len();
193-
let words =
194-
to_word_size(mem::size_of::<Self>() + (num_elements * mem::size_of::<Term>()));
195-
let ptr = heap.alloc(words)?.as_ptr() as *mut Self;
196-
// Get pointer to the old head element location
197-
let old_head = self.head();
198-
// Get pointer to the new head element location
199-
let head = ptr.add(1) as *mut Term;
200-
// Write the header
201-
ptr::write(
202-
ptr,
203-
Self {
204-
header: self.header,
205-
},
206-
);
207-
// Write each element
208-
for offset in 0..num_elements {
209-
let old = *old_head.add(offset);
210-
if old.is_immediate() {
211-
ptr::write(head.add(offset), old);
212-
} else {
213-
// Recursively call clone_to_process, and then write the box header here
214-
let boxed = old.clone_to_heap(heap)?;
215-
ptr::write(head.add(offset), boxed);
216-
}
217-
}
218-
Ok(Term::make_boxed(ptr))
219-
}
245+
Tuple::clone_to_heap_from_elements(heap, self)
220246
}
221247

222248
fn size_in_words(&self) -> usize {
223-
let elements = self.len();
224-
let mut words = to_word_size(mem::size_of::<Self>() + (elements * mem::size_of::<Term>()));
225-
for element in self.iter() {
226-
words += element.size_in_words();
227-
}
228-
words
249+
Self::need_in_words_from_elements(self)
229250
}
230251
}
231252

lumen_runtime/src/otp/erlang.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod exit_1;
77
pub mod link_1;
88
pub mod monotonic_time_0;
99
pub mod number_or_badarith_1;
10+
pub mod process_flag_2;
1011
pub mod self_0;
1112
pub mod send_2;
1213
pub mod spawn_3;

0 commit comments

Comments
 (0)