Skip to main content

MOD_NAME Module

Overview

The MOD_NAME Module serves as a template and example module for developing custom ChiMods within the Clio framework. It demonstrates various Module patterns and provides testing functionality for concurrency primitives such as CoMutex and CoRwLock. This module is primarily used for development, testing, and as a reference implementation for new Module development.

Key Features:

  • Template for custom Module development
  • Custom operation support with configurable parameters
  • CoMutex (Coroutine Mutex) testing and validation
  • CoRwLock (Coroutine Reader-Writer Lock) testing
  • Recursive task.Wait() testing functionality
  • Configurable worker count and operation parameters

CMake Integration

External Projects

To use the MOD_NAME Module in external projects:

# The umbrella package brings in clio::run::cxx, the admin client/runtime,
# and every ctp::* target.
find_package(clio-core CONFIG REQUIRED)
find_package(clio_run_MOD_NAME REQUIRED) # MOD_NAME Module package

target_link_libraries(your_application
clio::run::MOD_NAME_client # MOD_NAME client library
clio::run::admin_client # Admin client (required)
${CMAKE_THREAD_LIBS_INIT} # Threading support
)
# clio::run::cxx and ctp::cxx are transitive dependencies of the Module clients

Required Headers

#include <clio_runtime/clio_runtime.h>
#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <clio_runtime/MOD_NAME/MOD_NAME_tasks.h>
#include <clio_runtime/admin/admin_client.h> // Required for CreateTask

API Reference

Client Class: clio::run::MOD_NAME::Client

The MOD_NAME client provides the primary interface for module operations and testing.

Constructor

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>

void example() {
// Default constructor
clio::run::MOD_NAME::Client client;

// Constructor with pool ID (calls Init(pool_id) internally)
clio::run::MOD_NAME::Client client_with_pool(clio::run::PoolId(9000, 0));
}

Container Management

AsyncCreate()

Creates and initializes the MOD_NAME container asynchronously.

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>

// Signature (member of clio::run::MOD_NAME::Client):
clio::run::Future<clio::run::MOD_NAME::CreateTask> AsyncCreate(
const clio::run::PoolQuery& pool_query,
const std::string& pool_name,
const clio::run::PoolId& custom_pool_id);

Parameters:

  • pool_query: Pool domain query (typically chi::PoolQuery::Local())
  • pool_name: Name for the pool
  • custom_pool_id: Explicit pool ID for the container

Returns: Future for asynchronous completion checking

Usage:

#include <clio_runtime/clio_runtime.h>
#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>

void example() {
clio::run::CLIO_INIT(clio::run::RuntimeMode::kClient, true);
const clio::run::PoolId pool_id = clio::run::PoolId(9000, 0);
clio::run::MOD_NAME::Client mod_client(pool_id);

auto pool_query = clio::run::PoolQuery::Dynamic();
auto create_task = mod_client.AsyncCreate(pool_query, "my_mod_name", pool_id);
create_task.Wait();

// Adopt the pool ID the runtime assigned to this container
mod_client.pool_id_ = create_task->new_pool_id_;

if (create_task->GetReturnCode() != 0) {
std::cerr << "MOD_NAME creation failed" << std::endl;
return;
}
}

Custom Operations

AsyncCustom()

Executes a custom operation with configurable parameters asynchronously.

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>

// Signature (member of clio::run::MOD_NAME::Client):
clio::run::Future<clio::run::MOD_NAME::CustomTask> AsyncCustom(
const clio::run::PoolQuery& pool_query,
const std::string& input_data,
clio::run::u32 operation_id);

Parameters:

  • pool_query: Pool domain query
  • input_data: Input data string for the operation
  • operation_id: Identifier for the type of operation to perform

Returns: Future for asynchronous completion checking. Access output data via task->data_ after calling Wait().

Usage:

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>
#include <string>

void example() {
clio::run::MOD_NAME::Client mod_client(clio::run::PoolId(9000, 0));
auto pool_query = clio::run::PoolQuery::Local();

std::string input = "test data for processing";
auto custom_task = mod_client.AsyncCustom(pool_query, input, 1);
custom_task.Wait();

if (custom_task->GetReturnCode() == 0) {
std::cout << "Custom operation succeeded. Output: "
<< custom_task->data_.str() << std::endl;
} else {
std::cout << "Custom operation failed with code: "
<< custom_task->GetReturnCode() << std::endl;
}
}

Concurrency Testing Operations

AsyncCoMutexTest()

Tests CoMutex (Coroutine Mutex) functionality asynchronously.

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>

// Signature (member of clio::run::MOD_NAME::Client):
clio::run::Future<clio::run::MOD_NAME::CoMutexTestTask> AsyncCoMutexTest(
const clio::run::PoolQuery& pool_query,
clio::run::u32 test_id, clio::run::u32 hold_duration_ms);

Parameters:

  • pool_query: Pool domain query
  • test_id: Identifier for the test instance
  • hold_duration_ms: Duration to hold the mutex lock in milliseconds

Returns: Future for asynchronous completion checking

Usage:

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>

void example() {
clio::run::MOD_NAME::Client mod_client(clio::run::PoolId(9000, 0));
auto pool_query = clio::run::PoolQuery::Local();

// Test CoMutex with 1 second hold duration
auto mutex_task = mod_client.AsyncCoMutexTest(pool_query, 1, 1000);
mutex_task.Wait();
std::cout << "CoMutex test result: " << mutex_task->GetReturnCode()
<< std::endl;
}
AsyncCoRwLockTest()

Tests CoRwLock (Coroutine Reader-Writer Lock) functionality asynchronously.

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>

// Signature (member of clio::run::MOD_NAME::Client):
clio::run::Future<clio::run::MOD_NAME::CoRwLockTestTask> AsyncCoRwLockTest(
const clio::run::PoolQuery& pool_query,
clio::run::u32 test_id, bool is_writer, clio::run::u32 hold_duration_ms);

Parameters:

  • pool_query: Pool domain query
  • test_id: Identifier for the test instance
  • is_writer: True for write lock test, false for read lock test
  • hold_duration_ms: Duration to hold the lock in milliseconds

Returns: Future for asynchronous completion checking

Usage:

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>

void example() {
clio::run::MOD_NAME::Client mod_client(clio::run::PoolId(9000, 0));
auto pool_query = clio::run::PoolQuery::Local();

// Test read lock
auto read_task = mod_client.AsyncCoRwLockTest(pool_query, 1, false, 500);
read_task.Wait();

// Test write lock
auto write_task = mod_client.AsyncCoRwLockTest(pool_query, 2, true, 500);
write_task.Wait();

std::cout << "Read lock test result: " << read_task->GetReturnCode()
<< std::endl;
std::cout << "Write lock test result: " << write_task->GetReturnCode()
<< std::endl;
}
AsyncWaitTest()

Tests recursive task.Wait() functionality with specified depth.

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>

// Signature (member of clio::run::MOD_NAME::Client):
clio::run::Future<clio::run::MOD_NAME::WaitTestTask> AsyncWaitTest(
const clio::run::PoolQuery& pool_query,
clio::run::u32 depth,
clio::run::u32 test_id);

Parameters:

  • pool_query: Pool routing information
  • depth: Number of recursive calls to make
  • test_id: Test identifier for tracking

Returns: Future for asynchronous completion checking

Task Types

CreateTask

Container creation task for the MOD_NAME module. This is an alias for clio::run::admin::GetOrCreatePoolTask<CreateParams>.

Key Fields:

  • Inherits from BaseCreateTask with MOD_NAME-specific CreateParams
  • Processed by admin module for pool creation
  • Contains serialized MOD_NAME configuration parameters

CustomTask

Custom operation task for demonstrating module-specific functionality.

Key Fields:

  • data_: Input/output data string (INOUT)
  • operation_id_: Operation type identifier (IN)
  • result_code_: Operation result (OUT, 0 = success)

CoMutexTestTask

Task for testing CoMutex functionality.

Key Fields:

  • test_id_: Test instance identifier (IN)
  • hold_duration_ms_: Duration to hold mutex lock in milliseconds (IN)
  • result_: Test result code (OUT)

CoRwLockTestTask

Task for testing CoRwLock functionality.

Key Fields:

  • test_id_: Test instance identifier (IN)
  • is_writer_: True for write lock, false for read lock (IN)
  • hold_duration_ms_: Duration to hold lock in milliseconds (IN)
  • result_: Test result code (OUT)

WaitTestTask

Task for testing recursive task.Wait() functionality.

Key Fields:

  • depth_: Number of recursive calls to make (IN)
  • test_id_: Test identifier for tracking (IN)
  • result_: Test result code (OUT)

DestroyTask

Standard destruction task (alias for clio::run::admin::DestroyTask).

Configuration

CreateParams Structure

Configuration parameters for MOD_NAME container creation:

#include <clio_runtime/clio_runtime.h>

struct CreateParams {
// MOD_NAME-specific parameters (primitives only for cereal compatibility)
clio::run::u32 worker_count_; // Number of worker threads (default: 1)
clio::run::u32 config_flags_; // Module configuration flags (default: 0)

// Required: chimod library name for the module manager
static constexpr const char* chimod_lib_name = "clio_MOD_NAME";

// Constructor with parameters (also serves as default)
CreateParams(clio::run::u32 worker_count = 1, clio::run::u32 config_flags = 0)
: worker_count_(worker_count), config_flags_(config_flags) {}

// Serialization support for cereal
template <class Archive>
void serialize(Archive& ar) {
ar(worker_count_, config_flags_);
}
};

Parameter Guidelines:

  • config_data_: Custom configuration string for module behavior
  • worker_count_: Number of worker threads for parallel processing (default: 1)

Important: The chimod_lib_name does NOT include the _runtime suffix as it is automatically appended by the module manager.

Usage Examples

Complete Module Setup and Testing

#include <clio_runtime/clio_runtime.h>
#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <clio_runtime/admin/admin_client.h>
#include <iostream>
#include <string>

int main() {
// Initialize CLIO Runtime client
clio::run::CLIO_INIT(clio::run::RuntimeMode::kClient, true);

// Create admin client first (always required)
const clio::run::PoolId admin_pool_id = clio::run::kAdminPoolId;
clio::run::admin::Client admin_client(admin_pool_id);
auto admin_task =
admin_client.AsyncCreate(clio::run::PoolQuery::Local(), "admin", admin_pool_id);
admin_task.Wait();

// Create MOD_NAME client
const clio::run::PoolId mod_pool_id = clio::run::PoolId(9000, 0);
clio::run::MOD_NAME::Client mod_client(mod_pool_id);

// Initialize MOD_NAME container
auto create_task =
mod_client.AsyncCreate(clio::run::PoolQuery::Dynamic(), "my_mod_name", mod_pool_id);
create_task.Wait();
mod_client.pool_id_ = create_task->new_pool_id_;

if (create_task->GetReturnCode() != 0) {
std::cerr << "MOD_NAME creation failed" << std::endl;
return 1;
}

// Test custom operations
std::string input_data = "Hello, CLIO Runtime!";
auto custom_task =
mod_client.AsyncCustom(clio::run::PoolQuery::Local(), input_data, 1);
custom_task.Wait();

if (custom_task->GetReturnCode() == 0) {
std::cout << "Custom operation successful!" << std::endl;
std::cout << "Input: " << input_data << std::endl;
std::cout << "Output: " << custom_task->data_.str() << std::endl;
}

return 0;
}

Concurrency Testing

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>

void example() {
clio::run::MOD_NAME::Client mod_client(clio::run::PoolId(9000, 0));

// Test CoMutex functionality
std::cout << "Testing CoMutex..." << std::endl;
for (clio::run::u32 i = 0; i < 5; ++i) {
auto mutex_task =
mod_client.AsyncCoMutexTest(clio::run::PoolQuery::Local(), i, 100); // 100ms hold
mutex_task.Wait();
std::cout << "CoMutex test " << i
<< " result: " << mutex_task->GetReturnCode() << std::endl;
}

// Test CoRwLock functionality
std::cout << "Testing CoRwLock..." << std::endl;

// Test multiple readers (should allow concurrency)
for (clio::run::u32 i = 0; i < 3; ++i) {
auto read_task = mod_client.AsyncCoRwLockTest(clio::run::PoolQuery::Local(), i,
false, 200); // Read lock, 200ms
read_task.Wait();
std::cout << "Read lock test " << i
<< " result: " << read_task->GetReturnCode() << std::endl;
}

// Test exclusive writer (should serialize with other operations)
auto write_task = mod_client.AsyncCoRwLockTest(clio::run::PoolQuery::Local(), 100,
true, 300); // Write lock, 300ms
write_task.Wait();
std::cout << "Write lock test result: " << write_task->GetReturnCode()
<< std::endl;
}

Asynchronous Operations

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>
#include <string>
#include <vector>

void example() {
clio::run::MOD_NAME::Client mod_client(clio::run::PoolId(9000, 0));

// Example of using asynchronous operations for parallel execution
std::vector<clio::run::Future<clio::run::MOD_NAME::CustomTask>> tasks;

// Submit multiple async operations
for (clio::run::u32 i = 0; i < 5; ++i) {
std::string input = "Async operation " + std::to_string(i);
auto task = mod_client.AsyncCustom(clio::run::PoolQuery::Local(), input, i);
tasks.push_back(std::move(task));
}

// Wait for all tasks to complete and collect results
for (size_t i = 0; i < tasks.size(); ++i) {
tasks[i].Wait();

std::cout << "Task " << i << " completed:" << std::endl;
std::cout << " Result code: " << tasks[i]->GetReturnCode() << std::endl;
std::cout << " Output data: " << tasks[i]->data_.str() << std::endl;
}
}

Template for Custom Module Development

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <clio_runtime/MOD_NAME/MOD_NAME_tasks.h>

// Use MOD_NAME as a template for developing your own module:
// 1. Copy the modules/MOD_NAME directory structure.
// 2. Rename files and classes from MOD_NAME to your module name.
// 3. Update CreateParams with your configuration.
// 4. Replace CustomTask with your domain-specific tasks.
// 5. Implement your module logic in the runtime.

// Method IDs for your module (see autogen/<mod>_methods.h in a real module):
namespace Method {
GLOBAL_CROSS_CONST clio::run::u32 kYourCustom = 10;
} // namespace Method

// Example custom task (replace CustomTask):
struct YourCustomTask : public clio::run::Task {
IN clio::run::u32 input_param_;
OUT clio::run::u32 output_param_;

/** SHM default constructor */
YourCustomTask() : clio::run::Task(), input_param_(0), output_param_(0) {}

/** Emplace constructor */
explicit YourCustomTask(const clio::run::TaskId& task_node,
const clio::run::PoolId& pool_id,
const clio::run::PoolQuery& pool_query,
clio::run::u32 input_param)
: clio::run::Task(task_node, pool_id, pool_query, Method::kYourCustom),
input_param_(input_param), output_param_(0) {
method_ = Method::kYourCustom;
task_flags_.Clear();
}

template <typename Archive>
CTP_CROSS_FUN void SerializeIn(Archive& ar) {
Task::SerializeIn(ar);
ar(input_param_);
}

template <typename Archive>
CTP_CROSS_FUN void SerializeOut(Archive& ar) {
Task::SerializeOut(ar);
ar(output_param_);
}
};

// Add matching async methods to your client (mirrors MOD_NAME's Client):
class YourClient : public clio::run::ContainerClient {
public:
clio::run::Future<YourCustomTask> AsyncYourCustom(
const clio::run::PoolQuery& pool_query, clio::run::u32 input_param) {
auto* ipc_manager = CLIO_CPU_IPC;
auto task = ipc_manager->NewTask<YourCustomTask>(
clio::run::CreateTaskId(), pool_id_, pool_query, input_param);
return ipc_manager->Send(task);
}
};

Dependencies

  • HermesShm: Shared memory framework and IPC
  • CLIO Runtime core runtime: Base runtime objects and task framework
  • Admin Module: Required for pool creation and management
  • cereal: Serialization library for network communication
  • Boost.Fiber and Boost.Context: Coroutine support for CoMutex/CoRwLock

Installation

  1. Build CLIO Runtime with the MOD_NAME module:

    cmake --preset debug
    cmake --build build
  2. Install to system or custom prefix:

    cmake --install build --prefix /usr/local
  3. For external projects, set CMAKE_PREFIX_PATH:

    export CMAKE_PREFIX_PATH="/usr/local:/path/to/hermes-shm:/path/to/other/deps"

Error Handling

All operations are asynchronous and return chi::Future<TaskType>. Check task result codes after calling Wait():

#include <clio_runtime/MOD_NAME/MOD_NAME_client.h>
#include <iostream>
#include <string>

void example() {
clio::run::MOD_NAME::Client mod_client(clio::run::PoolId(9000, 0));
auto pool_query = clio::run::PoolQuery::Local();
std::string input = "payload";

auto task = mod_client.AsyncCustom(pool_query, input, 1);
task.Wait();

if (task->GetReturnCode() != 0) {
std::cerr << "Custom operation failed with code: " << task->GetReturnCode()
<< std::endl;
}
}

Development Guidelines

Using MOD_NAME as a Template

  1. File Structure: Copy the entire modules/MOD_NAME/ directory structure
  2. Renaming: Replace all instances of MOD_NAME with your module name
  3. Configuration: Update CreateParams with your module-specific parameters
  4. Tasks: Replace or extend the example tasks with your domain-specific operations
  5. Client API: Implement methods that make sense for your use case
  6. Runtime Logic: Implement the actual processing logic in the runtime files

Best Practices

  1. Naming Convention: Use descriptive names for your module and operations
  2. Parameter Validation: Always validate input parameters in tasks
  3. Error Handling: Provide meaningful error codes and messages
  4. Documentation: Document your API thoroughly following this template
  5. Testing: Use the testing patterns demonstrated in MOD_NAME
  6. Resource Management: Always clean up resources and memory properly

Task Design Patterns

  1. Standard Tasks: Request-response pattern with input/output parameters
  2. Long-Running: Tasks that may take significant time to complete
  3. Batch Operations: Tasks that process multiple items efficiently

Important Notes

  1. Template Purpose: MOD_NAME is primarily a template and testing module, not a production service.

  2. Admin Dependency: The MOD_NAME module requires the admin module to be initialized first.

  3. Concurrency Testing: The CoMutex and CoRwLock tests are useful for validating runtime behavior.

  4. Thread Safety: Operations are designed for single-threaded access per client instance.

  5. Development Template: Use this module as a starting point for custom Module development.

  6. Async-Only API: All client operations are asynchronous and return chi::Future<TaskType>. Call Wait() to block for completion.