# How to Handle Graceful Fiber Cancellation and Shutdown in libfiber

> Master graceful fiber cancellation and shutdown in libfiber. Learn to use FIBER_F_CANCELED, acl_fiber_canceled, acl_fiber_kill, and acl_fiber_signal for robust error handling and clean termination.

- Repository: [iQIYI/libfiber](https://github.com/iqiyi/libfiber)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Graceful fiber cancellation in libfiber relies on the `FIBER_F_CANCELED` flag checked via `acl_fiber_canceled()`, with shutdown triggered through `acl_fiber_kill()` or `acl_fiber_signal()` APIs that wake suspended fibers and propagate `ECANCELED` errors.**

When building high-concurrency applications with **iqiyi/libfiber**, managing the lifecycle of fibers—including their orderly termination—is critical for resource cleanup and system stability. The library provides a deterministic cancellation mechanism that allows external threads or fibers to request shutdown while giving target fibers the opportunity to release resources and exit cleanly. This guide examines the source-level implementation of cancellation flags, the public APIs for triggering shutdown, and the patterns required to write robust, cancellation-aware fiber code.

## Understanding the Cancellation Architecture

At the core of libfiber’s shutdown semantics is a bitmask-based state machine defined in [`c/include/fiber/fiber_base.h`](https://github.com/iqiyi/libfiber/blob/main/c/include/fiber/fiber_base.h). The architecture separates the act of canceling a fiber from the fiber’s cooperative response to that cancellation.

### The FIBER_F_CANCELED Flag

The **cancellation flag** aggregates three terminal states into a single testable mask. As defined at line 55 of [`c/include/fiber/fiber_base.h`](https://github.com/iqiyi/libfiber/blob/main/c/include/fiber/fiber_base.h), the macro `FIBER_F_CANCELED` represents the bitwise OR of:

- `FIBER_F_KILLED` — set by `acl_fiber_kill()`
- `FIBER_F_CLOSED` — set when a fiber’s context is closed
- `FIBER_F_SIGNALED` — set by `acl_fiber_signal()`

When any of these individual flags are set on a fiber’s `flag` field, `acl_fiber_canceled()` (implemented in [`c/src/fiber.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber.c) at lines 429–435) returns non-zero, indicating the fiber should abort its current operation.

### Integration with Synchronization and I/O

All blocking primitives in libfiber check the cancellation state before suspending. For example, in [`c/src/sync/fiber_sem.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/sync/fiber_sem.c) (lines 94–100), `acl_fiber_sem_timed_wait` begins with:

```c
if (acl_fiber_canceled(curr))
    return FIBER_EAGAIN;

```

Similarly, I/O operations in [`c/src/fiber_io.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber_io.c) (lines 478–519) invoke `file_cancel()` to abort underlying OS requests when `acl_fiber_canceled()` is true, ensuring that pending read/write calls return immediately with an error rather than hanging indefinitely.

## Triggering Fiber Cancellation

libfiber provides three main APIs for requesting fiber termination, ranging from non-blocking signals to synchronous, blocking waits.

### Signaling with acl_fiber_signal

The **asynchronous signal** API allows you to notify a fiber using POSIX signal conventions:

```c
acl_fiber_signal(target_fiber, SIGTERM);

```

According to the implementation in [`c/src/fiber.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber.c) (lines 445–470), this function sets the `FIBER_F_SIGNALED` bit on the target fiber’s flags. If the fiber is currently suspended (status `FIBER_STATUS_SUSPEND`), the scheduler immediately queues it for re-scheduling via the `FIBER_READY` macro, allowing the fiber to wake and check its cancellation state.

### Killing with acl_fiber_kill

For graceful shutdown without waiting, use **acl_fiber_kill**:

```c
acl_fiber_kill(target_fiber);

```

This function (lines 498–502) sets `fiber->errnum` to `ECANCELED` and invokes the internal `fiber_signal()` with `SIGTERM`. The target fiber will detect the cancellation on its next check, clean up resources, and exit its entry function.

### Synchronous Shutdown with acl_fiber_kill_wait

When the caller must ensure the target fiber has fully exited before proceeding, use **acl_fiber_kill_wait**:

```c
acl_fiber_kill_wait(target_fiber);

```

As implemented in lines 503–507 of [`c/src/fiber.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber.c), this behaves identically to `acl_fiber_kill()` but sets the `synchronized` flag, forcing the calling fiber to yield (`acl_fiber_yield()`) until the target fiber completes its execution and is reclaimed by the scheduler.

### Resetting State

In rare scenarios (typically testing), you can clear a fiber’s cancellation state using:

```c
acl_fiber_clear(target_fiber);

```

Located at lines 37–43 of [`c/src/fiber.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber.c), this clears both the `errnum` and the `FIBER_F_CANCELED` mask, allowing the fiber structure to be reused.

## Writing Cancellation-Aware Fiber Code

Long-running fibers must cooperatively check for cancellation to avoid resource leaks. Follow this pattern in your fiber entry functions:

```c
void my_fiber(ACL_FIBER *self, void *arg)
{
    ACL_FIBER_SEM *sem = (ACL_FIBER_SEM *)arg;
    
    while (!acl_fiber_canceled(self)) {
        /* Perform work */
        do_work();
        
        /* Check cancellation before blocking */
        if (acl_fiber_canceled(self)) {
            cleanup_resources();
            return;
        }
        
        /* Wait with timeout (handles cancellation internally) */
        int rc = acl_fiber_sem_timed_wait(sem, 1000); /* 1 second */
        if (rc < 0) {
            if (acl_fiber_canceled(self)) {
                printf("Cancelled during wait, errno = %d\n", fiber_errno(self));
                cleanup_resources();
                return;
            }
            /* Handle timeout or other errors */
        }
    }
}

```

**Key implementation details:**
- Always check `acl_fiber_canceled()` before entering blocking sections
- Synchronization primitives like `acl_fiber_sem_timed_wait` return errors when cancelled, setting `ECANCELED`
- I/O cancellations propagate automatically through `file_cancel()` in [`c/src/fiber_io.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber_io.c)

## Complete Example: Graceful Worker Shutdown

The following program demonstrates creating a worker fiber, allowing it to run, then requesting graceful shutdown:

```c
#include "fiber/libfiber.h"
#include <stdio.h>
#include <unistd.h>

static void worker(ACL_FIBER *self, void *arg)
{
    int counter = 0;
    ACL_FIBER_SEM *sem = (ACL_FIBER_SEM *)arg;
    
    while (!acl_fiber_canceled(self)) {
        printf("Worker iteration: %d\n", counter++);
        
        /* Simulate periodic work with cancellation-aware wait */
        if (acl_fiber_sem_timed_wait(sem, 1000) < 0) {
            if (acl_fiber_canceled(self)) {
                printf("Worker detected cancellation, exiting cleanly.\n");
                return;
            }
        }
    }
}

int main(void)
{
    ACL_FIBER_SEM *sem = acl_fiber_sem_create(1);
    ACL_FIBER *worker_fiber = acl_fiber_create(worker, sem, 327680);
    
    /* Let worker run for 3 seconds */
    sleep(3);
    
    /* Request graceful shutdown and wait for completion */
    printf("Main: requesting shutdown...\n");
    acl_fiber_kill_wait(worker_fiber);
    
    acl_fiber_sem_free(sem);
    printf("Main: worker terminated, resources freed.\n");
    return 0;
}

```

In this example:
- `acl_fiber_create` allocates a 320KB stack for the worker
- `acl_fiber_sem_timed_wait` provides a cancellation point every second
- `acl_fiber_kill_wait` ensures the main thread blocks until the worker exits

## Summary

Graceful fiber cancellation in libfiber is built around cooperative polling of the **FIBER_F_CANCELED** flag:

- **Cancellation state** is tracked via bitwise flags defined in [`c/include/fiber/fiber_base.h`](https://github.com/iqiyi/libfiber/blob/main/c/include/fiber/fiber_base.h)
- **External shutdown** is triggered by `acl_fiber_kill()` (async) or `acl_fiber_kill_wait()` (sync)
- **Blocking primitives** automatically check `acl_fiber_canceled()` and return `ECANCELED` when terminated
- **I/O operations** utilize `file_cancel()` in [`c/src/fiber_io.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber_io.c) to abort pending system calls
- **Cooperative cleanup** requires fibers to poll `acl_fiber_canceled()` and exit their entry functions cleanly

## Frequently Asked Questions

### How does libfiber distinguish between a timeout and a cancellation in blocking calls?

Both conditions cause waiting primitives to return an error, but you distinguish them by checking `acl_fiber_canceled()` and examining `fiber_errno()`. After a cancellation, `errno` is set to `ECANCELED` (as set in `acl_fiber_kill()` at lines 498–502 of [`c/src/fiber.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber.c)), whereas timeouts typically return `ETIME` or `FIBER_EAGAIN` depending on the specific primitive.

### Can I cancel a fiber that is actively running on another CPU core?

Yes. `acl_fiber_signal()` and `acl_fiber_kill()` are thread-safe operations that set the cancellation flag atomically. If the target fiber is currently executing, it will detect the cancellation on its next call to `acl_fiber_canceled()` or when it enters a blocking primitive. If suspended, the scheduler wakes it immediately via the `FIBER_READY` macro.

### What happens if I ignore the cancellation flag in my fiber code?

Ignoring `acl_fiber_canceled()` prevents graceful shutdown. The fiber will continue running until completion or until the process terminates. For fibers blocked in I/O, the underlying operation can be aborted via `file_cancel()` (as seen in [`c/src/fiber_io.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber_io.c)), but the fiber code must still check the return value and exit; otherwise, it may loop indefinitely or leak resources.

### Is it safe to reuse a fiber structure after cancellation?

Only if you explicitly clear the state. The `acl_fiber_clear()` function (lines 37–43 of [`c/src/fiber.c`](https://github.com/iqiyi/libfiber/blob/main/c/src/fiber.c)) resets the `errnum` and clears the `FIBER_F_CANCELED` mask. However, this is generally discouraged for production code; the intended pattern is to create a new fiber via `acl_fiber_create()` rather than recycling old structures, as the fiber’s stack may contain stale data from the previous execution.