30 modules · lock-free core · BSD-3-Clause

The C standard library
you wish existed.

Containers, Unicode, regex, HTTP parsing, sockets, time and lock-free concurrency, written in plain C and tested on Linux, macOS and Windows.

#include <mulle-core/mulle-core.h>   // everything
cc main.c -lmulle-core              // one link

Why mulle-core

libc gives you strings, stdio and not much more. mulle-core covers the things you would otherwise write yourself or collect from a dozen different projects.

Used in production by mulle-objc.

mulle-core is the foundation of mulle-objc, an Objective-C that is statically linkable, unloadable and real-time capable, and runs wherever C does.

  • Lock-free concurrency. A wait-free resizable hashmap, a lock-free linked list and FIFOs, and a working solution to the ABA problem. Classic mutexes and atomics are in mulle-thread for when you need them.
  • Fits your build. Use CMake FetchContent, a git submodule or a plain clone. A pinned snapshot builds with stock CMake and the compiler you already have. You don't need mulle-sde or any code generation.
  • Cross-platform. Ubuntu with GCC and Clang, Windows with MSVC (Win32/Win64) and GCC, macOS with Clang and GCC, all tested in CI.
  • Documented for AI agents. Every module comes with an AI-oriented reference that has keyword front-matter and the C signatures inline. It's plain text, so it works just as well for people with grep.
  • BSD-3-Clause. Every module uses the same license. Use it in commercial products, fork it, link it statically or dynamically.

What's inside

30 modules from the mulle-c, mulle-concurrent and mulle-core GitHub organizations, combined into one distribution.

⚡ Lock-free concurrency

mulle-aba

Timestamp-based ABA problem solver

🗄️ Containers & memory

🔤 Text, unicode & parsing

mulle-utf

UTF-8/16/32 analysis & manipulation

mulle-url

URL character validation (scheme, host, path, …)

mulle-http

Streaming HTTP request/response parser

🔢 Formatting, I/O & time

mulle-buffer

Growable char array & stream, stack + heap

🧩 System & networking

mulle-socket

Cross-platform TCP sockets (POSIX + Winsock)

mulle-spawn

Run programs without fork, system or shell

🧱 Foundation

Quick start

Three steps. CMake downloads the mulle-core sources into your build tree for you.

  1. 1Fetch it in CMake

    include( FetchContent)
    
    set( MULLE__CORE_TAG "master" CACHE STRING "branch or tag to fetch mulle-core from")
    FetchContent_Declare( MULLE__CORE
       GIT_REPOSITORY https://github.com/mulle-core/mulle-core.git
       GIT_TAG        "${MULLE__CORE_TAG}")
    FetchContent_MakeAvailable( MULLE__CORE)
    
    add_executable( hello-core src/main.c)
    target_link_libraries( hello-core PRIVATE mulle-core)
  2. 2Write code

    #include <mulle-core/mulle-core.h>
    #include <stdio.h>
    
    int main( void)
    {
       void   *item;
    
       // array and buffer are freed automatically when the block exits
       mulle_pointerarray_do( array)
       {
          mulle_pointerarray_add( array, "one");
          mulle_pointerarray_add( array, "two");
    
          mulle_buffer_do( buffer)
          {
             mulle_pointerarray_for( array, item)
             {
                mulle_buffer_add_string( buffer, item);
                mulle_buffer_add_string( buffer, "\n");
             }
             mulle_buffer_make_string( buffer);
             fputs( mulle_buffer_get_string( buffer), stdout);
          }
       }
    
       return( 0);
    }
  3. 3Build and run

    cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug
    cmake --build build-debug --parallel
    ./build-debug/hello-core

The first configure clones mulle-core into build-debug/_deps. To pin a release, pass -DMULLE__CORE_TAG=0.9.0. Develop with Debug and ship with Release: a Debug build keeps assert() active, so mistakes abort right where they happen. If you'd rather keep the sources in your own tree, use a submodule or a plain clone and point add_subdirectory at it. The README lists all installation methods.

Lock-free concurrency

The resizable hashmap is wait-free: every operation finishes in a bounded number of steps, whatever the other threads are doing. There are no locks, so nothing to spin on and nothing to deadlock.

#include <mulle-core/mulle-core.h>
#include <assert.h>
#include <string.h>

int main( void)
{
   struct mulle_concurrent_hashmap   map;
   char                              *key = "mulle-core";
   void                              *value;
   intptr_t                          hash;

   mulle_aba_init( NULL);               // one-time setup
   mulle_aba_register();                // per thread

   mulle_concurrent_hashmap_init( &map, 0, NULL);

   // wait-free from any thread:
   // the hash is the key, so it must be a legal one: 0 is NO_HASH
   hash  = (intptr_t) mulle_hash( key, strlen( key));
   if( ! hash)
      hash = 1;
   mulle_concurrent_hashmap_register( &map, hash, key);
   value = mulle_concurrent_hashmap_lookup( &map, hash);
   assert( value == key);

   mulle_concurrent_hashmap_done( &map);
   mulle_aba_unregister();
   mulle_aba_done();
   return( 0);
}
  • Wait-free hashmap. Register, insert, lookup and remove are all wait-free.
  • Lock-free linked list & FIFOs. Queues for single and multiple producers and consumers.
  • ABA solved. mulle-aba uses per-thread timestamps to make reuse-after-free detectable, on every supported platform.
  • Resizing without blocking. The map migrates to a larger table atomically while callers keep working.
  • Just C. No runtime and no garbage collector, and it works with any allocator.

Demos

Seven terminal programs, each built so that a constituent does the heavy lifting instead of making a token appearance. They show, with numbers, what each part of mulle-core is good at. Every demo is self-contained and builds mulle-core from source.

mredis — a Redis-shaped server

Speaks RESP2 over TCP with a small command set (PING, SET, GET, DEL, EXISTS, QUIT). Each connection gets its own thread, and all threads share one lock-free hash table. Redis is single-threaded by design; mredis takes the opposite approach, which mulle-concurrent makes practical, with mulle-socket handling the networking. It reaches 10.2M requests/s with 64 connections and 4.1× the throughput of redis-server at eight threads, because it scales with the number of cores while Redis stays on one.

mulle-concurrent · mulle-thread · mulle-socket · mulle-spawn

See the demos

multigrep

Parallel text search over memory-mapped files: one producer, N workers and a drain loop, with no locks on the hot path.

mulle-mmap · mulle-concurrent · mulle-multififo · mulle-utf

logtop

A live terminal dashboard for a log stream that shows counts, a histogram and throughput.

mulle-concurrent · mulle-multififo · mulle-data

windowrb

Keeps many short-lived ordered sets over a stream, so the cost of creating and tearing down an rbtree shows up in the numbers instead of disappearing as a rounding error.

mulle-rbtree · mulle-storage · mulle-arena

urltoolkit

Validates, cross-checks and rewrites URLs with two independent parsers, and sorts out the cases where they disagree.

mulle-url · mulle-http · mulle-regex · mulle-slug

blackboard

Seven processes publish through one shared 256 KiB region. The mmap holds a heap, locks and FIFOs, and a note can be freed by a different process than the one that allocated it.

mulle-mmapallocator · mulle-mmap · mulle-spawn · mulle-fifo

hashspace

In the concurrent maps the hash is the key, so it matters which hash values are legal. hashspace runs both maps and shows what each one accepts.

mulle-concurrent · mulle-aba

CI-tested across platforms

Supported platform and compiler matrix
OSCompilerFlags
UbuntuGCC
UbuntuGCC-O3
UbuntuGCCOut-of-source
UbuntuClangDebug
WindowsMSVC Win32
WindowsMSVC Win64
WindowsGCC
macOSClang
macOSGCC