aboutsummaryrefslogtreecommitdiffstats
path: root/include/litmus/feather_buffer.h
blob: 6c18277fdfc9fc681bb03363a2ed8a46fe9fa448 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#ifndef _FEATHER_BUFFER_H_
#define _FEATHER_BUFFER_H_

/* requires UINT_MAX and memcpy */

#define SLOT_FREE	0
#define	SLOT_BUSY 	1
#define	SLOT_READY	2

struct ft_buffer {
	unsigned int	slot_count;
	unsigned int	slot_size;

	int 		free_count;
	unsigned int 	write_idx;
	unsigned int 	read_idx;

	char*		slots;
	void*		buffer_mem;
	unsigned int	failed_writes;
};

static inline int init_ft_buffer(struct ft_buffer*	buf,
				 unsigned int 		slot_count,
				 unsigned int 		slot_size,
				 char*			slots,
				 void* 			buffer_mem)
{
	int i = 0;
	if (!slot_count || UINT_MAX % slot_count != slot_count - 1) {
		/* The slot count must divide UNIT_MAX + 1 so that when it
		 * wraps around the index correctly points to 0.
		 */
		return 0;
	} else {
		buf->slot_count    = slot_count;
		buf->slot_size     = slot_size;
		buf->slots         = slots;
		buf->buffer_mem    = buffer_mem;
		buf->free_count    = slot_count;
		buf->write_idx     = 0;
		buf->read_idx      = 0;
		buf->failed_writes = 0;
		for (i = 0; i < slot_count; i++)
			buf->slots[i] = SLOT_FREE;
		return 1;
	}
}

static inline int ft_buffer_start_write(struct ft_buffer* buf, void **ptr)
{
	int free = fetch_and_dec(&buf->free_count);
	unsigned int idx;
	if (free <= 0) {
		fetch_and_inc(&buf->free_count);
		*ptr = 0;
		fetch_and_inc(&buf->failed_writes);
		return 0;
	} else {
		idx  = fetch_and_inc((int*) &buf->write_idx) % buf->slot_count;
		buf->slots[idx] = SLOT_BUSY;
		*ptr = ((char*) buf->buffer_mem) + idx * buf->slot_size;
		return 1;
	}
}

static inline void ft_buffer_finish_write(struct ft_buffer* buf, void *ptr)
{
	unsigned int idx = ((char*) ptr - (char*) buf->buffer_mem) / buf->slot_size;
	buf->slots[idx]  = SLOT_READY;
}


/* exclusive reader access is assumed */
static inline int ft_buffer_read(struct ft_buffer* buf, void* dest)
{
	unsigned int idx;
	if (buf->free_count == buf->slot_count)
		/* nothing available */
		return 0;
	idx = buf->read_idx % buf->slot_count;
	if (buf->slots[idx] == SLOT_READY) {
		memcpy(dest, ((char*) buf->buffer_mem) + idx * buf->slot_size,
		       buf->slot_size);
		buf->slots[idx] = SLOT_FREE;
		buf->read_idx++;
		fetch_and_inc(&buf->free_count);
		return 1;
	} else
		return 0;
}


#endif