Skip to content

Add thread-safe wrapper with per-arena locking#22

Merged
jserv merged 1 commit intomasterfrom
thread-safe
Feb 9, 2026
Merged

Add thread-safe wrapper with per-arena locking#22
jserv merged 1 commit intomasterfrom
thread-safe

Conversation

@jserv
Copy link
Copy Markdown
Collaborator

@jserv jserv commented Feb 9, 2026

This splits a caller-provided memory region into TLSF_ARENA_COUNT independent sub-pools (default 4), each with its own lock. Threads are mapped to arenas by hashing their thread identifier, so concurrent allocations from different threads typically hit different locks with zero contention.

  • Two-phase fallback: preferred arena first, then non-blocking try-lock scan, then blocking acquire across remaining arenas.
  • Pointer-range ownership lookup for free/realloc: O(N) where N is the arena count, effectively O(1).
  • Cross-arena realloc: in-place first, then malloc+memcpy+free across arenas when the owning arena is exhausted.
  • Cache-line aligned arenas to prevent false sharing.
  • Lock abstraction macros for RTOS portability (FreeRTOS, Zephyr, etc.).
  • POSIX pthread_mutex_t as default, overridable before include.

Summary by cubic

Adds an optional thread-safe TLSF wrapper with per-arena locking to reduce contention and enable concurrent malloc/free. Also adds tlsf_usable_size and updates build, docs, and tests with pthread support.

  • New Features

    • Per‑arena wrapper (tlsf_thread.h/.c) with hashed arena selection, two‑phase fallback, cross‑arena realloc, pointer‑range ownership lookup, and cache‑line aligned arenas.
    • Thread-safe APIs: tlsf_thread_{init,destroy,malloc,aalloc,realloc,free,check,stats,reset}.
    • Pluggable lock layer via TLSF_LOCK_T and INIT/DESTROY/ACQUIRE/RELEASE/TRY; default pthread; TLSF_THREAD_HINT and TLSF_ARENA_COUNT configurable.
    • New core API: tlsf_usable_size(ptr).
    • Build: adds tlsf_thread.o and test_thread target; check runs it under -pthread. README documents thread safety, usage, and flags.
  • Migration

    • Include tlsf_thread.h and link with pthreads, or define the lock macros; set TLSF_ARENA_COUNT as needed.
    • Avoid concurrent init/destroy/reset on the same instance; the single‑threaded core API remains unchanged.

Written for commit 0c839de. Summary will update on new commits.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

This splits a caller-provided memory region into TLSF_ARENA_COUNT
independent sub-pools (default 4), each with its own lock. Threads are
mapped to arenas by hashing their thread identifier, so concurrent
allocations from different threads typically hit different locks with
zero contention.
- Two-phase fallback: preferred arena first, then non-blocking try-lock
  scan, then blocking acquire across remaining arenas.
- Pointer-range ownership lookup for free/realloc: O(N) where N is the
  arena count, effectively O(1).
- Cross-arena realloc: in-place first, then malloc+memcpy+free across
  arenas when the owning arena is exhausted.
- Cache-line aligned arenas to prevent false sharing.
- Lock abstraction macros for RTOS portability (FreeRTOS, Zephyr, etc.).
- POSIX pthread_mutex_t as default, overridable before include.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 9, 2026

WCET Results (x86-64)

TLSF WCET Analysis
==================
Timer:      cycles
Cache:      hot
Pool:       4194304 bytes (4.0 MB)
Iterations: 5000 (warmup: 500)
Sizes:      16 64 256 1024 4096 bytes

--- malloc_worst (small alloc from single huge block) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         73         98         98        123        196        490       97.9        9.3
      64         98         98         98        123        123        147       98.8        4.5
     256         73         98         98        123        171        220       94.9       12.8
    1024         98         98        122        123        123      19183      105.6      270.0
    4096         73         98         98        123        123        221       98.9        9.9

--- malloc_best (exact bin hit, no split) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         49         73         74         74         74      20335       73.6      286.7
      64         49         73         74         74         74        147       70.3        8.5
     256         49         73         74         74         74        147       69.4        9.3
    1024         49         73         74         74        147      20335       73.5      286.8
    4096         49         73         74         74         74        147       69.4        9.4

--- free_worst (sandwiched between two free blocks) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         49         74         98         98        147      17223       78.7      242.7
      64         49         74         98         98        122        245       75.8       11.5
     256         49         74         98         98        171        245       76.5       11.6
    1024         49         74         98         98        147        171       74.8       10.5
    4096         49         74         98         98        147        220       76.5        9.2

--- free_best (no merge (used neighbors)) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         49         73         74         74        123      17175       66.9      242.3
      64         49         73         74         74        123        196       62.3       12.6
     256         49         73         74         74        123        196       63.1       12.6
    1024         49         73         74         74        123        221       63.3       12.5
    4096         49         49         74         74        123        245       59.0       12.9

--- worst/best ratio (p99) ---
    size     malloc       free
      16      1.66x      1.32x
      64      1.66x      1.32x
     256      1.66x      1.32x
    1024      1.32x      1.32x
    4096      1.66x      1.32x

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 9, 2026

WCET Results (arm64)

TLSF WCET Analysis
==================
Timer:      ticks
Cache:      hot
Pool:       4194304 bytes (4.0 MB)
Iterations: 5000 (warmup: 500)
Sizes:      16 64 256 1024 4096 bytes

--- malloc_worst (small alloc from single huge block) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         16         32         32         32         32         40       30.5        3.2
      64         24         32         32         32         40         40       30.3        3.3
     256         16         32         32         32         40         48       30.2        3.4
    1024         24         32         32         32         40         40       30.6        3.1
    4096         24         32         32         32         40         40       30.6        3.1

--- malloc_best (exact bin hit, no split) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16          8         24         32         32         32         32       25.2        2.9
      64          8         24         32         32         32         32       25.2        2.9
     256         16         24         32         32         32         40       24.9        2.6
    1024         16         24         32         32         32         32       24.9        2.6
    4096         16         24         32         32         32         32       24.8        2.5

--- free_worst (sandwiched between two free blocks) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         16         24         32         32         32         48       25.5        3.2
      64         16         24         32         32         32         40       25.6        3.3
     256         16         24         32         32         32       5024       26.8       70.8
    1024         16         24         32         32         32         32       25.9        3.4
    4096         16         24         32         32         32       1952       26.3       27.5

--- free_best (no merge (used neighbors)) ---
    size        min        p50        p90        p99      p99.9        max       mean     stddev
      16         16         24         24         24         24         24       20.4        4.0
      64         16         24         24         24         24         24       20.5        4.0
     256         16         24         24         24         24       5368       21.6       75.7
    1024         16         24         24         24         24         24       20.5        4.0
    4096         16         24         24         24         24         24       20.5        4.0

--- worst/best ratio (p99) ---
    size     malloc       free
      16      1.00x      1.33x
      64      1.00x      1.33x
     256      1.00x      1.33x
    1024      1.00x      1.33x
    4096      1.00x      1.33x

@jserv jserv merged commit 286cc50 into master Feb 9, 2026
13 checks passed
@jserv jserv deleted the thread-safe branch February 9, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant