1use core::fmt;
10use core::sync::atomic::{Ordering, compiler_fence};
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum NativePlatform {
15 Linux,
17 MacOs,
19 Windows,
21}
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
25pub enum NativeArchitecture {
26 Arm64,
28 Amd64,
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub enum AuthorityMechanism {
35 DescriptorSeals,
37 MaximumPortRights,
39 ExactHandleRights,
41}
42
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub struct NativeMemoryCapabilities {
46 platform: NativePlatform,
47 architecture: NativeArchitecture,
48 authority: AuthorityMechanism,
49}
50
51impl NativeMemoryCapabilities {
52 pub const fn platform(self) -> NativePlatform {
54 self.platform
55 }
56
57 pub const fn architecture(self) -> NativeArchitecture {
59 self.architecture
60 }
61
62 pub const fn authority_mechanism(self) -> AuthorityMechanism {
64 self.authority
65 }
66
67 pub const fn supports_replacement_growth(self) -> bool {
69 true
70 }
71
72 pub const fn supports_in_place_growth(self) -> bool {
74 false
75 }
76
77 pub const fn supports_post_share_permission_changes(self) -> bool {
79 false
80 }
81
82 pub const fn releases_on_drop(self) -> bool {
84 true
85 }
86}
87
88pub const fn native_memory_capabilities() -> NativeMemoryCapabilities {
90 NativeMemoryCapabilities {
91 platform: native_platform(),
92 architecture: native_architecture(),
93 authority: authority_mechanism(),
94 }
95}
96
97#[derive(Clone, Copy, Debug, Eq, PartialEq)]
99pub enum WriterOwner {
100 Creator,
102 Peer,
104}
105
106#[derive(Clone, Copy, Debug, Eq, PartialEq)]
108pub enum MemoryAccess {
109 ReadOnly,
111 ReadWrite,
113}
114
115#[derive(Clone, Copy, Debug, Eq, PartialEq)]
117pub struct PermissionPlan {
118 writer: WriterOwner,
119}
120
121impl PermissionPlan {
122 pub const fn new(writer: WriterOwner) -> Self {
124 Self { writer }
125 }
126
127 pub const fn writer(self) -> WriterOwner {
129 self.writer
130 }
131
132 pub const fn creator_access(self) -> MemoryAccess {
134 match self.writer {
135 WriterOwner::Creator => MemoryAccess::ReadWrite,
136 WriterOwner::Peer => MemoryAccess::ReadOnly,
137 }
138 }
139
140 pub const fn peer_access(self) -> MemoryAccess {
142 match self.writer {
143 WriterOwner::Creator => MemoryAccess::ReadOnly,
144 WriterOwner::Peer => MemoryAccess::ReadWrite,
145 }
146 }
147
148 pub const fn library_view_executable(self) -> bool {
153 false
154 }
155}
156
157#[derive(Clone, Copy, Debug, Eq, PartialEq)]
159pub enum GrowthPolicy {
160 Fixed,
162 ReplaceBeforeShare {
164 maximum_len: usize,
166 },
167}
168
169#[derive(Clone, Copy, Debug, Eq, PartialEq)]
171pub enum CleanupPolicy {
172 ReleaseOnDrop,
174 ClearThenRelease,
176}
177
178#[derive(Clone, Copy, Debug, Eq, PartialEq)]
180pub enum SealPolicy {
181 RequiredOnShare,
183}
184
185#[derive(Clone, Copy, Debug, Eq, PartialEq)]
187pub struct RegionOptions {
188 logical_len: usize,
189 growth: GrowthPolicy,
190 cleanup: CleanupPolicy,
191 permissions: PermissionPlan,
192 seal: SealPolicy,
193}
194
195impl RegionOptions {
196 pub const fn fixed(logical_len: usize, writer: WriterOwner) -> Self {
198 Self {
199 logical_len,
200 growth: GrowthPolicy::Fixed,
201 cleanup: CleanupPolicy::ClearThenRelease,
202 permissions: PermissionPlan::new(writer),
203 seal: SealPolicy::RequiredOnShare,
204 }
205 }
206
207 pub const fn growable(logical_len: usize, maximum_len: usize, writer: WriterOwner) -> Self {
212 Self {
213 logical_len,
214 growth: GrowthPolicy::ReplaceBeforeShare { maximum_len },
215 cleanup: CleanupPolicy::ClearThenRelease,
216 permissions: PermissionPlan::new(writer),
217 seal: SealPolicy::RequiredOnShare,
218 }
219 }
220
221 pub const fn with_cleanup(mut self, cleanup: CleanupPolicy) -> Self {
223 self.cleanup = cleanup;
224 self
225 }
226
227 pub const fn logical_len(self) -> usize {
229 self.logical_len
230 }
231
232 pub const fn growth(self) -> GrowthPolicy {
234 self.growth
235 }
236
237 pub const fn cleanup(self) -> CleanupPolicy {
239 self.cleanup
240 }
241
242 pub const fn permissions(self) -> PermissionPlan {
244 self.permissions
245 }
246
247 pub const fn seal(self) -> SealPolicy {
249 self.seal
250 }
251
252 pub const fn maximum_len(self) -> usize {
254 match self.growth {
255 GrowthPolicy::Fixed => self.logical_len,
256 GrowthPolicy::ReplaceBeforeShare { maximum_len } => maximum_len,
257 }
258 }
259}
260
261#[derive(Clone, Copy, Debug, Eq, PartialEq)]
263pub enum RegionState {
264 Quiescent,
266}
267
268#[derive(Clone, Copy, Debug, Eq, PartialEq)]
270pub struct RegionStatus {
271 pub state: RegionState,
273 pub logical_len: usize,
275 pub mapped_len: usize,
277 pub maximum_len: usize,
279 pub can_grow: bool,
281 pub permissions: PermissionPlan,
283 pub cleanup: CleanupPolicy,
285 pub seal: SealPolicy,
287}
288
289#[derive(Debug)]
291pub enum MemoryError {
292 ZeroLength,
294 MaximumBelowInitial {
296 initial: usize,
298 maximum: usize,
300 },
301 FixedSize,
303 ShrinkUnsupported {
305 current: usize,
307 requested: usize,
309 },
310 MaximumExceeded {
312 requested: usize,
314 maximum: usize,
316 },
317 Platform {
319 operation: &'static str,
321 },
322 RandomnessUnavailable,
324}
325
326impl fmt::Display for MemoryError {
327 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
328 write!(formatter, "native shared-memory operation failed: {self:?}")
329 }
330}
331
332impl std::error::Error for MemoryError {
333 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
334 None
335 }
336}
337
338#[cfg(target_os = "linux")]
339impl From<crate::backend::linux::LinuxError> for MemoryError {
340 fn from(_: crate::backend::linux::LinuxError) -> Self {
341 Self::Platform {
342 operation: "allocate",
343 }
344 }
345}
346
347#[cfg(target_os = "macos")]
348impl From<crate::backend::macos::MachError> for MemoryError {
349 fn from(_: crate::backend::macos::MachError) -> Self {
350 Self::Platform {
351 operation: "allocate",
352 }
353 }
354}
355
356#[cfg(target_os = "windows")]
357impl From<crate::backend::windows::WindowsError> for MemoryError {
358 fn from(_: crate::backend::windows::WindowsError) -> Self {
359 Self::Platform {
360 operation: "allocate",
361 }
362 }
363}
364
365pub struct NativeRegion {
373 inner: Option<PlatformQuiescentRegion>,
374 logical_len: usize,
375 options: RegionOptions,
376}
377
378impl NativeRegion {
379 pub fn allocate(options: RegionOptions) -> Result<Self, MemoryError> {
384 validate_options(options)?;
385 let inner = PlatformQuiescentRegion::new(options.logical_len())?;
386 Ok(Self {
387 inner: Some(inner),
388 logical_len: options.logical_len(),
389 options,
390 })
391 }
392
393 pub const fn options(&self) -> RegionOptions {
395 self.options
396 }
397
398 pub fn status(&self) -> RegionStatus {
400 let maximum_len = self.options.maximum_len();
401 RegionStatus {
402 state: RegionState::Quiescent,
403 logical_len: self.logical_len,
404 mapped_len: self.inner().len(),
405 maximum_len,
406 can_grow: matches!(
407 self.options.growth(),
408 GrowthPolicy::ReplaceBeforeShare { .. }
409 ) && self.logical_len < maximum_len,
410 permissions: self.options.permissions(),
411 cleanup: self.options.cleanup(),
412 seal: self.options.seal(),
413 }
414 }
415
416 pub fn initialize<R>(&mut self, operation: impl FnOnce(&mut [u8]) -> R) -> R {
421 let logical_len = self.logical_len;
422 operation(&mut self.inner_mut().as_bytes_mut()[..logical_len])
423 }
424
425 pub fn clear(&mut self) {
430 clear_mapping(self.inner_mut());
431 }
432
433 pub fn grow(&mut self, requested: usize) -> Result<(), MemoryError> {
435 if requested == 0 {
436 return Err(MemoryError::ZeroLength);
437 }
438 if requested < self.logical_len {
439 return Err(MemoryError::ShrinkUnsupported {
440 current: self.logical_len,
441 requested,
442 });
443 }
444 if requested == self.logical_len {
445 return Ok(());
446 }
447 let maximum = match self.options.growth() {
448 GrowthPolicy::Fixed => return Err(MemoryError::FixedSize),
449 GrowthPolicy::ReplaceBeforeShare { maximum_len } => maximum_len,
450 };
451 if requested > maximum {
452 return Err(MemoryError::MaximumExceeded { requested, maximum });
453 }
454
455 let mut replacement = PlatformQuiescentRegion::new(requested)?;
456 replacement.as_bytes_mut()[..self.logical_len]
457 .copy_from_slice(&self.inner().as_bytes()[..self.logical_len]);
458 let mut previous = self
459 .inner
460 .replace(replacement)
461 .expect("managed region always owns its mapping");
462 if self.options.cleanup() == CleanupPolicy::ClearThenRelease {
463 clear_mapping(&mut previous);
464 }
465 self.logical_len = requested;
466 Ok(())
467 }
468
469 pub fn close(mut self) {
471 self.release();
472 }
473
474 pub fn destroy(mut self) {
481 if let Some(inner) = self.inner.as_mut() {
482 clear_mapping(inner);
483 }
484 drop(self.inner.take());
485 }
486
487 pub fn prepare_for_sharing(mut self) -> Result<NativeShareRequest, MemoryError> {
501 let incarnation =
502 crate::backend::mint_incarnation().map_err(|()| MemoryError::RandomnessUnavailable)?;
503 Ok(NativeShareRequest {
504 inner: self.inner.take(),
505 incarnation,
506 logical_len: self.logical_len,
507 permissions: self.options.permissions(),
508 seal: self.options.seal(),
509 cleanup: self.options.cleanup(),
510 })
511 }
512
513 pub(crate) fn prepare_with_writer(
514 mut self,
515 writer: WriterOwner,
516 ) -> Result<NativeShareRequest, MemoryError> {
517 self.options.permissions = PermissionPlan::new(writer);
518 self.prepare_for_sharing()
519 }
520
521 fn inner(&self) -> &PlatformQuiescentRegion {
522 self.inner
523 .as_ref()
524 .expect("managed region always owns its mapping")
525 }
526
527 fn inner_mut(&mut self) -> &mut PlatformQuiescentRegion {
528 self.inner
529 .as_mut()
530 .expect("managed region always owns its mapping")
531 }
532
533 fn release(&mut self) {
534 if let Some(inner) = self.inner.as_mut()
535 && self.options.cleanup() == CleanupPolicy::ClearThenRelease
536 {
537 clear_mapping(inner);
538 }
539 drop(self.inner.take());
540 }
541}
542
543pub struct NativeShareRequest {
559 inner: Option<PlatformQuiescentRegion>,
560 #[allow(dead_code)]
561 incarnation: [u8; 16],
562 logical_len: usize,
563 permissions: PermissionPlan,
564 seal: SealPolicy,
565 cleanup: CleanupPolicy,
566}
567
568impl NativeShareRequest {
569 pub const fn permissions(&self) -> PermissionPlan {
571 self.permissions
572 }
573
574 pub const fn seal_policy(&self) -> SealPolicy {
576 self.seal
577 }
578
579 pub fn mapped_len(&self) -> usize {
581 self.inner
582 .as_ref()
583 .expect("share request always owns its mapping")
584 .len()
585 }
586
587 #[allow(dead_code)]
588 pub(crate) const fn logical_len(&self) -> usize {
589 self.logical_len
590 }
591
592 #[allow(dead_code)]
593 pub(crate) const fn incarnation(&self) -> [u8; 16] {
594 self.incarnation
595 }
596
597 #[allow(dead_code)]
598 pub(crate) fn native_spec(&self, region_id: u128) -> Option<crate::protocol::NativeRegionSpec> {
599 crate::protocol::NativeRegionSpec::new(
600 region_id,
601 self.incarnation,
602 self.permissions.writer() as u32,
603 self.logical_len,
604 self.mapped_len(),
605 )
606 }
607
608 #[cfg(target_os = "linux")]
609 pub(crate) fn into_linux_quiescent(
610 mut self,
611 ) -> (crate::backend::linux::QuiescentRegion, CleanupPolicy) {
612 let inner = self
613 .inner
614 .take()
615 .expect("share request always owns its mapping");
616 (inner, self.cleanup)
617 }
618
619 #[cfg(target_os = "macos")]
620 pub(crate) fn into_macos_quiescent(
621 mut self,
622 ) -> (crate::backend::macos::QuiescentRegion, CleanupPolicy) {
623 let inner = self
624 .inner
625 .take()
626 .expect("share request always owns its mapping");
627 (inner, self.cleanup)
628 }
629
630 #[cfg(target_os = "windows")]
631 pub(crate) fn into_windows_quiescent(
632 mut self,
633 ) -> (crate::backend::windows::QuiescentRegion, CleanupPolicy) {
634 let inner = self
635 .inner
636 .take()
637 .expect("share request always owns its mapping");
638 (inner, self.cleanup)
639 }
640
641 pub fn destroy(mut self) {
643 if let Some(inner) = self.inner.as_mut() {
644 clear_mapping(inner);
645 }
646 drop(self.inner.take());
647 }
648
649 fn release(&mut self) {
650 if let Some(inner) = self.inner.as_mut()
651 && self.cleanup == CleanupPolicy::ClearThenRelease
652 {
653 clear_mapping(inner);
654 }
655 drop(self.inner.take());
656 }
657}
658
659impl Drop for NativeShareRequest {
660 fn drop(&mut self) {
661 self.release();
662 }
663}
664
665fn clear_mapping(region: &mut PlatformQuiescentRegion) {
666 for byte in region.as_bytes_mut() {
667 unsafe { core::ptr::write_volatile(byte, 0) };
670 }
671 compiler_fence(Ordering::SeqCst);
672}
673
674impl Drop for NativeRegion {
675 fn drop(&mut self) {
676 self.release();
677 }
678}
679
680fn validate_options(options: RegionOptions) -> Result<(), MemoryError> {
681 if options.logical_len() == 0 {
682 return Err(MemoryError::ZeroLength);
683 }
684 let maximum = options.maximum_len();
685 if maximum < options.logical_len() {
686 return Err(MemoryError::MaximumBelowInitial {
687 initial: options.logical_len(),
688 maximum,
689 });
690 }
691 Ok(())
692}
693
694#[cfg(target_os = "linux")]
695pub(crate) type PlatformQuiescentRegion = crate::backend::linux::QuiescentRegion;
697#[cfg(target_os = "macos")]
698pub(crate) type PlatformQuiescentRegion = crate::backend::macos::QuiescentRegion;
700
701#[cfg(target_os = "windows")]
702pub(crate) type PlatformQuiescentRegion = crate::backend::windows::QuiescentRegion;
704#[cfg(target_os = "linux")]
705const fn native_platform() -> NativePlatform {
706 NativePlatform::Linux
707}
708#[cfg(target_os = "macos")]
709const fn native_platform() -> NativePlatform {
710 NativePlatform::MacOs
711}
712#[cfg(target_os = "windows")]
713const fn native_platform() -> NativePlatform {
714 NativePlatform::Windows
715}
716
717#[cfg(target_arch = "aarch64")]
718const fn native_architecture() -> NativeArchitecture {
719 NativeArchitecture::Arm64
720}
721
722#[cfg(target_arch = "x86_64")]
723const fn native_architecture() -> NativeArchitecture {
724 NativeArchitecture::Amd64
725}
726
727#[cfg(target_os = "linux")]
728const fn authority_mechanism() -> AuthorityMechanism {
729 AuthorityMechanism::DescriptorSeals
730}
731#[cfg(target_os = "macos")]
732const fn authority_mechanism() -> AuthorityMechanism {
733 AuthorityMechanism::MaximumPortRights
734}
735#[cfg(target_os = "windows")]
736const fn authority_mechanism() -> AuthorityMechanism {
737 AuthorityMechanism::ExactHandleRights
738}
739
740#[cfg(test)]
741#[path = "memory_test.rs"]
742mod tests;