Skip to content

Commit 3ea09af

Browse files
authored
fix compilation on some CPUs and Windows (#1901)
This patch contains two part: * use cshim for sigsetjmp on CPUs/OSes that are not supported by `cee-scape`'s asm (needed by #1897 and Windows) * fix linking error on Windows in #1133
1 parent 9ed73d5 commit 3ea09af

File tree

12 files changed

+146
-73
lines changed

12 files changed

+146
-73
lines changed

pgrx-bindgen/src/build.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ fn run_bindgen(
794794
.default_non_copy_union_style(NonCopyUnionStyle::ManuallyDrop)
795795
.wrap_static_fns(enable_cshim)
796796
.wrap_static_fns_path(out_path.join("pgrx-cshim-static"))
797+
.wrap_static_fns_suffix("__pgrx_cshim")
797798
.generate()
798799
.wrap_err_with(|| format!("Unable to generate bindings for pg{major_version}"))?;
799800
let mut binding_str = bindings.to_string();
@@ -877,6 +878,14 @@ fn add_blocklists(bind: bindgen::Builder) -> bindgen::Builder {
877878
.blocklist_function("range_table_walker")
878879
.blocklist_function("raw_expression_tree_walker")
879880
.blocklist_function("type_is_array")
881+
// These structs contains array that is larger than 32
882+
// so that `derive(Default)` would fail.
883+
.blocklist_type("tagMONITORINFOEXA")
884+
.blocklist_type("MONITORINFOEXA")
885+
.blocklist_type("LPMONITORINFOEXA")
886+
.blocklist_type("MONITORINFOEX")
887+
.blocklist_type("LPMONITORINFOEX")
888+
.blocklist_function("ua_.*") // this should be Windows's names
880889
}
881890

882891
fn add_derives(bind: bindgen::Builder) -> bindgen::Builder {
@@ -1116,18 +1125,11 @@ fn apply_pg_guard(items: &Vec<syn::Item>) -> eyre::Result<proc_macro2::TokenStre
11161125
match item {
11171126
Item::ForeignMod(block) => {
11181127
let abi = &block.abi;
1119-
let (mut extern_funcs, mut others) = (Vec::new(), Vec::new());
1120-
block.items.iter().filter(|&item| !is_blocklisted_item(item)).cloned().for_each(
1121-
|item| match item {
1122-
ForeignItem::Fn(func) => extern_funcs.push(func),
1123-
item => others.push(item),
1124-
},
1125-
);
1128+
let items = block.items.iter().filter(|&item| !is_blocklisted_item(item));
11261129
out.extend(quote! {
11271130
#[pgrx_macros::pg_guard]
1128-
#abi { #(#extern_funcs)* }
1131+
#abi { #(#items)* }
11291132
});
1130-
out.extend(quote! { #abi { #(#others)* } });
11311133
}
11321134
_ => {
11331135
out.extend(item.into_token_stream());

pgrx-macros/src/rewriter.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use std::str::FromStr;
1616
use syn::punctuated::Punctuated;
1717
use syn::spanned::Spanned;
1818
use syn::{
19-
FnArg, ForeignItem, ForeignItemFn, GenericParam, ItemFn, ItemForeignMod, Pat, Signature, Token,
20-
Visibility,
19+
Expr, ExprLit, FnArg, ForeignItem, ForeignItemFn, ForeignItemStatic, GenericParam, ItemFn,
20+
ItemForeignMod, Lit, Pat, Signature, Token, Visibility,
2121
};
2222

2323
macro_rules! format_ident {
@@ -126,6 +126,7 @@ fn foreign_item(item: ForeignItem, abi: &syn::Abi) -> syn::Result<proc_macro2::T
126126

127127
foreign_item_fn(&func, abi)
128128
}
129+
ForeignItem::Static(variable) => foreign_item_static(&variable, abi),
129130
_ => Ok(quote! { #abi { #item } }),
130131
}
131132
}
@@ -135,19 +136,44 @@ fn foreign_item_fn(func: &ForeignItemFn, abi: &syn::Abi) -> syn::Result<proc_mac
135136
let arg_list = rename_arg_list(&func.sig)?;
136137
let arg_list_with_types = rename_arg_list_with_types(&func.sig)?;
137138
let return_type = func.sig.output.clone();
139+
let link_with_cshim = func.attrs.iter().any(|attr| match &attr.meta {
140+
syn::Meta::NameValue(kv) if kv.path.get_ident().filter(|x| *x == "link_name").is_some() => {
141+
if let Expr::Lit(ExprLit { lit: Lit::Str(value), .. }) = &kv.value {
142+
value.value().ends_with("__pgrx_cshim")
143+
} else {
144+
false
145+
}
146+
}
147+
_ => false,
148+
});
149+
let link = if link_with_cshim {
150+
quote! {}
151+
} else {
152+
quote! { #[cfg_attr(target_os = "windows", link(name = "postgres"))] }
153+
};
138154

139155
Ok(quote! {
140156
#[inline]
141157
#[track_caller]
142158
pub unsafe fn #func_name ( #arg_list_with_types ) #return_type {
143159
crate::ffi::pg_guard_ffi_boundary(move || {
144-
#abi { #func }
160+
#link #abi { #func }
145161
#func_name(#arg_list)
146162
})
147163
}
148164
})
149165
}
150166

167+
fn foreign_item_static(
168+
variable: &ForeignItemStatic,
169+
abi: &syn::Abi,
170+
) -> syn::Result<proc_macro2::TokenStream> {
171+
let link = quote! { #[cfg_attr(target_os = "windows", link(name = "postgres"))] };
172+
Ok(quote! {
173+
#link #abi { #variable }
174+
})
175+
}
176+
151177
#[allow(clippy::cmp_owned)]
152178
fn build_arg_list(sig: &Signature, suffix_arg_name: bool) -> syn::Result<proc_macro2::TokenStream> {
153179
let mut arg_list = proc_macro2::TokenStream::new();

pgrx-pg-sys/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ serde.workspace = true # impls on pub types
5050
# polyfill until #![feature(strict_provenance)] stabilizes
5151
sptr = "0.3"
5252

53+
[target.'cfg(all(any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies]
5354
# Safer `sigsetjmp` and `siglongjmp`
5455
cee-scape = "0.2"
5556

pgrx-pg-sys/pgrx-cshim.c

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,28 @@
1010

1111
#include "pgrx-cshim-static.c"
1212

13-
PGDLLEXPORT void *pgrx_list_nth(List *list, int nth);
14-
void *pgrx_list_nth(List *list, int nth) {
15-
return list_nth(list, nth);
16-
}
17-
18-
PGDLLEXPORT int pgrx_list_nth_int(List *list, int nth);
19-
int pgrx_list_nth_int(List *list, int nth) {
20-
return list_nth_int(list, nth);
21-
}
22-
23-
PGDLLEXPORT Oid pgrx_list_nth_oid(List *list, int nth);
24-
Oid pgrx_list_nth_oid(List *list, int nth) {
25-
return list_nth_oid(list, nth);
26-
}
27-
28-
PGDLLEXPORT ListCell *pgrx_list_nth_cell(List *list, int nth);
29-
ListCell *pgrx_list_nth_cell(List *list, int nth) {
30-
return list_nth_cell(list, nth);
31-
}
32-
33-
PGDLLEXPORT void pgrx_SpinLockInit(volatile slock_t *lock);
34-
void pgrx_SpinLockInit(volatile slock_t *lock) {
13+
void SpinLockInit__pgrx_cshim(volatile slock_t *lock) {
3514
SpinLockInit(lock);
3615
}
3716

38-
PGDLLEXPORT void pgrx_SpinLockAcquire(volatile slock_t *lock);
39-
void pgrx_SpinLockAcquire(volatile slock_t *lock) {
17+
void SpinLockAcquire__pgrx_cshim(volatile slock_t *lock) {
4018
SpinLockAcquire(lock);
4119
}
4220

43-
PGDLLEXPORT void pgrx_SpinLockRelease(volatile slock_t *lock);
44-
void pgrx_SpinLockRelease(volatile slock_t *lock) {
21+
void SpinLockRelease__pgrx_cshim(volatile slock_t *lock) {
4522
SpinLockRelease(lock);
4623
}
4724

48-
PGDLLEXPORT bool pgrx_SpinLockFree(slock_t *lock);
49-
bool pgrx_SpinLockFree(slock_t *lock) {
25+
bool SpinLockFree__pgrx_cshim(slock_t *lock) {
5026
return SpinLockFree(lock);
5127
}
28+
29+
int call_closure_with_sigsetjmp(int savemask, void* closure_env_ptr, int (*closure_code)(sigjmp_buf jbuf, void *env_ptr)) {
30+
sigjmp_buf jbuf;
31+
int val;
32+
if (0 == (val = sigsetjmp(jbuf, savemask))) {
33+
return closure_code(jbuf, closure_env_ptr);
34+
} else {
35+
return val;
36+
}
37+
}

pgrx-pg-sys/src/cshim.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,15 @@
22
#![allow(deprecated)]
33

44
use crate as pg_sys;
5-
use core::ffi;
65

76
#[pgrx_macros::pg_guard]
87
extern "C" {
9-
pub fn pgrx_list_nth(list: *mut pg_sys::List, nth: i32) -> *mut ffi::c_void;
10-
pub fn pgrx_list_nth_int(list: *mut pg_sys::List, nth: i32) -> i32;
11-
pub fn pgrx_list_nth_oid(list: *mut pg_sys::List, nth: i32) -> pg_sys::Oid;
12-
pub fn pgrx_list_nth_cell(list: *mut pg_sys::List, nth: i32) -> *mut pg_sys::ListCell;
13-
14-
#[link_name = "pgrx_SpinLockInit"]
8+
#[link_name = "SpinLockInit__pgrx_cshim"]
159
pub fn SpinLockInit(lock: *mut pg_sys::slock_t);
16-
#[link_name = "pgrx_SpinLockAcquire"]
10+
#[link_name = "SpinLockAcquire__pgrx_cshim"]
1711
pub fn SpinLockAcquire(lock: *mut pg_sys::slock_t);
18-
#[link_name = "pgrx_SpinLockRelease"]
12+
#[link_name = "SpinLockRelease__pgrx_cshim"]
1913
pub fn SpinLockRelease(lock: *mut pg_sys::slock_t);
20-
#[link_name = "pgrx_SpinLockFree"]
14+
#[link_name = "SpinLockFree__pgrx_cshim"]
2115
pub fn SpinLockFree(lock: *mut pg_sys::slock_t) -> bool;
2216
}

pgrx-pg-sys/src/submodules/ffi.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,64 @@
99
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
1010
#![deny(unsafe_op_in_unsafe_fn)]
1111

12-
use cee_scape::SigJmpBufFields;
12+
#[cfg(not(all(
13+
any(target_os = "linux", target_os = "macos"),
14+
any(target_arch = "x86_64", target_arch = "aarch64")
15+
)))]
16+
mod cee_scape {
17+
#[cfg(not(feature = "cshim"))]
18+
compile_error!("target platform cannot work without feature cshim");
19+
20+
use libc::{c_int, c_void};
21+
use std::marker::PhantomData;
22+
23+
#[repr(C)]
24+
pub struct SigJmpBufFields {
25+
_internal: [u8; 0],
26+
_neither_send_nor_sync: PhantomData<*const u8>,
27+
}
28+
29+
pub fn call_with_sigsetjmp<F>(savemask: bool, mut callback: F) -> c_int
30+
where
31+
F: for<'a> FnOnce(&'a SigJmpBufFields) -> c_int,
32+
{
33+
extern "C" {
34+
fn call_closure_with_sigsetjmp(
35+
savemask: c_int,
36+
closure_env_ptr: *mut c_void,
37+
closure_code: extern "C" fn(
38+
jbuf: *const SigJmpBufFields,
39+
env_ptr: *mut c_void,
40+
) -> c_int,
41+
) -> c_int;
42+
}
43+
44+
extern "C" fn call_from_c_to_rust<F>(
45+
jbuf: *const SigJmpBufFields,
46+
closure_env_ptr: *mut c_void,
47+
) -> c_int
48+
where
49+
F: for<'a> FnOnce(&'a SigJmpBufFields) -> c_int,
50+
{
51+
let closure_env_ptr: *mut F = closure_env_ptr as *mut F;
52+
unsafe { (closure_env_ptr.read())(&*jbuf) }
53+
}
54+
55+
let savemask: libc::c_int = if savemask { 1 } else { 0 };
56+
57+
unsafe {
58+
let closure_env_ptr = core::ptr::addr_of_mut!(callback);
59+
core::mem::forget(callback);
60+
call_closure_with_sigsetjmp(
61+
savemask,
62+
closure_env_ptr as *mut libc::c_void,
63+
call_from_c_to_rust::<F>,
64+
)
65+
}
66+
}
67+
}
68+
69+
use cee_scape::{call_with_sigsetjmp, SigJmpBufFields};
1370

1471
/**
1572
Given a closure that is assumed to be a wrapped Postgres `extern "C"` function, [pg_guard_ffi_boundary]
@@ -113,7 +170,7 @@ unsafe fn pg_guard_ffi_boundary_impl<T, F: FnOnce() -> T>(f: F) -> T {
113170
let prev_exception_stack = pg_sys::PG_exception_stack;
114171
let prev_error_context_stack = pg_sys::error_context_stack;
115172
let mut result: std::mem::MaybeUninit<T> = MaybeUninit::uninit();
116-
let jump_value = cee_scape::call_with_sigsetjmp(false, |jump_buffer| {
173+
let jump_value = call_with_sigsetjmp(false, |jump_buffer| {
117174
// Make Postgres' error-handling system aware of our new
118175
// setjmp/longjmp restore point.
119176
pg_sys::PG_exception_stack = std::mem::transmute(jump_buffer as *const SigJmpBufFields);

pgrx-pg-sys/src/submodules/panic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ where
395395
match unsafe { run_guarded(AssertUnwindSafe(f)) } {
396396
GuardAction::Return(r) => r,
397397
GuardAction::ReThrow => {
398+
#[cfg_attr(target_os = "windows", link(name = "postgres"))]
398399
extern "C" /* "C-unwind" */ {
399400
fn pg_re_throw() -> !;
400401
}
@@ -509,6 +510,7 @@ fn do_ereport(ereport: ErrorReportWithLevel) {
509510
// `build.rs` and we'd prefer pgrx users not have access to them at all
510511
//
511512

513+
#[cfg_attr(target_os = "windows", link(name = "postgres"))]
512514
extern "C" {
513515
fn errcode(sqlerrcode: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
514516
fn errmsg(fmt: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int;
@@ -524,6 +526,7 @@ fn do_ereport(ereport: ErrorReportWithLevel) {
524526
#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15", feature = "pg16", feature = "pg17"))]
525527
fn do_ereport_impl(ereport: ErrorReportWithLevel) {
526528

529+
#[cfg_attr(target_os = "windows", link(name = "postgres"))]
527530
extern "C" {
528531
fn errstart(elevel: ::std::os::raw::c_int, domain: *const ::std::os::raw::c_char) -> bool;
529532
fn errfinish(filename: *const ::std::os::raw::c_char, lineno: ::std::os::raw::c_int, funcname: *const ::std::os::raw::c_char);
@@ -588,6 +591,7 @@ fn do_ereport(ereport: ErrorReportWithLevel) {
588591
#[cfg(feature = "pg12")]
589592
fn do_ereport_impl(ereport: ErrorReportWithLevel) {
590593

594+
#[cfg_attr(target_os = "windows", link(name = "postgres"))]
591595
extern "C" {
592596
fn errstart(elevel: ::std::os::raw::c_int, filename: *const ::std::os::raw::c_char, lineno: ::std::os::raw::c_int, funcname: *const ::std::os::raw::c_char, domain: *const ::std::os::raw::c_char) -> bool;
593597
fn errfinish(dummy: ::std::os::raw::c_int, ...);

pgrx-pg-sys/src/submodules/thread_check.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ fn init_active_thread(tid: NonZeroUsize) {
9494
panic!("Attempt to initialize `pgrx` active thread from a thread other than the main");
9595
}
9696
match ACTIVE_THREAD.compare_exchange(0, tid.get(), Ordering::Relaxed, Ordering::Relaxed) {
97+
#[cfg(not(target_os = "windows"))]
9798
Ok(_) => unsafe {
9899
// We won the race. Register an atfork handler to clear the atomic
99100
// in any child processes we spawn.
@@ -102,6 +103,8 @@ fn init_active_thread(tid: NonZeroUsize) {
102103
}
103104
libc::pthread_atfork(None, None, Some(clear_in_child));
104105
},
106+
#[cfg(target_os = "windows")]
107+
Ok(_) => (),
105108
Err(_) => {
106109
thread_id_check_failed();
107110
}

pgrx/src/bgworkers.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ impl DynamicBackgroundWorker {
343343
/// return [`BackgroundWorkerStatus::Untracked`] error
344344
pub fn wait_for_startup(&self) -> Result<Pid, BackgroundWorkerStatus> {
345345
unsafe {
346-
if self.notify_pid != pg_sys::MyProcPid {
346+
if self.notify_pid != pg_sys::MyProcPid as pg_sys::pid_t {
347347
return Err(BackgroundWorkerStatus::Untracked { notify_pid: self.notify_pid });
348348
}
349349
}
@@ -382,7 +382,7 @@ impl TerminatingDynamicBackgroundWorker {
382382
/// return [`BackgroundWorkerStatus::Untracked`] error
383383
pub fn wait_for_shutdown(self) -> Result<(), BackgroundWorkerStatus> {
384384
unsafe {
385-
if self.notify_pid != pg_sys::MyProcPid {
385+
if self.notify_pid != pg_sys::MyProcPid as pg_sys::pid_t {
386386
return Err(BackgroundWorkerStatus::Untracked { notify_pid: self.notify_pid });
387387
}
388388
}
@@ -580,7 +580,7 @@ impl BackgroundWorkerBuilder {
580580
/// to wait for the worker to start up. Otherwise, it should be initialized to
581581
/// `pgrx::pg_sys::MyProcPid`
582582
pub fn set_notify_pid(mut self, input: i32) -> Self {
583-
self.bgw_notify_pid = input;
583+
self.bgw_notify_pid = input as pg_sys::pid_t;
584584
self
585585
}
586586

@@ -634,7 +634,7 @@ impl<'a> From<&'a BackgroundWorkerBuilder> for pg_sys::BackgroundWorker {
634634
bgw_name: RpgffiChar::from(&builder.bgw_name[..]).0,
635635
bgw_type: RpgffiChar::from(&builder.bgw_type[..]).0,
636636
bgw_flags: builder.bgw_flags.bits(),
637-
bgw_start_time: builder.bgw_start_time as u32,
637+
bgw_start_time: builder.bgw_start_time as _,
638638
bgw_restart_time: match builder.bgw_restart_time {
639639
None => -1,
640640
Some(d) => d.as_secs() as i32,

0 commit comments

Comments
 (0)