Skip to content

Commit c2c293e

Browse files
authored
add ffi & c++ wrapper for reactor and executor (#48280)
1 parent 9c88f84 commit c2c293e

File tree

7 files changed

+238
-0
lines changed

7 files changed

+238
-0
lines changed

src/core/core.pri

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ HEADERS += \
5858
$$PWD/callback.h \
5959
$$PWD/config.h \
6060
$$PWD/timerwheel.h \
61+
$$PWD/reactor.h \
62+
$$PWD/executor.h \
6163
$$PWD/jwt.h \
6264
$$PWD/timer.h \
6365
$$PWD/defercall.h \
@@ -91,6 +93,8 @@ HEADERS += \
9193
SOURCES += \
9294
$$PWD/config.cpp \
9395
$$PWD/timerwheel.cpp \
96+
$$PWD/reactor.cpp \
97+
$$PWD/executor.cpp \
9498
$$PWD/jwt.cpp \
9599
$$PWD/timer.cpp \
96100
$$PWD/defercall.cpp \

src/core/executor.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (C) 2025 Fastly, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "executor.h"
18+
19+
Executor::Executor(int tasksMax) :
20+
inner_(ffi::executor_create(tasksMax))
21+
{
22+
}
23+
24+
Executor::~Executor()
25+
{
26+
ffi::executor_destroy(inner_);
27+
}
28+
29+
int Executor::park_cb(void *ctx, int ms)
30+
{
31+
std::function<bool (std::optional<int>)> *park = (std::function<bool (std::optional<int>)> *)ctx;
32+
33+
std::optional<int> x;
34+
if(ms >= 0)
35+
x = ms;
36+
37+
if(!(*park)(x))
38+
return -1;
39+
40+
return 0;
41+
}
42+
43+
bool Executor::run(std::function<bool (std::optional<int>)> park)
44+
{
45+
if(ffi::executor_run(inner_, park_cb, &park) != 0)
46+
return false;
47+
48+
return true;
49+
}

src/core/executor.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (C) 2025 Fastly, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef EXECUTOR_H
18+
#define EXECUTOR_H
19+
20+
#include <optional>
21+
#include <functional>
22+
#include "rust/bindings.h"
23+
24+
class Executor
25+
{
26+
public:
27+
Executor(int tasksMax);
28+
~Executor();
29+
30+
bool run(std::function<bool (std::optional<int>)> park);
31+
32+
private:
33+
ffi::Executor *inner_;
34+
35+
static int park_cb(void *ctx, int ms);
36+
};
37+
38+
#endif

src/core/executor.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,51 @@ impl Spawner {
471471
}
472472
}
473473

474+
mod ffi {
475+
use super::*;
476+
use std::ffi::c_int;
477+
478+
#[no_mangle]
479+
pub extern "C" fn executor_create(tasks_max: libc::size_t) -> *mut Executor {
480+
Box::into_raw(Box::new(Executor::new(tasks_max)))
481+
}
482+
483+
#[no_mangle]
484+
pub unsafe extern "C" fn executor_destroy(ex: *mut Executor) {
485+
if !ex.is_null() {
486+
drop(Box::from_raw(ex));
487+
}
488+
}
489+
490+
#[no_mangle]
491+
pub unsafe extern "C" fn executor_run(
492+
ex: *mut Executor,
493+
park_fn: unsafe extern "C" fn(*mut libc::c_void, c_int) -> c_int,
494+
park_ctx: *mut libc::c_void,
495+
) -> c_int {
496+
let ex = unsafe { ex.as_ref().unwrap() };
497+
498+
let park = |d: Option<Duration>| {
499+
let ms = match d {
500+
Some(d) => d.as_millis() as c_int,
501+
None => -1,
502+
};
503+
504+
if park_fn(park_ctx, ms) != 0 {
505+
return Err(io::Error::from(io::ErrorKind::Other));
506+
}
507+
508+
Ok(())
509+
};
510+
511+
if ex.run(park).is_err() {
512+
return -1;
513+
}
514+
515+
0
516+
}
517+
}
518+
474519
#[cfg(test)]
475520
mod tests {
476521
use super::*;

src/core/reactor.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (C) 2025 Fastly, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "reactor.h"
18+
19+
Reactor::Reactor(int registrationsMax) :
20+
inner_(ffi::reactor_create(registrationsMax))
21+
{
22+
}
23+
24+
Reactor::~Reactor()
25+
{
26+
ffi::reactor_destroy(inner_);
27+
}
28+
29+
bool Reactor::poll(std::optional<int> ms)
30+
{
31+
if(ffi::reactor_poll(inner_, ms.value_or(-1)) != 0)
32+
return false;
33+
34+
return true;
35+
}

src/core/reactor.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (C) 2025 Fastly, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef REACTOR_H
18+
#define REACTOR_H
19+
20+
#include <optional>
21+
#include "rust/bindings.h"
22+
23+
class Reactor
24+
{
25+
public:
26+
Reactor(int registrationsMax);
27+
~Reactor();
28+
29+
bool poll(std::optional<int> ms);
30+
31+
private:
32+
ffi::Reactor *inner_;
33+
};
34+
35+
#endif

src/core/reactor.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2020-2023 Fanout, Inc.
3+
* Copyright (C) 2025 Fastly, Inc.
34
*
45
* Licensed under the Apache License, Version 2.0 (the "License");
56
* you may not use this file except in compliance with the License.
@@ -1009,6 +1010,37 @@ impl TimerEvented {
10091010
}
10101011
}
10111012

1013+
mod ffi {
1014+
use super::*;
1015+
use std::convert::TryInto;
1016+
use std::ffi::c_int;
1017+
1018+
#[no_mangle]
1019+
pub extern "C" fn reactor_create(registrations_max: libc::size_t) -> *mut Reactor {
1020+
Box::into_raw(Box::new(Reactor::new(registrations_max)))
1021+
}
1022+
1023+
#[no_mangle]
1024+
pub unsafe extern "C" fn reactor_destroy(r: *mut Reactor) {
1025+
if !r.is_null() {
1026+
drop(Box::from_raw(r));
1027+
}
1028+
}
1029+
1030+
#[no_mangle]
1031+
pub unsafe extern "C" fn reactor_poll(r: *const Reactor, ms: c_int) -> c_int {
1032+
let r = unsafe { r.as_ref().unwrap() };
1033+
1034+
let duration = ms.try_into().ok().map(Duration::from_millis);
1035+
1036+
if r.poll(duration).is_err() {
1037+
return -1;
1038+
}
1039+
1040+
0
1041+
}
1042+
}
1043+
10121044
#[cfg(test)]
10131045
mod tests {
10141046
use super::*;

0 commit comments

Comments
 (0)