libevent 1.0.0 clib Networking — Async I/O

Portable high-performance event notification library. Async I/O, timers, signals, built-in HTTP server, buffered TCP streams, and async DNS — powered by epoll/kqueue/IOCP.

ppm install libevent

What is libevent?

libevent is a battle-tested portable event notification library for building high-performance asynchronous I/O applications. It provides a unified API over the fastest available I/O multiplexing mechanism on each platform, so your code runs optimally on Linux, macOS, BSD, and Windows without change.

The core abstractions are:

libevent is used in production by Memcached, Tor, Varnish, tmux, libvirt, and the Chromium legacy network stack.

CLib package — system library required

Requires libevent-dev. Ubuntu/Debian: sudo apt install libevent-dev. macOS: brew install libevent. Windows: provided via vcpkg or prebuilt DLL.

Backends

libevent automatically selects the best available I/O notification backend at runtime. You can query or force a specific one:

BackendPlatformNotes
epollLinuxBest performance, edge or level-triggered
kqueuemacOS / BSDNative kernel event queue
IOCPWindowsCompletion ports, native async
pollPortable fallbackPOSIX, O(n) but reliable
selectOldest fallbackLimited to 1024 fds on most systems
uses libevent;
var Base := NewBase;
WriteLn('Active backend: ', GetMethod(Base));  { epoll, kqueue, etc. }

{ Force a specific backend }
var Base2 := NewBaseMethod('epoll');

{ List all available backends on this machine }
var Methods := SupportedMethods;
for I := 0 to Length(Methods) - 1 do
  WriteLn(Methods[I]);

vs Other Event Loops

libevent vs libuv

libuv (Node.js) is newer and more complete: it adds async file I/O and child process management. libevent is older, more battle-tested, and ships with a built-in HTTP server and async DNS. Prefer libevent when you need HTTP or DNS out of the box.

libevent vs libev / Boost.Asio

libev is lighter and faster for raw event dispatch but has fewer built-in features (no HTTP, no DNS). Boost.Asio is a C++ library with a richer async model (coroutines, strands) but is C++ only. libevent is the best choice for C-interop from PascalAI.

Types

TLEBaseEvent loop handle. Create with NewBase, run with Dispatch.
TLEEventRegistered event handle (fd + type + callback).
TLEBufEventBufferevent — auto-buffered TCP stream.
TLEEvbufDynamic I/O buffer (evbuffer).
TLEListenerTCP connection listener on a port.
TLEDNSBaseAsync DNS resolver attached to an event base.
TLEHTTPBuilt-in HTTP/1.1 server handle.
TLEHTTPReqIncoming HTTP request handle (per-request).

TLEEventType enum

ValueHexMeaning
etRead$02Fire when fd is readable
etWrite$04Fire when fd is writable
etSignal$08UNIX signal event
etPersist$10Re-add event after each trigger (persistent)
etEdge$20Edge-triggered mode (epoll ET)
etTimeout$01Timer / timeout event

TLEHTTPType enum

ValueHexHTTP Method
htGET$0010GET
htPOST$0020POST
htPUT$0040PUT
htPATCH$0080PATCH
htDELETE$0100DELETE
htHEAD$0200HEAD
htOPTIONS$0400OPTIONS
htAny$FFFFMatch any method

TLEHTTPRequest record

type TLEHTTPRequest = record
  Method     : string;   { 'GET', 'POST', etc. }
  URI        : string;   { full URI including query string }
  Path       : string;   { path component only }
  Query      : string;   { query string (after '?') }
  Major      : Integer;  { HTTP major version (1) }
  Minor      : Integer;  { HTTP minor version (0 or 1) }
  RemoteHost : string;   { client IP address }
  RemotePort : Integer;  { client port }
  Body       : string;   { request body }
  ContentLen : Int64;    { Content-Length header value }
end;

API Reference

Event Base

function NewBase: TLEBase
Create an event base using the best available backend on this platform.
function NewBaseMethod(Method: string): TLEBase
Create an event base forcing a specific backend ('epoll', 'kqueue', 'poll', 'select').
procedure Dispatch(Base: TLEBase)
Run the event loop until no more active or pending events remain. Blocks the calling thread.
procedure DispatchOnce(Base: TLEBase)
Run a single iteration of the event loop, then return. Useful for cooperative multitasking.
procedure LoopBreak(Base: TLEBase)
Break out of the event loop after the current event's callback returns.
procedure LoopExit(Base: TLEBase; TimeoutMs: Integer)
Exit the event loop after the given number of milliseconds.
procedure FreeBase(Base: TLEBase)
Release the event base and all associated memory.
function GetMethod(Base: TLEBase): string
Return the backend name in use ('epoll', 'kqueue', 'iocp', 'poll', 'select').

Events

function NewEvent(Base: TLEBase; FD: Integer; Events: Integer): TLEEvent
Create an event monitoring a file descriptor. Pass an OR-combination of TLEEventType values.
function NewTimer(Base: TLEBase): TLEEvent
Create a timer event (no file descriptor). Fire after the timeout passed to AddEvent.
function NewSignalEvent(Base: TLEBase; Signal: Integer): TLEEvent
Create an event that fires when the given UNIX signal is received (e.g. SIGTERM = 15).
procedure AddEvent(E: TLEEvent; TimeoutMs: Integer)
Activate an event on its base. Pass -1 for no timeout. Must call before Dispatch.
procedure DelEvent(E: TLEEvent)
Remove a pending event from the event loop without freeing it.
procedure FreeEvent(E: TLEEvent)
Free an event handle. Automatically removes it from the loop first.
function EventPending(E: TLEEvent; Events: Integer): Boolean
Return True if the event is currently pending (waiting to fire) for the given event flags.

Bufferevent (TCP streams with auto-buffering)

function NewBufEvent(Base: TLEBase; FD: Integer): TLEBufEvent
Create a bufferevent for an already-connected socket FD. Pass -1 to create an unconnected one.
function NewBufEventTLS(Base: TLEBase; FD: Integer; CertPath, KeyPath: string): TLEBufEvent
Create a TLS-enabled bufferevent. Wraps the socket in OpenSSL using the given certificate and key files.
procedure BufEventConnect(BE: TLEBufEvent; Host: string; Port: Integer)
Initiate an async TCP connection to Host:Port. The connection event fires via the event/error callback.
procedure BufEventEnable(BE: TLEBufEvent; Events: Integer)
Enable reading and/or writing on the bufferevent. Pass etRead, etWrite, or both OR-combined.
procedure BufEventWrite(BE: TLEBufEvent; Data: string)
Append data to the bufferevent's write buffer. libevent drains it asynchronously.
function BufEventRead(BE: TLEBufEvent; MaxBytes: Integer): string
Drain up to MaxBytes from the bufferevent's read buffer. Call from within a read callback.
procedure BufEventSetCallbacks(BE: TLEBufEvent; CallbackID: string)
Register a callback identifier for routing read/write/error events to named PascalAI handler procedures.
procedure FreeBufEvent(BE: TLEBufEvent)
Free the bufferevent and close the underlying socket if it was created by this bufferevent.

Connection Listener

function NewListener(Base: TLEBase; Host: string; Port, Backlog: Integer): TLEListener
Bind and listen for incoming TCP connections. For each accept, fires the accept callback. Pass '0.0.0.0' to listen on all interfaces. Backlog is the kernel listen queue depth (typically 128).
procedure FreeListener(L: TLEListener)
Stop listening and free the listener handle.

HTTP Server

function NewHTTP(Base: TLEBase): TLEHTTP
Create an HTTP/1.1 server attached to the given event base.
procedure HTTPBind(H: TLEHTTP; Host: string; Port: Integer)
Bind the HTTP server to a host and port. Call before Dispatch.
procedure FreeHTTP(H: TLEHTTP)
Shut down the HTTP server and free its handle.
procedure HTTPSetTimeout(H: TLEHTTP; Seconds: Integer)
Set the request/response timeout in seconds. Idle connections are closed after this time.
function HTTPGetRequest(Req: TLEHTTPReq): TLEHTTPRequest
Extract request metadata (method, URI, path, query, headers, body) from an HTTP request handle.
function HTTPGetHeader(Req: TLEHTTPReq; Name: string): string
Read the value of a specific request header by name (case-insensitive).
procedure HTTPSendReply(Req: TLEHTTPReq; Code: Integer; Reason, Body: string)
Send an HTTP response. Code is the status code (200, 404, etc.), Reason is the status text, Body is the response body string.
procedure HTTPAddHeader(Req: TLEHTTPReq; Name, Value: string)
Append a response header before calling HTTPSendReply. Call multiple times for multiple headers.

Async DNS

function NewDNS(Base: TLEBase): TLEDNSBase
Create an async DNS resolver attached to the event base. Reads /etc/resolv.conf automatically.
procedure DNSResolve(DNS: TLEDNSBase; Hostname: string)
Resolve a hostname asynchronously. The result is delivered via callback when the event loop fires.
procedure FreeDNS(DNS: TLEDNSBase)
Shut down the DNS resolver and free associated resources.

Info

function SupportedMethods: array of string
Return a list of all I/O backends available on the current platform (e.g. ['epoll', 'poll', 'select']).
function LibEventVersion: string
Return the version string of the linked libevent C library (e.g. '2.1.12-stable').

Simple HTTP Server

The built-in HTTP server is the easiest way to serve HTTP/1.1 from a PascalAI program. Bind, set a timeout, register a callback, then enter the event loop:

uses libevent;
var
  Base : TLEBase;
  HTTP : TLEHTTP;
  Req  : TLEHTTPRequest;
begin
  Base := NewBase;
  WriteLn('Backend: ', GetMethod(Base));  { epoll, kqueue, etc. }

  HTTP := NewHTTP(Base);
  HTTPBind(HTTP, '0.0.0.0', 8080);
  HTTPSetTimeout(HTTP, 30);

  { Register a handler via callback system }
  Dispatch(Base);  { run event loop — blocks until LoopBreak }

  FreeHTTP(HTTP);
  FreeBase(Base);
end.

Inside an HTTP callback (invoked by the runtime when a request arrives), parse the request and send a reply:

{ Inside the HTTP request callback: }
var Info := HTTPGetRequest(Req);
WriteLn(Info.Method, ' ', Info.Path);

{ Read a header }
var CT := HTTPGetHeader(Req, 'Content-Type');

{ Add response headers and send }
HTTPAddHeader(Req, 'Content-Type', 'application/json');
HTTPAddHeader(Req, 'X-Powered-By', 'PascalAI');
HTTPSendReply(Req, 200, 'OK', '{"status":"ok"}');

TCP Echo Server (Bufferevent)

For raw TCP, use NewListener to accept connections and NewBufEvent to wrap each socket with automatic read/write buffering. The callback receives data as soon as it is available:

uses libevent;
var
  Base : TLEBase;
  L    : TLEListener;
  BE   : TLEBufEvent;
begin
  Base := NewBase;

  { Listen on port 9000, backlog 128 }
  L := NewListener(Base, '0.0.0.0', 9000, 128);

  { In accept callback, wrap each new fd: }
  BE := NewBufEvent(Base, NewFD);
  BufEventSetCallbacks(BE, 'myReadCB');
  BufEventEnable(BE, $02);  { etRead }

  Dispatch(Base);
  FreeListener(L);
  FreeBase(Base);
end.

{ Read callback body (registered as 'myReadCB'): }
var Data : string;
Data := BufEventRead(BE, 4096);
BufEventWrite(BE, Data);  { echo back to client }

Timer and Signal Events

uses libevent;
var
  Base  : TLEBase;
  Timer : TLEEvent;
  Sig   : TLEEvent;
begin
  Base := NewBase;

  { One-shot timer fires after 5000 ms }
  Timer := NewTimer(Base);
  AddEvent(Timer, 5000);

  { Persistent SIGTERM handler }
  Sig := NewSignalEvent(Base, 15);  { SIGTERM }
  AddEvent(Sig, -1);               { no timeout }

  Dispatch(Base);
  FreeEvent(Timer);
  FreeEvent(Sig);
  FreeBase(Base);
end.

Async DNS Resolution

uses libevent;
var
  Base : TLEBase;
  DNS  : TLEDNSBase;
begin
  Base := NewBase;
  DNS  := NewDNS(Base);

  DNSResolve(DNS, 'api.github.com');  { non-blocking }
  { result arrives in DNS callback during Dispatch }

  Dispatch(Base);
  FreeDNS(DNS);
  FreeBase(Base);
end.

Install

ppm install libevent

Package Info

Version1.0.0
Typeclib
C Librarylibevent
Requireslibevent-dev
Authorgustavo

Used By

Memcached
Tor
Varnish
tmux
libvirt
Chromium (legacy)

Event Base

  • NewBase
  • NewBaseMethod
  • Dispatch
  • DispatchOnce
  • LoopBreak
  • LoopExit
  • FreeBase
  • GetMethod

Events

  • NewEvent
  • NewTimer
  • NewSignalEvent
  • AddEvent
  • DelEvent
  • FreeEvent
  • EventPending

Bufferevent

  • NewBufEvent
  • NewBufEventTLS
  • BufEventConnect
  • BufEventEnable
  • BufEventWrite
  • BufEventRead
  • BufEventSetCallbacks
  • FreeBufEvent

HTTP Server

  • NewHTTP / FreeHTTP
  • HTTPBind
  • HTTPSetTimeout
  • HTTPGetRequest
  • HTTPGetHeader
  • HTTPSendReply
  • HTTPAddHeader

Listener & DNS

  • NewListener
  • FreeListener
  • NewDNS
  • DNSResolve
  • FreeDNS
  • SupportedMethods
  • LibEventVersion

See Also