~alecgraves/ravenring

High-performance and simple message passing middleware
add ravenring tests, remove private ring creation
add private ring functions

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~alecgraves/ravenring
read/write
git@git.sr.ht:~alecgraves/ravenring

You can also use your local clone with git send-email.

#ravenring

A high-performance shared-memory message passing library implemented using lock-free ring buffers.

"Do nothing that is of no use." - Miyamoto Musashi

#Features

  • Inter-galactic messaging protocol designed for talking to aliens!
    • see docs/WXF.md
  • Fast ring-buffer shared memory communication
    • Vaguely based on the LMAX disruptor
  • Cross-platform, portable C message passing code (from PIC µC's to x86_64)

#Usage

#Publisher:

#include <assert.h>
#include <string.h>

#include "ravenring/ravenring.h"

int main() {
	// Create shared memory ring buffer
	char *topic = "raventopic";
	int size = 32;  // bytes
	int rate =10000000;  // messages / s
	ravenring *raventopic = ravenring_create(topic, strlen(topic)-1, size, rate);
	assert(raventopic && "ring creation should not fail");

	// Allocate an empty message
	ravenmsg *msg = ravenmsg_create(size);
	assert(msg);

	uint64_t count = 0;
	while (1) {
		raventime start = raventime_now();
		// Build a message:
		// List["hello", count]
		ravenmsg_write_start(msg);
		ravenmsg_write_fn(msg, (int8_t*) "List", 4, 2);
		ravenmsg_write_string(msg, (int8_t*) "hello", 5);
		ravenmsg_write_i64(msg, count%(1024));

		// Publish the message
		ravenring_write(raventopic, msg->data, msg->cursor);

		// Sleep
		double elapsed = raventime_elapsed(start)*1e-9;
		double sleep_duration = 1.0/rate-elapsed < 0 ? 0 : 1.0/rate-elapsed;
		raventime_sleep(sleep_duration);
		count += 1;
	}
}

#Subscriber:

#include <assert.h>
#include <string.h>
#include <stdio.h>

#include "ravenring/ravenring.h"

int main() {
	// Connect to our shared memory ring buffer
	char *topic = "raventopic";
	ravenring *raventopic = ravenring_connect(topic, strlen(topic)-1);
	assert(raventopic);

	// Allocate an empty message
	ravenmsg *msg = ravenmsg_create(raventopic->shared->message_size);
	assert(msg);

	raventime last_read = raventime_now();
	raventime last_second = raventime_now();

	uint64_t messages_recieved = 0;
	while (1) {
		// Print how many messages we read in the last second
		uint64_t nanoseconds = raventime_elapsed(last_second);
		if(nanoseconds > 1e9) {

			printf("%f messages per second\n",
				(double)messages_recieved/(nanoseconds*1e-9));
			last_second = raventime_now();
			messages_recieved = 0;
		}

		if (ravenring_read(raventopic, msg->data, msg->max_length) < 0) {
			// No new message, take a break
			raventime_nap(last_read, 100e-9, 1e-3);
			continue;
		}

		// Read succeeded; de-serialize our message
		// ["string", count]
		int8_t head[16];
		int64_t headsz = 16;
		int8_t str[16];
		int64_t strsz = 16;
		int64_t elements=0;
		int64_t count;

		int ret = 0;
		ret |= ravenmsg_read_start(msg);
		ret |= ravenmsg_read_fn(msg, head, &headsz, 16, &elements);
		assert(elements==2);
		ret |= ravenmsg_read_str(msg, str, &strsz, 16);
		ret |= ravenmsg_read_i64(msg, &count);
		assert(ret >= 0);

		messages_recieved += 1;
		last_read = raventime_now();
	}
}

#Issues

  • [ ] Problems with reconnecting to a ring that already exists
    • there is an error with 'create''s handling of existing rings. Also, sometimes reconnecting can cause the ring to lock or something
    • (but dead ring could be because I killed the publisher in the critical section. idk.)
  • [ ] Need to make ring revival automatic (on connect?)
Do not follow this link