summaryrefslogtreecommitdiff
path: root/cesar/lib/blk.h
blob: 44f3c2ebf572b46e0de1e6a50e577a858d1062f0 (plain)
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#ifndef lib_blk_h
#define lib_blk_h
/* Cesar project {{{
 *
 * Copyright (C) 2007 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    lib/blk.h
 * \brief   512 byte memory blocks.
 * \ingroup lib
 *
 * Block allocator
 * ===============
 *
 * This entity provide 512 byte memory blocks allocation and reference
 * counting.  Each block counts the number of reference pointing to it.  The
 * user is responsible for managing this counter using addref and release
 * functions.  When the number of references of a block reach zero, the block
 * is freed.
 *
 * Each block is associated with a descriptor.  This descriptor is 16 byte
 * long. The first 8 bytes are reserved for the blk_t type and the rest could
 * be used for anything the user wants.  The type blk_t provide a chaining and
 * a pointer to data member.  This is the basis for hardware blocks chaining.
 *
 * The API is available in two flavors.  The first one works with descriptors.
 * The user can request one or more chained blocks and will be given pointers
 * to descriptors.  The second one works directly with data, hiding the
 * descriptor to the user.  In the second flavor, only one block can be
 * requested at a time, and performances can be lower as usage should be rare.
 *
 * An extra feature is provided for block allocated without a descriptor:
 * automatic destruction.  In this case, the descriptor is used to store the
 * destructor function pointer.
 *
 * The reference counter associated with the descriptor.  It is modified
 * atomically but once it reach zero reference, the block is freed
 * immediately.
 */

#include "lib/blame.h"

/** A block is 512 bytes. */
#define BLK_SIZE 512

/** A block descriptor is 16 bytes, that is greater than \c blk_t. */
#define BLK_DESC_SIZE 16

/** Memory block descriptor.
 * This structure stores information about a 512 byte memory block.  This
 * representation is shared between hardware and software.  */
struct blk_t
{
    /** Pointer to next descriptor. */
    struct blk_t *next;
    /** Pointer to data. */
    u8 *data;
};
typedef struct blk_t blk_t;

/**
 * Block destructor called just before the block memory is released.
 * \param  data  pointer to block data
 *
 * Destructor feature can only be used with block returned without a
 * descriptor as it is then used internally to store the destructor pointer.
 */
typedef void (*blk_destructor_t) (void *data);

BEGIN_DECLS

/**
 * Initialise the block allocator.
 */
void
blk_init (void);

/**
 * Return a newly allocated 512 byte block with its descriptor.
 * \return the descriptor pointer
 *
 * The \c next pointer in the block descriptor is undefined.
 */
blk_t *
blk_alloc_desc_ (void_FL);
#define blk_alloc_desc() blk_alloc_desc_ (_fL)

/**
 * Return a number of newly allocated 512 byte blocks with their descriptors.
 * \param  n  number of block
 * \param  last  where to write the last block descriptor pointer
 * \return  the first block descriptor
 *
 * The returned blocks descriptors are chained, the \c next pointer in the
 * last block descriptor is undefined.
 */
blk_t *
blk_alloc_desc_range_ (uint n, blk_t **last __FL);
#define blk_alloc_desc_range(n, last) blk_alloc_desc_range_ ((n), (last) __fL)

/**
 * Add a reference to a block.
 * \param  blk  the block to reference
 */
void
blk_addref_desc_ (blk_t *blk __FL);
#define blk_addref_desc(blk) blk_addref_desc_ ((blk) __fL)

/**
 * Add a reference to a list of blocks.
 * \param  first  first block to reference
 * \param  last  last block to reference
 */
void
blk_addref_desc_range_ (blk_t *first, blk_t *last __FL);
#define blk_addref_desc_range(first, last) \
    blk_addref_desc_range_ ((first), (last) __fL)

/**
 * Add a reference to a list of blocks, by number of blocks.
 * \param  first  first block to reference
 * \param  n  number of block
 */
void
blk_addref_desc_range_nb_ (blk_t *first, uint n __FL);
#define blk_addref_desc_range_nb(first, n) \
    blk_addref_desc_range_nb_ ((first), (n) __fL)

/**
 * Release a block reference.
 * \param  blk  the block to release
 */
void
blk_release_desc_ (blk_t *blk __FL);
#define blk_release_desc(blk) blk_release_desc_ ((blk) __fL)

/**
 * Release references for a list of blocks.
 * \param  first  first block to release
 * \param  last  last block to release
 */
void
blk_release_desc_range_ (blk_t *first, blk_t *last __FL);
#define blk_release_desc_range(first, last) \
    blk_release_desc_range_ ((first), (last) __fL)

/**
 * Release references for a list of blocks, by number of blocks.
 * \param  first  first block to release
 * \param  n  number of block
 */
void
blk_release_desc_range_nb_ (blk_t *first, uint n __FL);
#define blk_release_desc_range_nb(first, n) \
    blk_release_desc_range_nb_ ((first), (n) __fL)

/**
 * Allocate a 512 byte block, without descriptor.
 * \return  the newly allocated block
 */
void *
blk_alloc_ (void_FL);
#define blk_alloc() blk_alloc_ (_fL)

/**
 * Allocate a zero'ed 512 byte block, without descriptor.
 * \return  the newly allocated block
 */
void *
blk_alloc_zero_ (void_FL);
#define blk_alloc_zero() blk_alloc_zero_ (_fL)

/**
 * Allocate a 512 byte block, and save the destructor.
 * \param  destructor  destructor function pointer
 * \return  the newly allocated block
 */
void *
blk_new_ (blk_destructor_t destructor __FL);
#define blk_new(destructor) blk_new_ ((destructor) __fL)

/**
 * Add a reference to a block without descriptor.
 * \param  data  pointer to block data
 */
void
blk_addref_ (void *data __FL);
#define blk_addref(data) blk_addref_ ((data) __fL)

/**
 * Release a block reference and call the optional destructor if the block is
 * freed.
 * \param  data  pointer to block data
 */
void
blk_release_ (void *data __FL);
#define blk_release(data) blk_release_ ((data) __fL)

/**
 * Check if all the blocks previously allocated are now free.
 * \return  true if all blocks are free
 *
 * Check if the number of blocks freed is equals to the number of blocks
 * allocated and if the number of blocks released is equals to the number of
 * blocks referenced.
 */
bool
blk_check_memory (void);

/**
 * Print memory blocks informations.
 *
 * Print the number of blocks allocated, freed, referenced, and released.
 */
void
blk_print_memory (void);

/**
 * Querry blk when a huge number of blocks are needed.
 * \return  number of free blocks which could be allocated, 0 otherwise.
 *
 * Each time a numerous quantity of blocks are needed to handle a stuff, this
 * function should be called. When the number of blocks reach a critical level
 * (not enough) this function will return false, the client should delay the
 * allocation request. Otherwise, the client can allocate the quantity of
 * blocks needed.
 *
 * The slack level is configurable with a CONFIG_BLK_SLACK = X in the Config
 * file. X is the minimum number of blocks under the one, the memory level
 * is considered as critical.
 */
uint
blk_slack (void);

/**
 * Get value of free blocks.
 * \return  value of free blocks.
 *
 */
uint
blk_free_nb (void);

END_DECLS

#endif /* lib_blk_h */