Module Contract¶
Every module in this repository must satisfy the following contract. This ensures consistency, testability, and integration readiness across all protocol implementations.
Required Files¶
Every module directory must contain:
src/category/module_name/
├── module_name.h # Header-only implementation (public API)
├── module_name.c # Demo program / test harness
└── Makefile # Build rules
Header File Requirements¶
1. Protocol Documentation Block¶
The header must begin with a comprehensive comment block:
/**
* =============================================================================
* MODULE NAME (Brief Description)
* =============================================================================
*
* PROTOCOL SPECIFICATION:
* What this module implements (1-3 paragraphs).
*
* MEMORY & CONCURRENCY MODEL:
* ┌───────────────────────────────────────────────────┐
* │ ASCII diagram of memory layout or architecture │
* └───────────────────────────────────────────────────┘
*
* PERFORMANCE:
* - Key latency/throughput characteristics
* - Big-O complexity of operations
*
* COMPILATION:
* gcc -Wall -Wextra -Werror -O3 -std=c11 -o demo module.c [libs]
*
* RUNTIME PREREQUISITES:
* - Required capabilities, kernel modules, hardware
*
* =============================================================================
*/
2. Include Guard¶
3. C++ Compatibility¶
4. Static Inline Functions¶
All API functions must be static inline:
static inline int module_open(module_t *ctx, const char *device)
{
/* Full implementation in header */
}
5. Error Handling Convention¶
- Return
0on success - Return
-errnoon failure - For functions returning data size: positive = success, negative = error
- Never set global
errno(always capture and return)
/* Pattern: capture errno before any other call */
if (syscall(...) < 0) {
int err = errno; /* ← capture immediately */
cleanup(); /* ← this might change errno */
return -err; /* ← return the original error */
}
Demo Program Requirements¶
The .c file must include:
1. Self-Contained Demo¶
int main(void)
{
/* 1. Initialize the module */
/* 2. Demonstrate core operations */
/* 3. Print results with [module] prefix */
/* 4. Clean up */
/* 5. Print [PASS] or [FAIL] */
}
2. Output Format¶
[module_name] Operation description: result
[module_name] Another operation: value
[PASS] All module_name tests passed
3. No External Dependencies¶
The demo must compile with just the standard Makefile (GCC + POSIX libs). No third-party libraries.
4. Virtual Device Support¶
Where hardware is required, document how to create a virtual substitute:
/* For testing without hardware:
* socat -d -d pty,raw,echo=0 pty,raw,echo=0
* Use the reported /dev/pts/N paths
*/
Makefile Requirements¶
CC = gcc
CFLAGS = -Wall -Wextra -Werror -O3 -std=c11
LDFLAGS = # Add -lpthread if using pthreads
TARGET = module_name_demo
SOURCES = module_name.c
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(SOURCES) module_name.h
$(CC) $(CFLAGS) -o $@ $(SOURCES) $(LDFLAGS)
clean:
rm -f $(TARGET)
API Design Checklist¶
- Handle struct Opaque-ish struct holding all state (fd, config, stats)
- Config struct Separate configuration with a
module_default_config()initializer - Open/Close Resource acquisition and release with cleanup-on-error
- Core operations The primary read/write/transfer functions
- Utility helpers Convenience wrappers for common patterns
- Statistics At minimum: operation count, error count
Integration Requirements¶
epoll Reactor Compatibility¶
If the module uses file descriptors, it must be compatible with the epoll reactor:
/* The module's FD must be accessible for reactor registration */
int fd = module_get_fd(ctx); /* Or access ctx->fd directly */
reactor_add(&reactor, fd, EPOLLIN | EPOLLET, callback, ctx);
Memory Pool Compatibility¶
If the module needs dynamic-sized buffers, use the memory pool:
Zero Allocation in Hot Path¶
After initialization, no function in the hot path may call malloc(), calloc(), realloc(), or any allocating function. All buffers must be:
- Stack-allocated (for small, fixed-size)
- Pre-allocated at init time (for configurable-size)
- Provided by caller (for variable-size)
Performance Requirements¶
Latency Budget¶
| Module Type | Target | Measurement |
|---|---|---|
| Network (raw_socket, epoll) | < 5 µs | Wire-to-callback |
| Embedded (UART, SPI, I2C) | < 50 µs | Syscall round-trip |
| Concurrency (ring, pool) | < 20 ns | Push/pop/alloc |
| Industrial (Modbus) | < 1 ms | Request-response |
Benchmark Requirement¶
Every module must include a timing measurement in its demo:
struct timespec t0, t1;
clock_gettime(CLOCK_MONOTONIC, &t0);
/* ... operation ... */
clock_gettime(CLOCK_MONOTONIC, &t1);
double ns = (t1.tv_sec - t0.tv_sec) * 1e9 + (t1.tv_nsec - t0.tv_nsec);
printf("[module] Operation: %.1f ns\n", ns);
Documentation Requirements¶
Every module must have a corresponding documentation page in docs/:
The documentation page must include: - [ ] Overview and status badge - [ ] Protocol specification with ASCII diagrams - [ ] Complete API reference with parameter tables - [ ] At least 2 usage examples - [ ] Build & run instructions - [ ] Prerequisites and permissions - [ ] Performance characteristics table - [ ] Test output showing expected results
Checklist for New Modules¶
Before submitting a PR for a new module:
- Header compiles cleanly with
-Wall -Wextra -Werror - Demo compiles and runs (on virtual device if no hardware)
- All API functions have documentation comments
- Memory: no
malloc/freein operational functions - Errors: returns
-errno, captures errno immediately - Integration: FD accessible for epoll reactor
- Performance: timing measured in demo output
- Docs: MkDocs page created in
docs/ - Tests: demo prints
[PASS]on success