Skip to main content

Phase-locked userland scheduling library

Project description

Build Status@GitHub Coverage Status

libElPeriodic

Library to run frequent periodic tasks.

Principle of Operation

The libElPeriodic is designed to simplify writing control loops that are expected to run at constant "tick" intervals with smallest possible overhead and little or no support from the underlying run time environment.

The library is optimized to align active periods of the control loop to the set frequency (and optionally phase as well) by applying phase locked loop design with a proportional phase detector and a low-pass filter as an error amplifier.

Basic Usage

Sample usage pattern is demonstrated below. The code block denoted by the square brackets will be executing 125.5 times a second, untul the value returned by the is_runnable() routine is non-zero. Provided of course that the "logic" does not take more than 0.01 second to run on average and that OS scheduler plays the ball.

#include <assert.h>
#include <time.h>
#include <elperiodic.h>

extern int is_runnable(void);

void
event_loop(void)
{
    double frequency = 125.5; /* Hz */
    void *elp;

    elp = prdic_init(frequency, 0.0);
    assert(elp != NULL);

    while (is_runnable()) {
//      [----------------------];
//      [Insert your logic here];
//      [----------------------];
        prdic_procrastinate(elp);
    }
    prdic_free(elp);
}

Dispatching Calls from Worker Threads

The library also supports simple FIFO queue of function calls that have to be dispatched by the library asynchronously in the main thread during the "procrastination" time intervals. This allows I/O, timer and other type of events to enter into the processing loop in a thread-safe manner.

This can be accomplished by enabling the functionality using the prdic_CFT_enable() API and then scheduling necessary calls via the prdic_call_from_thread() in a worker thread(s).

#include <assert.h>
#include <time.h>
#include <elperiodic.h>
#include <pthread.h>
#include <signal.h>

extern int do_something(void);

struct prd_ctx {
    /* This member is initialized in the main thread */
    void *elp;
    /* This member only accessible by the main thread */
    int is_runnable;
    /* This member is filled in by the worker thread before exit */
    int result;
};

static void shutdown(struct prd_ctx *ctxp) {ctxp->is_runnable = 0;}

static void
worker_thread(void *ap)
{
    struct prd_ctx *ctxp = (struct prd_ctx *)ap;

    ctxp->result = do_something();
    prdic_call_from_thread(ctxp->elp, (void (*)(void *))shutdown, ctxp);
}

int
event_loop(void)
{
    struct prd_ctx ctx = {.is_runnable = 1};
    double freq = 125.5; /* Hz */
    pthread_t wthr;

    ctx.elp = prdic_init(freq, 0.0);
    assert(ctx.elp != NULL);
    assert(prdic_CFT_enable(ctx.elp, SIGUSR1) == 0);

    assert(pthread_create(&wthr, NULL, (void *(*)(void *))worker_thread, &ctx) == 0);

    while (ctx.is_runnable) {
//      [----------------------];
//      [Insert your logic here];
//      [----------------------];
        prdic_procrastinate(ctx.elp);
    }
    pthread_join(wthr, NULL);
    prdic_free(ctx.elp);

    return ctx.result;
}

Story

It came about having to write the same code over and over again in multiple real-time projects, ranging from game Digger, RTP relay server RTPProxy. It has also been recently utilized to replace a heavy-weight (and at the time not portable to Python 3) "Twisted" framework in the Python Sippy B2BUA project.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

elperiodic-1.4.tar.gz (14.5 kB view details)

Uploaded Source

File details

Details for the file elperiodic-1.4.tar.gz.

File metadata

  • Download URL: elperiodic-1.4.tar.gz
  • Upload date:
  • Size: 14.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.4

File hashes

Hashes for elperiodic-1.4.tar.gz
Algorithm Hash digest
SHA256 91cfa74738c1cde2beb3ffdceb65d5678a2a01a858f2dafb60bbffdd702cd23e
MD5 ebc8a08d02bb65a5ca83b8ba65e73842
BLAKE2b-256 2600ade21919723725aac68c2ff0ef8fe67a8d2460e2658206d393310f6a4962

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page