The Memory Channel Utility

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


--MUTS provides a utility to allocate memory in a controlled way. Each module or instance of a module can have its own memory channel. A memory scheduler decides how fast a module can allocate memory, depending on priority and availability. If the module allocates memory too fast, it will be blocked for a while.

Of course, all these routines are perfectly multiprocessor safe. If, in spite of everything, this module still runs out of memory, it will print a message once every while, but won't fail. However, there is a distinct possibility that the system is deadlocked by then.

SOURCES

include/muts/mem_chan.h
src/muts/mem_chan.c

INCLUDE

#include "muts.h"

SWITCHES

#define NO_MEM_CHAN	/* disables the memory scheduler */
#define MC_OVERHEAD	/* byte overhead of memory allocation */

INTERFACE

struct mem_chan *mc_create(
	char *name,
	int priority,
	int capacity
);
Create a memory channel. Name is used for debugging purposes (it is usually the name of module or something like that). Priority is an integer between 1 and 255. A channel with priority p1 gets memory pumped into it at a rate p1/p2 faster than a channel of priority p2. The capacity of the channel is limited as specified. The capacity may be zero.
struct mem_chan *mc_child(
	struct mem_chan *parent,
	char *name,
	int priority,
	int capacity
);
Like mc_create, but creates a child channel, i.e., a channel that allocates memory of the given parent channel. The capacity of the parent channel must be zero, that is, only zero capacity channels can get child channels.
void *mc_alloc(
	struct mem_chan *mc,
	int size
);
Allocate size bytes on the given channel. If there is not enough memory in the channel, the call will block until there is. Size may be larger than the capacity of the channel, in which case the allocation takes multiple phases internally until the channel has filled up enough times. This call can not return 0! Although technically trying to allocate memory of a zero-capacity channel should just block for ever, we consider that an error and will panic.
void *mc_try_alloc(
	struct mem_chan *mc,
	int size
);
Like mc_alloc, but fails if there's not enough memory in the channel.
void mc_free(
	struct mem_chan *mc,
	void *mem
);
Push the given memory back into the channel, where it will be available for immediate reallocation. If the channel overflows, this memory goes back into the general pool of memory. It's good programming practice that the specified memory was allocated of the same channel, although this implementation does not require it.
void *mc_realloc(
	struct mem_chan *mc,
	void *mem,
	int size
);
Resize the given piece of memory, and return a pointer to this new memory. Again, preferably the memory came originally from the same channel. If mem == 0, this call behaves like mc_alloc().
void *mc_string_copy(
	struct mem_chan *mc,
	char *string
);
Create a copy of the given, null-terminated string.
void *mc_printf(
	struct mem_chan *mc,
	char *fmt,
	...
);
Like sprintf, but returns a pointer to a buffer that can be freed using mc_free.
void *mc_vprintf(
	struct mem_chan *mc,
	char *fmt,
	va_list *args
);
Like vprintf.
int mc_contents(struct mem_chan *mc);
Returns how much memory the channel has currently available. If negative, it specifies how much memory threads are waiting for before you.
void mc_destroy(struct mem_chan *mc);
Get rid of the given channel.
error_t mc_start(void);
	Start the memory scheduler.  Has to be done after the threads
	and timer packages have been initialized, and after mc_avail
	has been called at least once.
void mc_init(void);
Initialize this module.

DEPENDENCY

This module calls routine "float mem_rate(void)", which is typically defined in mem_alloc.c. This routine returns to the module how many bytes of memory per second are available for allocation. The rate at which this module parcels out memory depends on how much it has given away already, and on this value avail. In emergency situations, this module may steal memory from channels to give back to the general allocator, or to redistribute over other channels.

EXAMPLE

not available yet

FUTURE WORK

The thread scheduler should be able to notify this module some way or other that all threads are blocked. One way of doing this would be to declare a really low priority thread here. When such is the case, we might as well pick a high priority channel that is waiting for more memory, and just give it to it.


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