use crate::lwlock::*;
use crate::{pg_sys, PgAtomic};
use std::hash::Hash;
use uuid::Uuid;
pub unsafe trait PGRXSharedMemory {}
#[cfg(not(feature = "pg15"))]
#[macro_export]
macro_rules! pg_shmem_init {
($thing:expr) => {
$thing.pg_init();
unsafe {
static mut PREV_SHMEM_STARTUP_HOOK: Option<unsafe extern "C" fn()> = None;
PREV_SHMEM_STARTUP_HOOK = pg_sys::shmem_startup_hook;
pg_sys::shmem_startup_hook = Some(__pgrx_private_shmem_hook);
#[pg_guard]
extern "C" fn __pgrx_private_shmem_hook() {
unsafe {
if let Some(i) = PREV_SHMEM_STARTUP_HOOK {
i();
}
}
$thing.shmem_init();
}
}
};
}
#[cfg(feature = "pg15")]
#[macro_export]
macro_rules! pg_shmem_init {
($thing:expr) => {
unsafe {
static mut PREV_SHMEM_REQUEST_HOOK: Option<unsafe extern "C" fn()> = None;
PREV_SHMEM_REQUEST_HOOK = pg_sys::shmem_request_hook;
pg_sys::shmem_request_hook = Some(__pgrx_private_shmem_request_hook);
#[pg_guard]
extern "C" fn __pgrx_private_shmem_request_hook() {
unsafe {
if let Some(i) = PREV_SHMEM_REQUEST_HOOK {
i();
}
}
$thing.pg_init();
}
}
unsafe {
static mut PREV_SHMEM_STARTUP_HOOK: Option<unsafe extern "C" fn()> = None;
PREV_SHMEM_STARTUP_HOOK = pg_sys::shmem_startup_hook;
pg_sys::shmem_startup_hook = Some(__pgrx_private_shmem_hook);
#[pg_guard]
extern "C" fn __pgrx_private_shmem_hook() {
unsafe {
if let Some(i) = PREV_SHMEM_STARTUP_HOOK {
i();
}
}
$thing.shmem_init();
}
}
};
}
pub trait PgSharedMemoryInitialization {
fn pg_init(&'static self);
fn shmem_init(&'static self);
}
impl<T> PgSharedMemoryInitialization for PgLwLock<T>
where
T: Default + PGRXSharedMemory + 'static,
{
fn pg_init(&'static self) {
PgSharedMem::pg_init_locked(self);
}
fn shmem_init(&'static self) {
PgSharedMem::shmem_init_locked(self);
}
}
impl<T> PgSharedMemoryInitialization for PgAtomic<T>
where
T: atomic_traits::Atomic + Default,
{
fn pg_init(&'static self) {
PgSharedMem::pg_init_atomic(self);
}
fn shmem_init(&'static self) {
PgSharedMem::shmem_init_atomic(self);
}
}
pub struct PgSharedMem {}
impl PgSharedMem {
pub fn pg_init_locked<T: Default + PGRXSharedMemory>(lock: &PgLwLock<T>) {
unsafe {
let lock = alloc::ffi::CString::new(lock.get_name()).expect("CString::new failed");
pg_sys::RequestAddinShmemSpace(std::mem::size_of::<T>());
pg_sys::RequestNamedLWLockTranche(lock.as_ptr(), 1);
}
}
pub fn pg_init_atomic<T: atomic_traits::Atomic + Default>(_atomic: &PgAtomic<T>) {
unsafe {
pg_sys::RequestAddinShmemSpace(std::mem::size_of::<T>());
}
}
pub fn shmem_init_locked<T: Default + PGRXSharedMemory>(lock: &PgLwLock<T>) {
let mut found = false;
unsafe {
let shm_name = alloc::ffi::CString::new(lock.get_name()).expect("CString::new failed");
let addin_shmem_init_lock: *mut pg_sys::LWLock =
&mut (*pg_sys::MainLWLockArray.add(21)).lock;
pg_sys::LWLockAcquire(addin_shmem_init_lock, pg_sys::LWLockMode_LW_EXCLUSIVE);
let fv_shmem =
pg_sys::ShmemInitStruct(shm_name.into_raw(), std::mem::size_of::<T>(), &mut found)
as *mut T;
std::ptr::write(fv_shmem, <T>::default());
lock.attach(fv_shmem);
pg_sys::LWLockRelease(addin_shmem_init_lock);
}
}
pub fn shmem_init_atomic<T: atomic_traits::Atomic + Default>(atomic: &PgAtomic<T>) {
unsafe {
let shm_name = alloc::ffi::CString::new(Uuid::new_v4().to_string())
.expect("CString::new() failed");
let addin_shmem_init_lock: *mut pg_sys::LWLock =
&mut (*pg_sys::MainLWLockArray.add(21)).lock;
let mut found = false;
pg_sys::LWLockAcquire(addin_shmem_init_lock, pg_sys::LWLockMode_LW_EXCLUSIVE);
let fv_shmem =
pg_sys::ShmemInitStruct(shm_name.into_raw(), std::mem::size_of::<T>(), &mut found)
as *mut T;
atomic.attach(fv_shmem);
let atomic = T::default();
std::ptr::copy(&atomic, fv_shmem, 1);
pg_sys::LWLockRelease(addin_shmem_init_lock);
}
}
}
unsafe impl PGRXSharedMemory for bool {}
unsafe impl PGRXSharedMemory for char {}
unsafe impl PGRXSharedMemory for str {}
unsafe impl PGRXSharedMemory for () {}
unsafe impl PGRXSharedMemory for i8 {}
unsafe impl PGRXSharedMemory for i16 {}
unsafe impl PGRXSharedMemory for i32 {}
unsafe impl PGRXSharedMemory for i64 {}
unsafe impl PGRXSharedMemory for i128 {}
unsafe impl PGRXSharedMemory for u8 {}
unsafe impl PGRXSharedMemory for u16 {}
unsafe impl PGRXSharedMemory for u32 {}
unsafe impl PGRXSharedMemory for u64 {}
unsafe impl PGRXSharedMemory for u128 {}
unsafe impl PGRXSharedMemory for usize {}
unsafe impl PGRXSharedMemory for isize {}
unsafe impl PGRXSharedMemory for f32 {}
unsafe impl PGRXSharedMemory for f64 {}
unsafe impl<T> PGRXSharedMemory for [T] where T: PGRXSharedMemory + Default {}
unsafe impl<A, B> PGRXSharedMemory for (A, B)
where
A: PGRXSharedMemory + Default,
B: PGRXSharedMemory + Default,
{
}
unsafe impl<A, B, C> PGRXSharedMemory for (A, B, C)
where
A: PGRXSharedMemory + Default,
B: PGRXSharedMemory + Default,
C: PGRXSharedMemory + Default,
{
}
unsafe impl<A, B, C, D> PGRXSharedMemory for (A, B, C, D)
where
A: PGRXSharedMemory + Default,
B: PGRXSharedMemory + Default,
C: PGRXSharedMemory + Default,
D: PGRXSharedMemory + Default,
{
}
unsafe impl<A, B, C, D, E> PGRXSharedMemory for (A, B, C, D, E)
where
A: PGRXSharedMemory + Default,
B: PGRXSharedMemory + Default,
C: PGRXSharedMemory + Default,
D: PGRXSharedMemory + Default,
E: PGRXSharedMemory + Default,
{
}
unsafe impl<T, const N: usize> PGRXSharedMemory for heapless::Vec<T, N> {}
unsafe impl<K: Eq + Hash, V: Default, S, const N: usize> PGRXSharedMemory
for heapless::IndexMap<K, V, S, N>
{
}