Horus Automaton Interface

This document is part of the online Horus Documentation, under Horus Utilities.


We have come to the conclusion (after more than 10 years of active experience), that threads are a pain. Although Horus has supported and will continue to support threads, we are switching to a model that is easier to grasp, portable between machine architectures, and more efficient that threads. We call this the automaton model, since it is based on event-driven finite automata.

Automata are event driven. Event structures are allocated from event pools, and are enqueued to a particular automaton. Within an automaton, events run non-preempted and to completion (they are not blocked). Event handlers in different automata are allowed to run in true parallelism when run on a multi-processor. Therefore, shared utility modules, like maps, should still use the lock facility to deal with multi-processing. However, efficient spin-locks, rather than sleep-locks, will suffice.

For backward compatibility with threads, we have also implemented a thread interface to automata. In this implementation, t_create allocates an event from an event pool and enqueues it for later execution, as if it were a thread. For example, most Horus layers can run unchanged on both a threaded and on an automaton configuration.

SOURCES

machdep/auto/auto.h	(NOTE:  they should not be in a machdep directory)
machdep/auto/auto.c

INCLUDE

#include "muts.h"

INTERFACE

void au_enqueue(
	automaton_t au,
	auto_event_t ev,
	auto_sched_t sched
);
Enqueue an event. sched gives scheduling information like starting time, deadlines, priorities, or whatever.
auto_sweep_t au_sweep(
	automaton_t au,
	auto_pool_t pool,
	struct itimerval *it,
	auto_sched_t sched
);
Deliver a AU_SWEEP event starting at it->it_value, and after that at regular intervals given by it->it_interval.
void au_sweep_cancel(auto_sweep_t sweep);
Cancel an outstanding sweep event generator.
void au_read(
	automaton_t au,
	auto_pool_t pool,
	int fd,
	auto_sched_t sched
);
Deliver an AU_READ event when input becomes available on the given file descriptor.
automaton_t au_create(
	char *name,
	auto_pool_t pool,
	auto_deliver_t *deliver
);
Create one of these automata. ``deliver'' specifies how events should be delivered to this automaton. The first event is an AU_CREATE event.
void au_destroy(automaton_t au);
Delivers an AU_DESTROY event to an automaton. Automatically cancels time and input events. When the delivery of this event has completed, the automaton is destroyed.
void au_scheduler(void);
Check input and timers, and schedule events.

EXAMPLE

auto_sweep_t my_sweep;

void upcall(auto_event_t ev){
	char buf[128];

	printf("EVENT '%s' : ", ev->au->name);
	switch (ev->type) {
	case AU_CREATE:
		printf("CREATE");
		break;
	case AU_ERROR:
		printf("ERROR");
		break;
	case AU_GENERIC:
		printf("EVENT");
		break;
	case AU_SWEEP:
		printf("SWEEP");
		break;
	case AU_READ:
		printf("READ");
		if (!(ev->flags & AU_CANCELED))
			read(ev->u.read.fd, buf, sizeof(buf));
		break;
	case AU_DESTROY:
		printf("DESTROY");
		break;
	default:
		printf("UNKNOWN???");
	}

	if (ev->flags & AU_CANCELED)
		printf(" (CANCELED)");
	printf("\n");
}

void main(void){
	automaton_t au1;
	automaton_t au2;
	auto_deliver_t deliver;
	struct itimerval it;

	deliver.func = upcall;
	au1 = au_create("au1", 0, &deliver);
	au2 = au_create("au2", 0, &deliver);
	gettimeofday(&it.it_value, 0);
	it.it_interval.tv_sec = 3;
	it.it_interval.tv_usec = 0;
	au_sweep(au1, 0, &it, 0);
	au_read(au1, 0, 0, 0);
	it.it_value.tv_sec -= 10;
	it.it_interval.tv_sec = 2;
	it.it_interval.tv_usec = 0;
	my_sweep = au_sweep(au2, 0, &it, 0);
	au_read(au2, 0, 0, 0);
	au_scheduler();
}

FUTURE WORK

One current problem with this model is that even the user application cannot block on semaphores, a system call, or an RPC. However, as long as there is at most one application thread (or one per processor), we could allow blocking. We are going to support this in the near future.


This document is part of the online Horus Documentation, under Horus Utilities.