Line data Source code
1 : //! Functions called from the C code in the worker process
2 :
3 : use std::ffi::{CStr, CString, c_char};
4 :
5 : use crate::worker_process::main_loop;
6 : use crate::worker_process::main_loop::CommunicatorWorkerProcessStruct;
7 :
8 : /// Launch the communicator's tokio tasks, which do most of the work.
9 : ///
10 : /// The caller has initialized the process as a regular PostgreSQL background worker
11 : /// process.
12 : ///
13 : /// Inputs:
14 : /// `tenant_id` and `timeline_id` can be NULL, if we're been launched in "non-Neon" mode,
15 : /// where we use local storage instead of connecting to remote neon storage. That's
16 : /// currently only used in some unit tests.
17 : ///
18 : /// Result:
19 : /// Returns pointer to CommunicatorWorkerProcessStruct, which is a handle to running
20 : /// Rust tasks. The C code can use it to interact with the Rust parts. On failure, returns
21 : /// None/NULL, and an error message is returned in *error_p
22 : ///
23 : /// This is called only once in the process, so the returned struct, and error message in
24 : /// case of failure, are simply leaked.
25 : #[unsafe(no_mangle)]
26 0 : pub extern "C" fn communicator_worker_launch(
27 0 : tenant_id: *const c_char,
28 0 : timeline_id: *const c_char,
29 0 : error_p: *mut *const c_char,
30 0 : ) -> Option<&'static CommunicatorWorkerProcessStruct> {
31 : // Convert the arguments into more convenient Rust types
32 0 : let tenant_id = if tenant_id.is_null() {
33 0 : None
34 : } else {
35 0 : let cstr = unsafe { CStr::from_ptr(tenant_id) };
36 0 : Some(cstr.to_str().expect("assume UTF-8"))
37 : };
38 0 : let timeline_id = if timeline_id.is_null() {
39 0 : None
40 : } else {
41 0 : let cstr = unsafe { CStr::from_ptr(timeline_id) };
42 0 : Some(cstr.to_str().expect("assume UTF-8"))
43 : };
44 :
45 : // The `init` function does all the work.
46 0 : let result = main_loop::init(tenant_id, timeline_id);
47 :
48 : // On failure, return the error message to the C caller in *error_p.
49 0 : match result {
50 0 : Ok(worker_struct) => Some(worker_struct),
51 0 : Err(errmsg) => {
52 0 : let errmsg = CString::new(errmsg).expect("no nuls within error message");
53 0 : let errmsg = Box::leak(errmsg.into_boxed_c_str());
54 0 : let p: *const c_char = errmsg.as_ptr();
55 :
56 0 : unsafe { *error_p = p };
57 0 : None
58 : }
59 : }
60 0 : }
|