transaction_ptr.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. use {
  2. agave_scheduler_bindings::{SharableTransactionBatchRegion, SharableTransactionRegion},
  3. agave_transaction_view::transaction_data::TransactionData,
  4. core::ptr::NonNull,
  5. rts_alloc::Allocator,
  6. };
  7. pub struct TransactionPtr {
  8. ptr: NonNull<u8>,
  9. len: usize,
  10. }
  11. impl TransactionData for TransactionPtr {
  12. fn data(&self) -> &[u8] {
  13. unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
  14. }
  15. }
  16. impl TransactionPtr {
  17. /// # Safety
  18. /// - `sharable_transaction_region` must reference a valid offset and length
  19. /// within the `allocator`.
  20. pub unsafe fn from_sharable_transaction_region(
  21. sharable_transaction_region: &SharableTransactionRegion,
  22. allocator: &Allocator,
  23. ) -> Self {
  24. let ptr = allocator.ptr_from_offset(sharable_transaction_region.offset);
  25. Self {
  26. ptr,
  27. len: sharable_transaction_region.length as usize,
  28. }
  29. }
  30. /// Translate the ptr type into a sharable region.
  31. ///
  32. /// # Safety
  33. /// - `allocator` must be the allocator owning the memory region pointed
  34. /// to by `self`.
  35. pub unsafe fn to_sharable_transaction_region(
  36. &self,
  37. allocator: &Allocator,
  38. ) -> SharableTransactionRegion {
  39. // SAFETY: The `TransactionPtr` creation `Self::from_sharable_transaction_region`
  40. // is already conditioned on the offset being valid, if that safety constraint
  41. // was satisfied translation back to offset is safe.
  42. let offset = unsafe { allocator.offset(self.ptr) };
  43. SharableTransactionRegion {
  44. offset,
  45. length: self.len as u32,
  46. }
  47. }
  48. /// Frees the memory region pointed to in the `allocator`.
  49. /// This should only be called by the owner of the memory
  50. /// i.e. the external scheduler.
  51. ///
  52. /// # Safety
  53. /// - Data region pointed to by `TransactionPtr` belongs to the `allocator`.
  54. /// - Inner `ptr` must not have been previously freed.
  55. pub unsafe fn free(self, allocator: &Allocator) {
  56. unsafe { allocator.free(self.ptr) }
  57. }
  58. }
  59. /// A batch of transaction pointers that can be iterated over.
  60. pub struct TransactionPtrBatch<'a> {
  61. ptr: NonNull<SharableTransactionRegion>,
  62. num_transactions: usize,
  63. allocator: &'a Allocator,
  64. }
  65. impl<'a> TransactionPtrBatch<'a> {
  66. /// # Safety
  67. /// - [`SharableTransactionBatchRegion`] must reference a valid offset and length
  68. /// within the `allocator`.
  69. /// - ALL [`SharableTransactionRegion`] within the batch must be valid.
  70. /// See [`TransactionPtr::from_sharable_transaction_region`] for details.
  71. pub unsafe fn from_sharable_transaction_batch_region(
  72. sharable_transaction_batch_region: &SharableTransactionBatchRegion,
  73. allocator: &'a Allocator,
  74. ) -> Self {
  75. let ptr = allocator
  76. .ptr_from_offset(sharable_transaction_batch_region.transactions_offset)
  77. .cast();
  78. Self {
  79. ptr,
  80. num_transactions: usize::from(sharable_transaction_batch_region.num_transactions),
  81. allocator,
  82. }
  83. }
  84. /// Iterator returning [`TransactionPtr`] for each transaction in the batch.
  85. pub fn iter(&'a self) -> impl Iterator<Item = TransactionPtr> + 'a {
  86. (0..self.num_transactions)
  87. .map(|idx| unsafe { self.ptr.add(idx) })
  88. .map(|ptr| unsafe {
  89. TransactionPtr::from_sharable_transaction_region(ptr.as_ref(), self.allocator)
  90. })
  91. }
  92. /// Free all transactions in the batch, then free the batch itself.
  93. pub fn free(self) {
  94. for transaction_ptr in self.iter() {
  95. unsafe { transaction_ptr.free(self.allocator) }
  96. }
  97. unsafe { self.allocator.free(self.ptr.cast()) }
  98. }
  99. }