Skip to content

Commit 8bf0dcf

Browse files
committed
Merge branch 'feature/better-fibers' into 'master'
feat: new fiber abstractions See merge request picodata/brod/tarantool-module!43
2 parents 6459b97 + 2164a7c commit 8bf0dcf

File tree

9 files changed

+1120
-15
lines changed

9 files changed

+1120
-15
lines changed

src/error.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ use rmp::encode::ValueWriteError;
2727

2828
use crate::ffi::tarantool as ffi;
2929

30+
/// A specialized [`Result`] type for the crate
31+
pub type Result<T> = std::result::Result<T, Error>;
32+
3033
/// Represents all error cases for all routines of crate (including Tarantool errors)
3134
#[derive(Debug, Fail)]
3235
pub enum Error {
@@ -171,7 +174,7 @@ pub struct TarantoolError {
171174
impl TarantoolError {
172175
/// Tries to get the information about the last API call error. If error was not set
173176
/// returns `Ok(())`
174-
pub fn maybe_last() -> Result<(), Self> {
177+
pub fn maybe_last() -> std::result::Result<(), Self> {
175178
let error_ptr = unsafe { ffi::box_error_last() };
176179
if error_ptr.is_null() {
177180
return Ok(());

src/ffi/helper.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,19 @@ use std::ffi::CString;
33
pub unsafe fn new_c_str(s: &str) -> CString {
44
return CString::new(s).unwrap();
55
}
6+
7+
#[macro_export]
8+
macro_rules! c_str {
9+
($s:literal) => {
10+
::std::ffi::CStr::from_bytes_with_nul_unchecked(
11+
::std::concat!($s, "\0").as_bytes()
12+
)
13+
};
14+
}
15+
16+
#[macro_export]
17+
macro_rules! c_ptr {
18+
($s:literal) => {
19+
crate::c_str!($s).as_ptr()
20+
};
21+
}

src/ffi/tarantool.rs

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,70 @@ bitflags! {
3333
}
3434

3535
extern "C" {
36+
/// Wait until **READ** or **WRITE** event on socket (`fd`). Yields.
37+
/// - `fd` - non-blocking socket file description
38+
/// - `events` - requested events to wait.
39+
/// Combination of `TNT_IO_READ` | `TNT_IO_WRITE` bit flags.
40+
/// - `timeoout` - timeout in seconds.
41+
///
42+
/// Returns:
43+
/// - `0` - timeout
44+
/// - `>0` - returned events. Combination of `TNT_IO_READ` | `TNT_IO_WRITE`
45+
/// bit flags.
3646
pub fn coio_wait(fd: c_int, event: c_int, timeout: f64) -> c_int;
47+
48+
/**
49+
* Close the fd and wake any fiber blocked in
50+
* coio_wait() call on this fd.
51+
*/
3752
pub fn coio_close(fd: c_int) -> c_int;
53+
54+
/// Fiber-friendly version of getaddrinfo(3).
55+
///
56+
/// - `host` host name, i.e. "tarantool.org"
57+
/// - `port` service name, i.e. "80" or "http"
58+
/// - `hints` hints, see getaddrinfo(3)
59+
/// - `res`[out] result, see getaddrinfo(3)
60+
/// - `timeout` timeout
61+
///
62+
/// Returns:
63+
/// - `0` on success, please free @a res using freeaddrinfo(3).
64+
/// - `-1` on error, check diag.
65+
/// Please note that the return value is not compatible with
66+
/// getaddrinfo(3).
3867
pub fn coio_getaddrinfo(
3968
host: *const c_char,
4069
port: *const c_char,
4170
hints: *const libc::addrinfo,
4271
res: *mut *mut libc::addrinfo,
4372
timeout: f64,
4473
) -> c_int;
74+
75+
/// Create new eio task with specified function and
76+
/// arguments. Yield and wait until the task is complete.
77+
///
78+
/// This function doesn't throw exceptions to avoid double error
79+
/// checking: in most cases it's also necessary to check the return
80+
/// value of the called function and perform necessary actions. If
81+
/// func sets errno, the errno is preserved across the call.
82+
///
83+
/// Returns:
84+
/// - `-1` and `errno = ENOMEM` if failed to create a task
85+
/// - the function return (errno is preserved).
86+
///
87+
/// # Example
88+
/// ```c
89+
/// static ssize_t openfile_cb(va_list ap)
90+
/// {
91+
/// const char *filename = va_arg(ap);
92+
/// int flags = va_arg(ap);
93+
/// return open(filename, flags);
94+
/// }
95+
///
96+
/// if (coio_call(openfile_cb, "/tmp/file", 0) == -1)
97+
/// // handle errors.
98+
/// ...
99+
/// ```
45100
pub fn coio_call(func: Option<unsafe extern "C" fn(VaList) -> c_int>, ...) -> isize;
46101
}
47102

@@ -64,35 +119,180 @@ pub struct FiberCond {
64119
pub type FiberFunc = Option<unsafe extern "C" fn(VaList) -> c_int>;
65120

66121
extern "C" {
122+
/// Create a new fiber.
123+
///
124+
/// Takes a fiber from fiber cache, if it's not empty.
125+
/// Can fail only if there is not enough memory for
126+
/// the fiber structure or fiber stack.
127+
///
128+
/// The created fiber automatically returns itself
129+
/// to the fiber cache when its "main" function
130+
/// completes.
131+
///
132+
/// - `name` string with fiber name
133+
/// - `fiber_func` func for run inside fiber
134+
///
135+
/// See also: [fiber_start](#fn.fiber_start)
67136
pub fn fiber_new(name: *const c_char, f: FiberFunc) -> *mut Fiber;
137+
138+
/// Create a new fiber with defined attributes.
139+
///
140+
/// Can fail only if there is not enough memory for
141+
/// the fiber structure or fiber stack.
142+
///
143+
/// The created fiber automatically returns itself
144+
/// to the fiber cache if has default stack size
145+
/// when its "main" function completes.
146+
///
147+
/// - `name` string with fiber name
148+
/// - `fiber_attr` fiber attributes
149+
/// - `fiber_func` func for run inside fiber
150+
///
151+
/// See also: [fiber_start](#fn.fiber_start)
68152
pub fn fiber_new_ex(
69153
name: *const c_char,
70154
fiber_attr: *const FiberAttr,
71155
f: FiberFunc,
72156
) -> *mut Fiber;
157+
158+
/// Return control to another fiber and wait until it'll be woken.
159+
///
160+
/// See also: [fiber_wakeup](#fn.fiber_wakeup)
73161
pub fn fiber_yield();
162+
163+
/// Start execution of created fiber.
164+
///
165+
/// - `callee` fiber to start
166+
/// - `...` arguments to start the fiber with
167+
///
168+
/// See also: [fiber_new](#fn.fiber_new)
74169
pub fn fiber_start(callee: *mut Fiber, ...);
170+
171+
/// Interrupt a synchronous wait of a fiber. Nop for the currently running
172+
/// fiber.
173+
///
174+
/// - `f` fiber to be woken up
75175
pub fn fiber_wakeup(f: *mut Fiber);
176+
177+
/// Cancel the subject fiber. (set FIBER_IS_CANCELLED flag)
178+
///
179+
/// If target fiber's flag FIBER_IS_CANCELLABLE set, then it would
180+
/// be woken up (maybe prematurely). Then current fiber yields
181+
/// until the target fiber is dead (or is woken up by
182+
/// see also: [fiber_wakeup](#fn.fiber_wakeup)).
183+
///
184+
/// - `f` fiber to be cancelled
76185
pub fn fiber_cancel(f: *mut Fiber);
186+
187+
/// Make it possible or not possible to wakeup the current
188+
/// fiber immediately when it's cancelled.
189+
///
190+
/// - `yesno` status to set
191+
///
192+
/// Returns: previous state.
77193
pub fn fiber_set_cancellable(yesno: bool) -> bool;
194+
195+
/// Set fiber to be joinable (false by default).
196+
/// - `yesno` status to set
78197
pub fn fiber_set_joinable(fiber: *mut Fiber, yesno: bool);
198+
199+
/// Wait until the fiber is dead and then move its execution
200+
/// status to the caller.
201+
/// The fiber must not be detached (See also:
202+
/// [fiber_set_joinable](#fn.fiber_set_joinable)).
203+
/// `FIBER_IS_JOINABLE` flag is set.
204+
///
205+
/// - `f` fiber to be woken up
206+
///
207+
/// Returns: fiber function ret code
79208
pub fn fiber_join(f: *mut Fiber) -> c_int;
209+
210+
/// Put the current fiber to sleep for at least 's' seconds.
211+
///
212+
/// - `s` time to sleep
213+
///
214+
/// **Note:** this is a cancellation point (\sa fiber_is_cancelled)
80215
pub fn fiber_sleep(s: f64);
216+
217+
/// Check current fiber for cancellation (it must be checked manually).
81218
pub fn fiber_is_cancelled() -> bool;
219+
220+
/// Report loop begin time as double (cheap).
221+
/// Uses real time clock.
82222
pub fn fiber_time() -> f64;
223+
224+
/// Report loop begin time as 64-bit int.
225+
/// Uses real time clock.
83226
pub fn fiber_time64() -> u64;
227+
228+
/// Report loop begin time as double (cheap).
229+
/// Uses monotonic clock.
84230
pub fn fiber_clock() -> f64;
231+
232+
/// Report loop begin time as 64-bit int.
233+
/// Uses monotonic clock.
85234
pub fn fiber_clock64() -> u64;
235+
236+
/// Reschedule fiber to end of event loop cycle.
86237
pub fn fiber_reschedule();
238+
239+
/// Create a new fiber attribute container and initialize it
240+
/// with default parameters.
241+
/// Can be used for many fibers creation, corresponding fibers
242+
/// will not take ownership.
87243
pub fn fiber_attr_new() -> *mut FiberAttr;
244+
245+
/// Delete the fiber_attr and free all allocated resources.
246+
/// This is safe when fibers created with this attribute still exist.
247+
///
248+
/// - `fiber_attr` fiber attribute
88249
pub fn fiber_attr_delete(fiber_attr: *mut FiberAttr);
250+
251+
/// Set stack size for the fiber attribute.
252+
///
253+
/// - `fiber_attribute` fiber attribute container
254+
/// - `stacksize` stack size for new fibers
89255
pub fn fiber_attr_setstacksize(fiber_attr: *mut FiberAttr, stack_size: usize) -> c_int;
256+
257+
/// Get stack size from the fiber attribute.
258+
///
259+
/// - `fiber_attribute` fiber attribute container or NULL for default
260+
///
261+
/// Returns: stack size
90262
pub fn fiber_attr_getstacksize(fiber_attr: *mut FiberAttr) -> usize;
263+
264+
/// Instantiate a new fiber cond object.
91265
pub fn fiber_cond_new() -> *mut FiberCond;
266+
267+
/// Delete the fiber cond object.
268+
/// Behaviour is undefined if there are fiber waiting for the cond.
92269
pub fn fiber_cond_delete(cond: *mut FiberCond);
270+
271+
/// Wake one fiber waiting for the cond.
272+
/// Does nothing if no one is waiting.
273+
/// - `cond` condition
93274
pub fn fiber_cond_signal(cond: *mut FiberCond);
275+
276+
/// Wake up all fibers waiting for the cond.
277+
/// - `cond` condition
94278
pub fn fiber_cond_broadcast(cond: *mut FiberCond);
279+
280+
/// Suspend the execution of the current fiber (i.e. yield) until
281+
/// fiber_cond_signal() is called. Like pthread_cond, fiber_cond can issue
282+
/// spurious wake ups caused by explicit fiber_wakeup() or fiber_cancel()
283+
/// calls. It is highly recommended to wrap calls to this function into a loop
284+
/// and check an actual predicate and fiber_testcancel() on every iteration.
285+
///
286+
/// - `cond` condition
287+
/// - `timeout` timeout in seconds
288+
///
289+
/// Returns:
290+
/// - `0` on fiber_cond_signal() call or a spurious wake up
291+
/// - `-1` on timeout or fiber cancellation, diag is set
95292
pub fn fiber_cond_wait_timeout(cond: *mut FiberCond, timeout: f64) -> c_int;
293+
294+
/// Shortcut for fiber_cond_wait_timeout().
295+
/// See also: [fiber_cond_wait_timeout](#fn.fiber_cond_wait_timeout)
96296
pub fn fiber_cond_wait(cond: *mut FiberCond) -> c_int;
97297
}
98298

@@ -103,10 +303,33 @@ pub struct Latch {
103303
}
104304

105305
extern "C" {
306+
/// Allocate and initialize the new latch.
307+
///
308+
/// Returns: latch
106309
pub fn box_latch_new() -> *mut Latch;
310+
311+
/// Destroy and free the latch.
312+
/// - `latch` latch
107313
pub fn box_latch_delete(latch: *mut Latch);
314+
315+
/// Lock a latch. Waits indefinitely until the current fiber can gain access to
316+
/// the latch.
317+
///
318+
/// - `latch` a latch
108319
pub fn box_latch_lock(latch: *mut Latch);
320+
321+
/// Try to lock a latch. Return immediately if the latch is locked.
322+
/// - `latch` a latch
323+
///
324+
/// Returns:
325+
/// - `0` - success
326+
/// - `1` - the latch is locked.
109327
pub fn box_latch_trylock(latch: *mut Latch) -> c_int;
328+
329+
/// Unlock a latch. The fiber calling this function must
330+
/// own the latch.
331+
///
332+
/// - `latch` a latch
110333
pub fn box_latch_unlock(latch: *mut Latch);
111334
}
112335

@@ -129,11 +352,55 @@ pub struct BoxError {
129352
}
130353

131354
extern "C" {
355+
/// Return IPROTO error code
356+
/// - `error` error
357+
///
358+
/// Returns: enum `box_error_code`
132359
pub fn box_error_code(error: *const BoxError) -> u32;
360+
361+
/// Return the error message
362+
/// - `error` error
363+
///
364+
/// Returns: not-null string
133365
pub fn box_error_message(error: *const BoxError) -> *const c_char;
366+
367+
/// Get the information about the last API call error.
368+
///
369+
/// The Tarantool error handling works most like libc's errno. All API calls
370+
/// return -1 or NULL in the event of error. An internal pointer to
371+
/// box_error_t type is set by API functions to indicate what went wrong.
372+
/// This value is only significant if API call failed (returned -1 or NULL).
373+
///
374+
/// Successful function can also touch the last error in some
375+
/// cases. You don't have to clear the last error before calling
376+
/// API functions. The returned object is valid only until next
377+
/// call to **any** API function.
378+
///
379+
/// You must set the last error using [box_error_set](#fn.box_error_set) in
380+
/// your stored C procedures if you want to return a custom error message.
381+
/// You can re-throw the last API error to IPROTO client by keeping
382+
/// the current value and returning -1 to Tarantool from your
383+
/// stored procedure.
384+
///
385+
/// Returns: last error.
134386
pub fn box_error_last() -> *mut BoxError;
387+
388+
/// Return the error type, e.g. "ClientError", "SocketError", etc.
389+
/// - `error`
390+
///
391+
/// Returns: not-null string
135392
pub fn box_error_type(error: *const BoxError) -> *const c_char;
393+
394+
/// Clear the last error.
136395
pub fn box_error_clear();
396+
397+
/// Set the last error.
398+
///
399+
/// - `code` IPROTO error code (enum \link box_error_code \endlink)
400+
/// - `format` (const char * ) - printf()-like format string
401+
/// - ... - format arguments
402+
///
403+
/// Returns: `-1` for convention use
137404
pub fn box_error_set(
138405
file: *const c_char,
139406
line: c_uint,

0 commit comments

Comments
 (0)