How to Use fiber_delay for Non-Blocking Timeouts in libfiber
The fiber_delay function (C API: acl_fiber_delay, C++: fiber::delay) suspends the calling fiber for a specified duration without blocking the underlying OS thread, enabling cooperative multitasking through the fiber scheduler.
The iqiyi/libfiber library provides a high-performance coroutine implementation where fibers yield control instead of blocking threads. Using fiber_delay allows developers to implement non-blocking timeouts that pause individual fibers while the scheduler continues processing other ready fibers on the same OS thread.
Understanding fiber_delay and Non-Blocking Timeouts
When a fiber invokes fiber_delay, it triggers a four-step non-blocking sequence. First, the fiber registers with the internal timer manager via fiber_timer_add, storing the timer in a per-thread timer list. Second, the fiber marks itself with the FIBER_WAIT_DELAY state and yields the CPU through acl_fiber_switch, allowing the scheduler to run other ready fibers. Third, when the timer expires, the event loop (event_get_stamp / wakeup_timers) marks the waiting fiber as ready and clears the delay flag. Finally, the scheduler resumes the fiber and the function returns the remaining milliseconds (normally zero), enabling detection of early wake-up if the fiber was killed.
This architecture ensures that no system sleep() or usleep() blocks the entire thread; only the calling fiber pauses. The public declaration resides in c/include/fiber/fiber_base.h lines 84-88, while the core implementation appears in c/src/fiber_io.c lines 29-73.
C API Implementation (acl_fiber_delay)
Function Signature and Behavior
The acl_fiber_delay function accepts a single int parameter specifying milliseconds to suspend. It returns the remaining time as an unsigned int, which is normally zero but may be non-zero if the fiber wakes early due to termination signals.
Basic Non-Blocking Sleep Example
#include <fiber/fiber.h>
void worker(void *arg)
{
(void) arg;
/* Suspend this fiber for 1 second without blocking other fibers */
acl_fiber_delay(1000); /* 1000 ms */
printf("Fiber resumed after 1 s\n");
}
int main(void)
{
acl_fiber_schedule(); /* start the scheduler */
acl_fiber_create(worker, NULL, 320000, 0);
acl_fiber_schedule_stop(); /* stop when done */
return 0;
}
This example creates a worker fiber that yields for one second while the scheduler processes other fibers. The implementation references c/src/fiber_io.c for the delay logic and c/include/fiber/fiber_base.h for the API contract.
C++ Wrapper Interface (fiber::delay)
Static Method Declaration
The C++ wrapper exposes non-blocking delays through the fiber::delay static method declared in cpp/include/fiber/fiber.hpp lines 31-38. This wrapper forwards calls to acl_fiber_delay via the implementation in cpp/src/fiber.cpp lines 16-18, maintaining identical non-blocking semantics.
Object-Oriented Timeout Example
#include <fiber/fiber.hpp>
#include <iostream>
class my_fiber : public fiber
{
public:
void run() override
{
std::cout << "Sleeping for 500 ms (non-blocking)" << std::endl;
fiber::delay(500);
std::cout << "Awake again!" << std::endl;
}
};
int main()
{
fiber::schedule(); /* Start the scheduler */
my_fiber f;
f.start();
fiber::schedule_stop(); /* Stop when all fibers finished */
return 0;
}
The fiber::delay(500) call invokes the same underlying timer mechanism as the C API, ensuring the fiber yields control without blocking the native thread.
Advanced Timer-Based Callbacks
For scenarios requiring callback-based timeouts rather than simple resumption, use acl_fiber_create_timer. This function creates a dedicated timer fiber that sleeps using identical fiber_delay mechanics but delivers the wake-up to a specified callback instead of the original fiber context.
Declared in c/include/fiber/fiber_base.h lines 98-106 and implemented in c/src/fiber_io.c lines 106-124, this API enables one-shot timer fibers:
static void timer_cb(ACL_FIBER *fb, void *arg)
{
(void)fb; (void)arg;
printf("Timer fired after 2 seconds\n");
}
void start_timer(void)
{
/* 2000 ms, default stack size 320000, timer_cb as entry */
acl_fiber_create_timer(2000, 320000, timer_cb, NULL);
}
Summary
acl_fiber_delaysuspends fibers without blocking OS threads by registering with the per-thread timer manager inc/src/fiber_io.c- The fiber state transitions to
FIBER_WAIT_DELAYbefore yielding viaacl_fiber_switch, allowing the scheduler to execute other fibers - The function returns remaining milliseconds to detect early wake-up conditions from fiber termination
- C++ wrapper provides
fiber::delaystatic method forwarding to the C implementation incpp/src/fiber.cpp - Timer fibers utilize identical mechanics through
acl_fiber_create_timerfor callback-based timeout handling
Frequently Asked Questions
What is the difference between fiber_delay and standard sleep functions?
Standard sleep() or usleep() blocks the entire OS thread, preventing other fibers from executing during the wait period. In contrast, fiber_delay only pauses the calling fiber, allowing the scheduler to continue processing other ready fibers on the same thread through cooperative multitasking.
Can a fiber_delay be interrupted or cancelled early?
Yes, if the fiber receives a termination signal or is killed during the delay period, fiber_delay returns early with a non-zero value indicating the remaining milliseconds. This return value allows cleanup code to detect premature wake-up and adjust logic accordingly.
Is fiber_delay safe to use across multiple OS threads?
Each OS thread maintains its own fiber scheduler and independent timer list within libfiber's architecture. fiber_delay operates strictly within the current thread's scheduler context, making it safe when fibers remain on their creating threads according to the library's thread-affinity design.
What precision does fiber_delay provide?
The implementation uses millisecond granularity specified in the ms parameter, though actual wake-up timing depends on the event loop's timer resolution (event_get_stamp and wakeup_timers) and current scheduler load. The timer expires when the event loop processes the pending timeout, which typically aligns with the requested millisecond count.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →