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

Commit aeb75ec

Browse files
authored
Merge pull request #209 from lumen/process_flag_2
:erlang.process_flag(:trap_exit, boolean)
2 parents 8f3374b + 3a490a1 commit aeb75ec

File tree

77 files changed

+734
-320
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+734
-320
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: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub struct ProcessControlBlock {
7272
/// The priority of the process in `scheduler`.
7373
pub priority: Priority,
7474
/// Process flags, e.g. `Process.flag/1`
75-
flags: AtomicProcessFlag,
75+
flags: AtomicProcessFlags,
7676
/// Minimum size of the heap that this process will start with
7777
min_heap_size: usize,
7878
/// The maximum size of the heap allowed for this process
@@ -122,7 +122,7 @@ impl ProcessControlBlock {
122122
let pid = pid::next();
123123

124124
Self {
125-
flags: AtomicProcessFlag::new(ProcessFlag::Default),
125+
flags: AtomicProcessFlags::new(ProcessFlags::Default),
126126
min_heap_size: heap_size,
127127
max_heap_size: 0,
128128
min_vheap_size: 0,
@@ -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: ProcessFlag) {
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: ProcessFlag) {
171-
self.flags.clear(flags);
174+
pub fn clear_flags(&self, flags: ProcessFlags) -> ProcessFlags {
175+
self.flags.clear(flags)
176+
}
177+
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)
172188
}
173189

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
///
@@ -336,11 +358,7 @@ impl ProcessControlBlock {
336358

337359
// Send
338360

339-
pub fn send_heap_message(
340-
&self,
341-
heap_fragment: NonNull<HeapFragment>,
342-
data: Term,
343-
) -> Result<(), Alloc> {
361+
pub fn send_heap_message(&self, heap_fragment: NonNull<HeapFragment>, data: Term) {
344362
let heap_fragment_ptr = heap_fragment.as_ptr();
345363

346364
let off_heap_unsafe_ref_heap_fragment = unsafe { UnsafeRef::from_raw(heap_fragment_ptr) };
@@ -353,27 +371,32 @@ impl ProcessControlBlock {
353371
self.send_message(Message::HeapFragment(message::HeapFragment {
354372
unsafe_ref_heap_fragment: message_unsafe_ref_heap_fragment,
355373
data,
356-
}))
374+
}));
357375
}
358376

359-
pub fn send_from_self(&self, data: Term) -> Result<(), Alloc> {
360-
self.send_message(Message::Process(message::Process { data }))
377+
pub fn send_from_self(&self, data: Term) {
378+
self.send_message(Message::Process(message::Process { data }));
361379
}
362380

363381
/// Returns `true` if the process should stop waiting and be rescheduled as runnable.
364382
pub fn send_from_other(&self, data: Term) -> Result<bool, Alloc> {
365383
match self.heap.try_lock() {
366-
Some(ref mut destination_heap) => {
367-
let destination_data = data.clone_to_heap(destination_heap)?;
368-
369-
self.send_message(Message::Process(message::Process {
370-
data: destination_data,
371-
}))?;
372-
}
384+
Some(ref mut destination_heap) => match data.clone_to_heap(destination_heap) {
385+
Ok(destination_data) => {
386+
self.send_message(Message::Process(message::Process {
387+
data: destination_data,
388+
}));
389+
}
390+
Err(_) => {
391+
let (heap_fragment_data, heap_fragment) = data.clone_to_fragment()?;
392+
393+
self.send_heap_message(heap_fragment, heap_fragment_data);
394+
}
395+
},
373396
None => {
374397
let (heap_fragment_data, heap_fragment) = data.clone_to_fragment()?;
375398

376-
self.send_heap_message(heap_fragment, heap_fragment_data)?;
399+
self.send_heap_message(heap_fragment, heap_fragment_data);
377400
}
378401
}
379402

@@ -391,10 +414,8 @@ impl ProcessControlBlock {
391414
}
392415
}
393416

394-
fn send_message(&self, message: Message) -> Result<(), Alloc> {
395-
self.mailbox.lock().borrow_mut().push(message);
396-
397-
Ok(())
417+
fn send_message(&self, message: Message) {
418+
self.mailbox.lock().borrow_mut().push(message)
398419
}
399420

400421
// Terms
@@ -626,22 +647,22 @@ impl ProcessControlBlock {
626647

627648
#[inline]
628649
fn is_gc_forced(&self) -> bool {
629-
self.flags.is_set(ProcessFlag::ForceGC)
650+
self.flags.are_set(ProcessFlags::ForceGC)
630651
}
631652

632653
#[inline(always)]
633654
fn is_gc_delayed(&self) -> bool {
634-
self.flags.is_set(ProcessFlag::DelayGC)
655+
self.flags.are_set(ProcessFlags::DelayGC)
635656
}
636657

637658
#[inline(always)]
638659
fn is_gc_disabled(&self) -> bool {
639-
self.flags.is_set(ProcessFlag::DisableGC)
660+
self.flags.are_set(ProcessFlags::DisableGC)
640661
}
641662

642663
#[inline(always)]
643664
fn needs_fullsweep(&self) -> bool {
644-
self.flags.is_set(ProcessFlag::NeedFullSweep)
665+
self.flags.are_set(ProcessFlags::NeedFullSweep)
645666
}
646667

647668
/// Performs a garbage collection, using the provided root set

liblumen_alloc/src/erts/process/flags.rs

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use core::sync::atomic::{AtomicU32, Ordering};
66
/// to combine multiple flags in one value.
77
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88
#[repr(transparent)]
9-
pub struct ProcessFlag(u32);
10-
impl ProcessFlag {
9+
pub struct ProcessFlags(u32);
10+
impl ProcessFlags {
1111
#![allow(non_upper_case_globals)]
1212

1313
/// The default value where no flags are set
@@ -23,93 +23,96 @@ impl ProcessFlag {
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
}
30-
impl Into<u32> for ProcessFlag {
34+
impl Into<u32> for ProcessFlags {
3135
#[inline]
3236
fn into(self) -> u32 {
3337
self.0
3438
}
3539
}
36-
impl From<u32> for ProcessFlag {
40+
impl From<u32> for ProcessFlags {
3741
#[inline]
3842
fn from(n: u32) -> Self {
39-
assert!(n <= Self::MAX_VALUE);
4043
Self(n)
4144
}
4245
}
43-
impl Not for ProcessFlag {
46+
impl Not for ProcessFlags {
4447
type Output = Self;
4548

4649
fn not(self) -> Self {
4750
Self(!self.0)
4851
}
4952
}
50-
impl BitOr for ProcessFlag {
53+
impl BitOr for ProcessFlags {
5154
type Output = Self;
5255

5356
fn bitor(self, rhs: Self) -> Self {
5457
Self(self.0 | rhs.0)
5558
}
5659
}
57-
impl BitOrAssign for ProcessFlag {
60+
impl BitOrAssign for ProcessFlags {
5861
fn bitor_assign(&mut self, rhs: Self) {
5962
self.0 |= rhs.0
6063
}
6164
}
62-
impl BitAnd for ProcessFlag {
65+
impl BitAnd for ProcessFlags {
6366
type Output = Self;
6467

6568
fn bitand(self, rhs: Self) -> Self {
6669
Self(self.0 & rhs.0)
6770
}
6871
}
69-
impl BitAndAssign for ProcessFlag {
72+
impl BitAndAssign for ProcessFlags {
7073
fn bitand_assign(&mut self, rhs: Self) {
7174
self.0 &= rhs.0
7275
}
7376
}
7477

7578
/// This type is a wrapper around `AtomicU32` and provides atomic
76-
/// semantics for the `ProcessFlag` enum type
79+
/// semantics for the `ProcessFlags` enum type
7780
#[repr(transparent)]
78-
pub struct AtomicProcessFlag(AtomicU32);
79-
impl AtomicProcessFlag {
80-
/// Create a new `AtomicProcessFlag`
81+
pub struct AtomicProcessFlags(AtomicU32);
82+
impl AtomicProcessFlags {
83+
/// Create a new `AtomicProcessFlags`
8184
#[inline]
82-
pub fn new(flag: ProcessFlag) -> Self {
85+
pub fn new(flag: ProcessFlags) -> Self {
8386
Self(AtomicU32::new(flag.into()))
8487
}
8588

8689
/// Fetch the current value, with the given `Ordering`
8790
#[inline]
88-
pub fn load(&self, ordering: Ordering) -> ProcessFlag {
91+
pub fn load(&self, ordering: Ordering) -> ProcessFlags {
8992
self.0.load(ordering).into()
9093
}
9194

9295
/// Fetch the current value, using `Relaxed` ordering
9396
#[inline]
94-
pub fn get(&self) -> ProcessFlag {
97+
pub fn get(&self) -> ProcessFlags {
9598
self.0.load(Ordering::Relaxed).into()
9699
}
97100

98101
/// Check if the current value contains the given flags, uses `Relaxed` ordering
99102
#[inline]
100-
pub fn is_set(&self, flags: ProcessFlag) -> bool {
103+
pub fn are_set(&self, flags: ProcessFlags) -> bool {
101104
self.get() & flags == flags
102105
}
103106

104107
/// Set the given flags, uses `AcqRel` ordering
105108
#[inline]
106-
pub fn set(&self, flags: ProcessFlag) -> ProcessFlag {
109+
pub fn set(&self, flags: ProcessFlags) -> ProcessFlags {
107110
self.0.fetch_or(flags.into(), Ordering::AcqRel).into()
108111
}
109112

110113
/// Clear the given flags, uses `AcqRel` ordering
111114
#[inline]
112-
pub fn clear(&self, flags: ProcessFlag) -> ProcessFlag {
115+
pub fn clear(&self, flags: ProcessFlags) -> ProcessFlags {
113116
let cleared = !flags;
114117
self.0.fetch_and(cleared.into(), Ordering::AcqRel).into()
115118
}
@@ -121,34 +124,34 @@ mod tests {
121124

122125
#[test]
123126
fn process_flag_test() {
124-
let mut flags = ProcessFlag::Default;
127+
let mut flags = ProcessFlags::Default;
125128
// Set fullsweep
126-
flags |= ProcessFlag::NeedFullSweep;
127-
assert!(flags & ProcessFlag::NeedFullSweep == ProcessFlag::NeedFullSweep);
129+
flags |= ProcessFlags::NeedFullSweep;
130+
assert!(flags & ProcessFlags::NeedFullSweep == ProcessFlags::NeedFullSweep);
128131
// Set force_gc
129-
flags |= ProcessFlag::ForceGC;
130-
assert!(flags & ProcessFlag::NeedFullSweep == ProcessFlag::NeedFullSweep);
131-
assert!(flags & ProcessFlag::ForceGC == ProcessFlag::ForceGC);
132+
flags |= ProcessFlags::ForceGC;
133+
assert!(flags & ProcessFlags::NeedFullSweep == ProcessFlags::NeedFullSweep);
134+
assert!(flags & ProcessFlags::ForceGC == ProcessFlags::ForceGC);
132135
// Ensure we can check multiple flags at once
133-
let checking = ProcessFlag::ForceGC | ProcessFlag::NeedFullSweep;
136+
let checking = ProcessFlags::ForceGC | ProcessFlags::NeedFullSweep;
134137
assert!(flags & checking == checking);
135138
// Clear force_gc
136-
flags &= !ProcessFlag::ForceGC;
137-
assert!(flags & ProcessFlag::ForceGC != ProcessFlag::ForceGC);
138-
assert!(flags & ProcessFlag::NeedFullSweep == ProcessFlag::NeedFullSweep);
139+
flags &= !ProcessFlags::ForceGC;
140+
assert!(flags & ProcessFlags::ForceGC != ProcessFlags::ForceGC);
141+
assert!(flags & ProcessFlags::NeedFullSweep == ProcessFlags::NeedFullSweep);
139142
}
140143

141144
#[test]
142145
fn atomic_process_flag_test() {
143-
let flags = AtomicProcessFlag::new(ProcessFlag::Default);
144-
flags.set(ProcessFlag::NeedFullSweep);
145-
assert!(flags.is_set(ProcessFlag::NeedFullSweep));
146-
flags.set(ProcessFlag::ForceGC);
147-
assert!(flags.is_set(ProcessFlag::NeedFullSweep));
148-
assert!(flags.is_set(ProcessFlag::ForceGC));
149-
assert!(flags.is_set(ProcessFlag::ForceGC | ProcessFlag::NeedFullSweep));
150-
flags.clear(ProcessFlag::ForceGC);
151-
assert!(flags.is_set(ProcessFlag::NeedFullSweep));
152-
assert!(!flags.is_set(ProcessFlag::ForceGC));
146+
let flags = AtomicProcessFlags::new(ProcessFlags::Default);
147+
flags.set(ProcessFlags::NeedFullSweep);
148+
assert!(flags.are_set(ProcessFlags::NeedFullSweep));
149+
flags.set(ProcessFlags::ForceGC);
150+
assert!(flags.are_set(ProcessFlags::NeedFullSweep));
151+
assert!(flags.are_set(ProcessFlags::ForceGC));
152+
assert!(flags.are_set(ProcessFlags::ForceGC | ProcessFlags::NeedFullSweep));
153+
flags.clear(ProcessFlags::ForceGC);
154+
assert!(flags.are_set(ProcessFlags::NeedFullSweep));
155+
assert!(!flags.are_set(ProcessFlags::ForceGC));
153156
}
154157
}

0 commit comments

Comments
 (0)