We shall now discuss how inet allocates memory to store the data which is sent and received.
This is handled in buf.c.
1 /*
2 This file contains routines for buffer management.
3
4 Copyright 1995 Philip Homburg
5 */
6
7 #define BUF_IMPLEMENTATION 1 /* Avoid some macros */
8
9 #include "inet.h"
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "generic/assert.h"
15 #include "generic/buf.h"
16 #include "generic/type.h"
17
18 THIS_FILE
19
BUF_USEMALLOC determines whether storage is allocated using malloc or by using arrays.
If BUF_USEMALLOC is defined, storage is allocated using malloc.
If BUF_USEMALLOC is not defined, storage is allocated using arrays.
Henceforth we shall assume storage using arrays.
We shall only handle the case when storage is allocated without malloc - by using arrays.
20 #ifndef BUF_USEMALLOC
21 #define BUF_USEMALLOC 0
22 #endif
23
Storage is allocated in chunks of 512 bytes of data since CRAMPED is not defined.
24 #ifndef BUF512_NR
25 #if CRAMPED
26 #define BUF512_NR 32
27 #else
28 #define BUF512_NR 128
29 #endif
30 #endif
31 #ifndef BUF2K_NR
32 #define BUF2K_NR 0
33 #endif
34 #ifndef BUF32K_NR
35 #define BUF32K_NR 0
36 #endif
37
ACC_NR defines the number of accessors in the accessors array which is an array of acc_t structures.
38 #define ACC_NR ((BUF512_NR+BUF2K_NR+BUF32K_NR)*3/2)
39 #define CLIENT_NR 6
40
DECLARE_TYPE declares a structure which holds the data.
DECLARE_STORAGE declares an array of the structure.
41 #define DECLARE_TYPE(Tag, Type, Size) \
42 typedef struct Tag \
43 { \
44 buf_t buf_header; \
45 char buf_data[Size]; \
46 } Type
47
48 #if BUF_USEMALLOC
49 #define DECLARE_STORAGE(Type, Ident, Nitems) \
50 PRIVATE Type *Ident
51
52 #define ALLOC_STORAGE(Ident, Nitems, Label) \
53 do \
54 { \
55 printf("buf.c: malloc %d %s\n", Nitems, Label); \
56 Ident= malloc(sizeof(*Ident) * Nitems); \
57 if (!Ident) \
58 ip_panic(( "unable to alloc %s", Label )); \
59 } while(0)
60 #else
61 #define DECLARE_STORAGE(Type, Ident, Nitems) \
62 PRIVATE Type Ident[Nitems]
63
64 #define ALLOC_STORAGE(Ident, Nitems, Label) \
65 (void)0
66 #endif
67
The buffer structure is declared below.
buffers512 is the array which stores the data. buffers512 is an array of Buf512_t structures.
Buf512_t is the structure that holds buffer data.
A Buf512_t structure has 2 parts: the buf_header header field which stores information about the
buffer data and a buf_data field which stores the data.
buffers512 is an array of Buf512_t structures.
In the code below, buffers512 has BUF512_NR elements of Buf512_t structures.
Each element in buffers512 can store 512 bytes of data.
buf512_freelist points to a freelist of accessors (acc_t structures) which are free and can be used and which has buf_t structure allocated to it ie the acc_buffer is not null.
It is used by bf_memreq to return a acc_t structure which has a buffer allocated to it
but the buffer is not being used by another acc_t structure.
The buf512_freelist freelist is made up of accessors (acc_t structures).
An acc_t structure holds a pointer to a buf_t structure and holds pointers to other acc_t structures
which allows several buffers to link together in a singly linked list
so that inet can hold data of arbitrary size.
We shall now go over the buf_t structure. buf_t is defined in buf.h. Ignoring certain defines buf_t is defined as follows:
buf_linkC: holds the number of accessors which holds pointers to this structure. If buf_linkC = 0 the buffer goes back to one of the free lists.
buf_free: pointer to the function which is called to free the acc_t structures which holds the buffer.
buf_size: amount (in byes) of data held in buf_data.
buf_data_p: pointer to the buf_data array which holds the data.
We shall now go over the acc_t structure. acc_t is defined in buf.h. In general the specific implementations of the protocols (as in udp.c) access the buf_t structure indirectly throught the acc_t structure. Ignoring certain defines acc_t is defined as follows:
acc_linkC: holds the number of variables which points to this structure. If acc_linkC = 0 the buffer goes back to one of the free lists.
acc_offset: holds an offset in to the buffer data.
acc_length: length of buffer data which acc_t structure is storing.
acc_buffer: points to buf_t structure which stores the data.
acc_next: points to next acc_t structure in linked list. When the acc_t structure is not being used it points to the next free item in a linked list. When it's not free, the linked list is used in the following way for example: one acc_t structure points to the ip header, acc_next points to the udp header., the acc_next of that acc_t structure points to the data, etc. In the case the acc_t structure is not free, the different buffers which belong to the different acc_t structures in the linked list are considered to store the same chunk of data. Therefore if the size of the array pointed to by buf_data_p is not large enough to hold the chunk of data desired, new acc_t structures (with their own buf_data_p arrays) are used until there are enough buf_data_p buffers to hold all of data. The acc_t structures are linked together by the acc_next pointer.
acc_ext_link: points to next acc_t structure in linked list. It's used by the implementation of a protocol.
One define which is used quite often is the following from buf.h
68 #if BUF512_NR
69 DECLARE_TYPE(buf512, buf512_t, 512);
70 PRIVATE acc_t *buf512_freelist;
71 DECLARE_STORAGE(buf512_t, buffers512, BUF512_NR);
72 FORWARD void bf_512free ARGS(( acc_t *acc ));
73 #endif
74 #if BUF2K_NR
75 DECLARE_TYPE(buf2K, buf2K_t, (2*1024));
76 PRIVATE acc_t *buf2K_freelist;
77 DECLARE_STORAGE(buf2K_t, buffers2K, BUF2K_NR);
78 FORWARD void bf_2Kfree ARGS(( acc_t *acc ));
79 #endif
80 #if BUF32K_NR
81 DECLARE_TYPE(buf32K, buf32K_t, (32*1024));
82 PRIVATE acc_t *buf32K_freelist;
83 DECLARE_STORAGE(buf32K_t, buffers32K, BUF32K_NR);
84 FORWARD void bf_32Kfree ARGS(( acc_t *acc ));
85 #endif
86
acc_freelist points to a freelist of acc_t structures which are free and can
be used and which does not have a buf_t structure allocated to it ie the acc_buffer is null. It is used
by bf_dupacc to return a copy of the original acc_t structure. Since the
acc_t structure stores a pointer to the buf_t structure, bf_dupacc merely
sets the pointer to the buf_t structure in the original buffer and no new
buf_t structure need be allocated to it.
87 PRIVATE acc_t *acc_freelist;
accessors is an array of acc_t structures. An acc_t structure holds a pointer
to a buf_t structure. A buf_t structure holds a pointer to a buf_data field
and holds information about the data stored in the buf_data field.
88 DECLARE_STORAGE(acc_t, accessors, ACC_NR);
89
The freereq array which is called when a freelist runs out of free acc_t structures.
90 PRIVATE bf_freereq_t freereq[CLIENT_NR];
91 PRIVATE size_t bf_buf_gran;
92
93 PUBLIC size_t bf_free_bufsize;
94 PUBLIC acc_t *bf_temporary_acc;
95
96 #ifdef BUF_CONSISTENCY_CHECK
97 int inet_buf_debug;
98 unsigned buf_generation;
99 PRIVATE bf_checkreq_t checkreq[CLIENT_NR];
100 #endif
101
102 #ifndef BUF_TRACK_ALLOC_FREE
103 FORWARD acc_t *bf_small_memreq ARGS(( size_t size ));
104 #else
105 FORWARD acc_t *_bf_small_memreq ARGS(( char *clnt_file, int clnt_line,
106 size_t size ));
107 #define bf_small_memreq(a) _bf_small_memreq(clnt_file, clnt_line, a)
108 #endif
109 FORWARD void free_accs ARGS(( void ));
110 #ifdef BUF_CONSISTENCY_CHECK
111 FORWARD void count_free_bufs ARGS(( acc_t *list ));
112 FORWARD int report_buffer ARGS(( buf_t *buf, char *label, int i ));
113 #endif
114
bf_init initializes the buffer used to store data. We shall only handle
the case when storage is allocated without malloc - by using arrays (this
is done by not defining BUF_USEMALLOC) - and where each buffer stores 512
bytes of data (this is done by defining BUF512_NR).
115 PUBLIC void bf_init()
116 {
117 int i;
118 size_t size;
119 size_t buf_s;
120 acc_t *acc;
121
122 bf_buf_gran= BUF_S;
123 buf_s= 0;
124
The freereq array is called when a freelist runs out of free acc_t structures.
The elements of the freereq array are set to null at initialization time.
125 for (i=0;i<CLIENT_NR;i++)
126 freereq[i]=0;
127 #ifdef BUF_CONSISTENCY_CHECK
128 for (i=0;i<CLIENT_NR;i++)
129 checkreq[i]=0;
130 #endif
131
132 #if BUF512_NR
133 ALLOC_STORAGE(buffers512, BUF512_NR, "512B-buffers");
134 #endif
135 #if BUF2K_NR
136 ALLOC_STORAGE(buffers2K, BUF2K_NR, "2K-buffers");
137 #endif
138 #if BUF32K_NR
139 ALLOC_STORAGE(buffers32K, BUF32K_NR, "32K-buffers");
140 #endif
141 ALLOC_STORAGE(accessors, ACC_NR, "accs");
142
The two freelists pointed to by acc_freelist and buf512_freelist are set up in the following.
143 acc_freelist= NULL;
144 for (i=0;i<ACC_NR;i++)
145 {
146 memset(&accessors[i], '\0', sizeof(accessors[i]));
147
148 accessors[i].acc_linkC= 0;
149 accessors[i].acc_next= acc_freelist;
150 acc_freelist= &accessors[i];
151 }
152
153 #define INIT_BUFFERS(Ident, Nitems, Freelist, Freefunc) \
154 do \
155 { \
156 Freelist= NULL; \
157 for (i=0;i<Nitems;i++) \
158 { \
159 acc= acc_freelist; \
160 if (!acc) \
161 ip_panic(( "fewer accessors than buffers")); \
162 acc_freelist= acc->acc_next; \
163 acc->acc_linkC= 0; \
164 \
165 memset(&Ident[i], '\0', sizeof(Ident[i])); \
166 Ident[i].buf_header.buf_linkC= 0; \
167 Ident[i].buf_header.buf_free= Freefunc; \
168 Ident[i].buf_header.buf_size= \
169 sizeof(Ident[i].buf_data); \
170 Ident[i].buf_header.buf_data_p= \
171 Ident[i].buf_data; \
172 \
173 acc->acc_buffer= &Ident[i].buf_header; \
174 acc->acc_next= Freelist; \
175 Freelist= acc; \
176 } \
177 if (sizeof(Ident[0].buf_data) < bf_buf_gran) \
178 bf_buf_gran= sizeof(Ident[0].buf_data); \
179 if (sizeof(Ident[0].buf_data) > buf_s) \
180 buf_s= sizeof(Ident[0].buf_data); \
181 } while(0)
182
183 #if BUF512_NR
184 INIT_BUFFERS(buffers512, BUF512_NR, buf512_freelist, bf_512free);
185 #endif
186 #if BUF2K_NR
187 INIT_BUFFERS(buffers2K, BUF2K_NR, buf2K_freelist, bf_2Kfree);
188 #endif
189 #if BUF32K_NR
190 INIT_BUFFERS(buffers32K, BUF32K_NR, buf32K_freelist, bf_32Kfree);
191 #endif
192
193 #undef INIT_BUFFERS
194
195 assert (buf_s == BUF_S);
196 }
197
198 #ifndef BUF_CONSISTENCY_CHECK
bf_logon is called by the user process when it initializes.
bf_logon() defines the freereq array which is called when a freelist runs out of free acc_t structures.
For example, free_accs calls the freereq array functions to free acc_t structures.
199 PUBLIC void bf_logon(func)
200 bf_freereq_t func;
201 #else
202 PUBLIC void bf_logon(func, checkfunc)
203 bf_freereq_t func;
204 bf_checkreq_t checkfunc;
205 #endif
206 {
207 int i;
208
209 for (i=0;i<CLIENT_NR;i++)
210 if (!freereq[i])
211 {
212 freereq[i]=func;
213 #ifdef BUF_CONSISTENCY_CHECK
214 checkreq[i]= checkfunc;
215 #endif
216 return;
217 }
218
219 ip_panic(( "buf.c: to many clients" ));
220 }
221
222 /*
223 bf_memreq
224 */
225
bf_memreq(size) returns a acc_t structure whose bf_bufsize() is size. It calls freereq if
there are not any free acc_t structures in the buf512_freelist free list.
226 #ifndef BUF_TRACK_ALLOC_FREE
227 PUBLIC acc_t *bf_memreq(size)
228 #else
229 PUBLIC acc_t *_bf_memreq(clnt_file, clnt_line, size)
230 char *clnt_file;
231 int clnt_line;
232 #endif
233 size_t size;
234 {
235 acc_t *head, *tail, *new_acc;
236 buf_t *buf;
237 int i,j;
238 size_t count;
239
240 assert (size>0);
241
242 head= NULL;
Loop allocates an accessor which is the head of a linked list of accessors.
Each accessor holds a pointer to a buffer.
The sum of the size of the buffers is equal to size.
The sum of the size of the buffers is returned by bf_bufsize().
If size of the data > 512 bytes, the data is stored in multiple accessors such that
the sum of the size of accessors is equal to the sum of the size of the accessors.
243 while (size)
244 {
245 new_acc= NULL;
246
247 /* Note the tricky dangling else... */
248 #define ALLOC_BUF(Freelist, Bufsize) \
249 if (Freelist && (Bufsize == BUF_S || size <= Bufsize)) \
250 { \
251 new_acc= Freelist; \
252 Freelist= new_acc->acc_next; \
253 \
Accessor should not be used. Therefore acc_linkC = 0.
254 assert(new_acc->acc_linkC == 0); \
Mark accessor being used for first time.
255 new_acc->acc_linkC= 1; \
256 buf= new_acc->acc_buffer; \
Buffer should not be used. Therefore buf_linkC = 0.
257 assert(buf->buf_linkC == 0); \
Mark buffer being used for first time.
258 buf->buf_linkC= 1; \
259 } \
260 else
261
262 /* Sort attempts by buffer size */
BUF_S is defined as 512 in inet/const.h. Therefore so long as buf512_freelist still has elements in the list, it will allocate accessors from the buf512_freelist list.
263 #if BUF512_NR
264 ALLOC_BUF(buf512_freelist, 512)
265 #endif
266 #if BUF2K_NR
267 ALLOC_BUF(buf2K_freelist, 2*1024)
268 #endif
269 #if BUF32K_NR
270 ALLOC_BUF(buf32K_freelist, 32*1024)
271 #endif
272 #undef ALLOC_BUF
Free some accessors if there are currently no free accessors.
273 {
274 DBLOCK(1, printf("freeing buffers\n"));
275
276 bf_free_bufsize= 0;
277 for (i=0; bf_free_bufsize<size && i<MAX_BUFREQ_PRI;
278 i++)
279 {
280 for (j=0; j<CLIENT_NR; j++)
281 {
282 if (freereq[j])
283 (*freereq[j])(i);
284 }
285 #if DEBUG
286 { acc_t *acc;
287 j= 0; for(acc= buf512_freelist; acc; acc= acc->acc_next) j++;
288 printf("# of free 512-bytes buffer is now %d\n", j); }
289 #endif
290 }
291 #if DEBUG
292 { printf("last level was level %d\n", i-1); }
293 #endif
294 if (bf_free_bufsize<size)
295 ip_panic(( "not enough buffers freed" ));
296
297 continue;
298 }
299
300 #ifdef BUF_TRACK_ALLOC_FREE
301 new_acc->acc_alloc_file= clnt_file;
302 new_acc->acc_alloc_line= clnt_line;
303 buf->buf_alloc_file= clnt_file;
304 buf->buf_alloc_line= clnt_line;
305 #endif
306
307 if (!head)
308 head= new_acc;
309 else
310 tail->acc_next= new_acc;
311 tail= new_acc;
312
313 count= tail->acc_buffer->buf_size;
314 if (count > size)
315 count= size;
316
317 tail->acc_offset= 0;
318 tail->acc_length= count;
319 size -= count;
320 }
Mark tail as end of linked list by setting the next pointer to null.
321 tail->acc_next= 0;
322
323 #if DEBUG
324 bf_chkbuf(head);
325 #endif
326
327 return head;
328 }
329
330 /*
331 bf_small_memreq
332 */
333
334 #ifndef BUF_TRACK_ALLOC_FREE
335 PRIVATE acc_t *bf_small_memreq(size)
336 #else
337 PRIVATE acc_t *_bf_small_memreq(clnt_file, clnt_line, size)
338 char *clnt_file;
339 int clnt_line;
340 #endif
341 size_t size;
342 {
343 return bf_memreq(size);
344 }
345
bf_afree(acc) attempts to free all of the acc_t structures in the linked list whose head is pointed
to by acc. If the buf_t structure acc_buffer is still being used by
another acc_t structure, acc is put on the acc_freelist; else acc is put on the buf512_freelist.
346 #ifndef BUF_TRACK_ALLOC_FREE
347 PUBLIC void bf_afree(acc)
348 #else
349 PUBLIC void _bf_afree(clnt_file, clnt_line, acc)
350 char *clnt_file;
351 int clnt_line;
352 #endif
353 acc_t *acc;
354 {
355 acc_t *next_acc;
356 buf_t *buf;
357
358 while (acc)
359 {
360 #if defined(bf_afree)
361 DIFBLOCK(1, (acc->acc_linkC <= 0),
362 printf("clnt_file= %s, clnt_line= %d\n",
363 clnt_file, clnt_line));
364 #endif
365 assert (acc->acc_linkC>0);
Checks if the accessor is still being used. If it is then no more accessors are freed.
366 if (--acc->acc_linkC > 0)
367 break;
368
369 #ifdef BUF_TRACK_ALLOC_FREE
370 acc->acc_free_file= clnt_file;
371 acc->acc_free_line= clnt_line;
372 #endif
373 buf= acc->acc_buffer;
374 assert (buf);
375
376 #if defined(bf_afree)
377 DIFBLOCK(1, (buf->buf_linkC == 0),
378 printf("clnt_file= %s, clnt_line= %d\n",
379 clnt_file, clnt_line));
380 #endif
381 assert (buf->buf_linkC>0);
Checks if the buf_t structure acc_buffer of the accessor is still being used.
If it is then acc is put on the acc_freelist.
Checks if the buffer is still being used by another accessor. If it is then the accessor is
placed in the acc_freelist list and acc_buffer is set to null.
382 if (--buf->buf_linkC > 0)
383 {
384 acc->acc_buffer= NULL;
385 next_acc= acc->acc_next;
386 acc->acc_next= acc_freelist;
387 acc_freelist= acc;
388 #ifdef BUF_CONSISTENCY_CHECK
389 if (inet_buf_debug)
390 {
391 acc->acc_offset= 0xdeadbeaf;
392 acc->acc_length= 0xdeadbeaf;
393 acc->acc_buffer= (buf_t *)0xdeadbeaf;
394 acc->acc_ext_link= (acc_t *)0xdeadbeaf;
395 }
396 #endif
397 acc= next_acc;
398 continue;
399 }
400
If the buffer is not being used by another accessor, the accessor is
placed in the buf512_freelist list by calling buf->buf_free(acc).
401 bf_free_bufsize += buf->buf_size;
402 #ifdef BUF_TRACK_ALLOC_FREE
403 buf->buf_free_file= clnt_file;
404 buf->buf_free_line= clnt_line;
405 #endif
406 next_acc= acc->acc_next;
407 buf->buf_free(acc);
408 acc= next_acc;
409 continue;
410 }
411 }
bf_dupacc(acc_ptr) returns a copy of the original accessor pointed to by acc_ptr.
bf_dupacc does the copy by copying the contents of the original accessor to the new accessor.
412
413 #ifndef BUF_TRACK_ALLOC_FREE
414 PUBLIC acc_t *bf_dupacc(acc_ptr)
415 #else
416 PUBLIC acc_t *_bf_dupacc(clnt_file, clnt_line, acc_ptr)
417 char *clnt_file;
418 int clnt_line;
419 #endif
420 register acc_t *acc_ptr;
421 {
422 register acc_t *new_acc;
423 int i, j;
424
Checks if there are any more accessors in the acc_freelist free list.
425 if (!acc_freelist)
426 {
If there are no more accessors in the acc_freelist free list, call free_accs() to get more.
427 free_accs();
428 if (!acc_freelist)
429 ip_panic(( "buf.c: out of accessors" ));
430 }
431 new_acc= acc_freelist;
432 acc_freelist= new_acc->acc_next;
433
Copy old accessor to new accessor.
434 *new_acc= *acc_ptr;
Increment acc_linkC because another accessor is pointing to it.
435 if (acc_ptr->acc_next)
436 acc_ptr->acc_next->acc_linkC++;
437 if (acc_ptr->acc_buffer)
Increment buf_linkC because another accessor is pointing to it.
438 acc_ptr->acc_buffer->buf_linkC++;
439 new_acc->acc_linkC= 1;
440 #ifdef BUF_TRACK_ALLOC_FREE
441 new_acc->acc_alloc_file= clnt_file;
442 new_acc->acc_alloc_line= clnt_line;
443 #endif
444 return new_acc;
445 }
446
acc_ptr is the head of a linked list of accesssors.
Each accessor holds a pointer to a buffer.
The sum of the size of the buffers is returned by bf_bufsize().
447 PUBLIC size_t bf_bufsize(acc_ptr)
448 register acc_t *acc_ptr;
449 {
450 register size_t size;
451
452 assert(acc_ptr);
453
454 size=0;
455
456 while (acc_ptr)
457 {
458 assert(acc_ptr >= accessors && acc_ptr <= &accessors[ACC_NR-1]);
459 size += acc_ptr->acc_length;
460 acc_ptr= acc_ptr->acc_next;
461 }
462 return size;
463 }
464
I have no idea what bf_packIffLess() does.
465 #ifndef BUF_TRACK_ALLOC_FREE
466 PUBLIC acc_t *bf_packIffLess(pack, min_len)
467 #else
468 PUBLIC acc_t *_bf_packIffLess(clnt_file, clnt_line, pack, min_len)
469 char *clnt_file;
470 int clnt_line;
471 #endif
472 acc_t *pack;
473 int min_len;
474 {
475 if (!pack || pack->acc_length >= min_len)
476 return pack;
477
478 #if DEBUG
479 #ifdef bf_packIffLess
480 { where(); printf("calling bf_pack because of %s %d: %d\n", bf_pack_file,
481 bf_pack_line, min_len); }
482 #endif
483 #endif
484 return bf_pack(pack);
485 }
486
I have no idea what bf_pack() does.
487 #ifndef BUF_TRACK_ALLOC_FREE
488 PUBLIC acc_t *bf_pack(old_acc)
489 #else
490 PUBLIC acc_t *_bf_pack(clnt_file, clnt_line, old_acc)
491 char *clnt_file;
492 int clnt_line;
493 #endif
494 acc_t *old_acc;
495 {
496 acc_t *new_acc, *acc_ptr_old, *acc_ptr_new;
497 size_t size, offset_old, offset_new, block_size, block_size_old;
498
499 /* Check if old acc is good enough. */
500 if (!old_acc || !old_acc->acc_next && old_acc->acc_linkC == 1 &&
501 old_acc->acc_buffer->buf_linkC == 1)
502 {
503 return old_acc;
504 }
505
506 size= bf_bufsize(old_acc);
507 assert(size > 0);
508 new_acc= bf_memreq(size);
509 acc_ptr_old= old_acc;
510 acc_ptr_new= new_acc;
511 offset_old= 0;
512 offset_new= 0;
513 while (size)
514 {
515 assert (acc_ptr_old);
516 if (offset_old == acc_ptr_old->acc_length)
517 {
518 offset_old= 0;
519 acc_ptr_old= acc_ptr_old->acc_next;
520 continue;
521 }
522 assert (offset_old < acc_ptr_old->acc_length);
523 block_size_old= acc_ptr_old->acc_length - offset_old;
524 assert (acc_ptr_new);
525 if (offset_new == acc_ptr_new->acc_length)
526 {
527 offset_new= 0;
528 acc_ptr_new= acc_ptr_new->acc_next;
529 continue;
530 }
531 assert (offset_new < acc_ptr_new->acc_length);
532 block_size= acc_ptr_new->acc_length - offset_new;
533 if (block_size > block_size_old)
534 block_size= block_size_old;
535 memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
536 ptr2acc_data(acc_ptr_old)+offset_old, block_size);
537 offset_new += block_size;
538 offset_old += block_size;
539 size -= block_size;
540 }
541 bf_afree(old_acc);
542 return new_acc;
543 }
544
bf_cut(data, offset, length) returns a copy of the chunk of data starting with
offset and ending at offset + length - 1. It does not free the original data.
545 #ifndef BUF_TRACK_ALLOC_FREE
546 PUBLIC acc_t *bf_cut (data, offset, length)
547 #else
548 PUBLIC acc_t *_bf_cut (clnt_file, clnt_line, data, offset, length)
549 char *clnt_file;
550 int clnt_line;
551 #endif
552 register acc_t *data;
553 register unsigned offset;
554 register unsigned length;
555 {
556 register acc_t *head, *tail;
557
558 if (!data && !offset && !length)
559 return 0;
560 #ifdef BUF_TRACK_ALLOC_FREE
561 assert(data ||
562 (printf("from %s, %d: %u, %u\n",
563 clnt_file, clnt_line, offset, length), 0));
564 #else
565 assert(data);
566 #endif
567
568 assert(data);
569 #if DEBUG
570 bf_chkbuf(data);
571 #endif
572
If length = 0 return an accessor with no data.
573 if (!length)
574 {
575 head= bf_dupacc(data);
576 bf_afree(head->acc_next);
577 head->acc_next= 0;
578 head->acc_length= 0;
579 #if DEBUG
580 bf_chkbuf(data);
581 #endif
582 return head;
583 }
Search for accessor which has the data beginning at offset.
584 while (data && offset>=data->acc_length)
585 {
586 offset -= data->acc_length;
587 data= data->acc_next;
588 }
589
590 assert (data);
591
Free the accessors which are holding data > offset.
592 head= bf_dupacc(data);
593 bf_afree(head->acc_next);
594 head->acc_next= 0;
Variable offset = bytes of excess data in accessor pointed to by head.
595 head->acc_offset += offset;
596 head->acc_length -= offset;
Set the variable length equal to the size of data still needed.
If length (size requested) < head->acc_length (size of head accessor), set size of head accessor to length.
597 if (length >= head->acc_length)
598 length -= head->acc_length;
599 else
600 {
601 head->acc_length= length;
602 length= 0;
603 }
604 tail= head;
605 data= data->acc_next;
Copy the data to new accessors by calling bf_dupacc(data) for the size(length) given.
Make a "deep copy" of the data (rather than a "shallow copy") by copying the contents the accessors
and not simply make a new pointer to the accessors.
606 while (data && length && length>=data->acc_length)
607 {
608 tail->acc_next= bf_dupacc(data);
609 tail= tail->acc_next;
610 bf_afree(tail->acc_next);
611 tail->acc_next= 0;
612 data= data->acc_next;
613 length -= tail->acc_length;
614 }
615 if (length)
616 {
If there is still data to be copied there the variable data should not be null.
617 #ifdef bf_cut
618 assert (data ||
619 (printf("bf_cut called from %s:%d\n",
620 clnt_file, clnt_line), 0));
621 #else
622 assert (data);
623 #endif
Copy data.
624 tail->acc_next= bf_dupacc(data);
625 tail= tail->acc_next;
Free extra data.
626 bf_afree(tail->acc_next);
Set acc_length to the remaining data requested.
627 tail->acc_next= 0;
628 tail->acc_length= length;
629 }
630 #if DEBUG
631 bf_chkbuf(data);
632 #endif
633 return head;
634 }
635
bf_delhead (data, offset) returns a copy of the chunk of data starting with offset. It frees the original accessors.
636 #ifndef BUF_TRACK_ALLOC_FREE
637 PUBLIC acc_t *bf_delhead (data, offset)
638 #else
639 PUBLIC acc_t *_bf_delhead (clnt_file, clnt_line, data, offset)
640 char *clnt_file;
641 int clnt_line;
642 #endif
643 register acc_t *data;
644 register unsigned offset;
645 {
646 acc_t *new_acc;
647
648 assert(data);
649
650 /* Find the acc we need to modify. */
651 new_acc= data;
652 while(offset >= new_acc->acc_length)
653 {
654 offset -= new_acc->acc_length;
655 new_acc= new_acc->acc_next;
656 #ifdef BUF_TRACK_ALLOC_FREE
657 assert(new_acc || (printf("called from %s, %d\n",
658 clnt_file, clnt_line),0));
659 #else
660 assert(new_acc);
661 #endif
662 }
663
664 /* Discard the old acc(s) */
665 if (new_acc != data)
666 {
Increment acc_linkC so that bf_afree does not free any accessors after new_acc.
667 new_acc->acc_linkC++;
668 bf_afree(data);
669 data= new_acc;
670 }
671
672 /* Make sure that acc_linkC == 1 */
No one else is using the accessor.
673 if (data->acc_linkC != 1)
674 {
675 new_acc= bf_dupacc(data);
676 bf_afree(data);
677 data= new_acc;
678 }
679
680 /* Delete the last bit by modifying acc_offset and acc_length */
681 data->acc_offset += offset;
682 data->acc_length -= offset;
683 return data;
684 }
685
bf_append() appends data_second to data_first. It frees the original accessors.
686 /*
687 bf_append
688 */
689
690 #ifndef BUF_TRACK_ALLOC_FREE
691 PUBLIC acc_t *bf_append(data_first, data_second)
692 #else
693 PUBLIC acc_t *_bf_append(clnt_file, clnt_line, data_first, data_second)
694 char *clnt_file;
695 int clnt_line;
696 #endif
697 acc_t *data_first;
698 acc_t *data_second;
699 {
700 acc_t *head, *tail, *new_acc, *acc_ptr_new, tmp_acc, *curr;
701 char *src_ptr, *dst_ptr;
702 size_t size, offset_old, offset_new, block_size_old, block_size;
703
704 if (!data_first)
705 return data_second;
706 if (!data_second)
707 return data_first;
708
709 head= 0;
710 while (data_first)
711 {
Make sure no one else is using the accessor.
712 if (data_first->acc_linkC == 1)
713 curr= data_first;
714 else
Copy the accessor and then free the original accessor.
715 {
716 curr= bf_dupacc(data_first);
717 assert (curr->acc_linkC == 1);
718 bf_afree(data_first);
719 }
720 data_first= curr->acc_next;
Only copy the accessor if there is data in it.
721 if (!curr->acc_length)
722 {
723 curr->acc_next= 0;
724 bf_afree(curr);
725 continue;
726 }
Place accessor in linked list.
727 if (!head)
728 head= curr;
729 else
730 tail->acc_next= curr;
731 tail= curr;
732 }
If there is no data in data_first return data_second.
733 if (!head)
734 return data_second;
735 tail->acc_next= 0;
736
Skip accessors which have no data.
737 while (data_second && !data_second->acc_length)
738 {
739 curr= data_second;
740 data_second= data_second->acc_next;
741 if (data_second)
742 data_second->acc_linkC++;
743 bf_afree(curr);
744 }
745 if (!data_second)
746 return head;
747
748 if (tail->acc_length + data_second->acc_length >
749 tail->acc_buffer->buf_size)
750 {
751 tail->acc_next= data_second;
752 return head;
753 }
754
If data in data_second fits in tail and tail is not used by anything else, then
copy the data from data_second to tail and put the rest of chunk of data in the
data_second linked list in the linked list pointed to by head.
755 if (tail->acc_buffer->buf_size == bf_buf_gran &&
756 tail->acc_buffer->buf_linkC == 1)
757 {
758 if (tail->acc_offset)
759 {
760 memmove(tail->acc_buffer->buf_data_p,
761 ptr2acc_data(tail), tail->acc_length);
762 tail->acc_offset= 0;
763 }
764 dst_ptr= ptr2acc_data(tail) + tail->acc_length;
765 src_ptr= ptr2acc_data(data_second);
766 memcpy(dst_ptr, src_ptr, data_second->acc_length);
767 tail->acc_length += data_second->acc_length;
768 tail->acc_next= data_second->acc_next;
769 if (data_second->acc_next)
770 data_second->acc_next->acc_linkC++;
771 bf_afree(data_second);
772 return head;
773 }
774
775 new_acc= bf_small_memreq(tail->acc_length+data_second->acc_length);
776 acc_ptr_new= new_acc;
777 offset_old= 0;
778 offset_new= 0;
779 size= tail->acc_length;
If data in data_second fits in tail and tail is used by someone else, then
get a new accessor acc_ptr_new (ie new_acc) and copy the old data from tail and data_second
to acc_ptr_new.
780 while (size)
781 {
782 assert (acc_ptr_new);
783 if (offset_new == acc_ptr_new->acc_length)
784 {
785 offset_new= 0;
786 acc_ptr_new= acc_ptr_new->acc_next;
787 continue;
788 }
789 assert (offset_new < acc_ptr_new->acc_length);
790 assert (offset_old < tail->acc_length);
791 block_size_old= tail->acc_length - offset_old;
792 block_size= acc_ptr_new->acc_length - offset_new;
793 if (block_size > block_size_old)
794 block_size= block_size_old;
795 memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
796 ptr2acc_data(tail)+offset_old, block_size);
797 offset_new += block_size;
798 offset_old += block_size;
799 size -= block_size;
800 }
801 offset_old= 0;
802 size= data_second->acc_length;
803 while (size)
804 {
805 assert (acc_ptr_new);
806 if (offset_new == acc_ptr_new->acc_length)
807 {
808 offset_new= 0;
809 acc_ptr_new= acc_ptr_new->acc_next;
810 continue;
811 }
812 assert (offset_new < acc_ptr_new->acc_length);
813 assert (offset_old < data_second->acc_length);
814 block_size_old= data_second->acc_length - offset_old;
815 block_size= acc_ptr_new->acc_length - offset_new;
816 if (block_size > block_size_old)
817 block_size= block_size_old;
818 memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
819 ptr2acc_data(data_second)+offset_old, block_size);
820 offset_new += block_size;
821 offset_old += block_size;
822 size -= block_size;
823 }
Replace tail and data_second with new_acc and put new_acc in the appropriate place in
the linked list headed by head.
824 tmp_acc= *tail;
825 *tail= *new_acc;
826 *new_acc= tmp_acc;
827
828 bf_afree(new_acc);
829 while (tail->acc_next)
830 tail= tail->acc_next;
831
832 tail->acc_next= data_second->acc_next;
833 if (data_second->acc_next)
834 data_second->acc_next->acc_linkC++;
835 bf_afree(data_second);
836 return head;
837 }
838
bf_512free(acc) puts the accessor acc at the head of the buf512_freelist list.
839 #if BUF512_NR
840 PRIVATE void bf_512free(acc)
841 acc_t *acc;
842 {
843 #ifdef BUF_CONSISTENCY_CHECK
844 if (inet_buf_debug)
845 memset(acc->acc_buffer->buf_data_p, 0xa5, 512);
846 #endif
847 acc->acc_next= buf512_freelist;
848 buf512_freelist= acc;
849 }
850 #endif
851 #if BUF2K_NR
852 PRIVATE void bf_2Kfree(acc)
853 acc_t *acc;
854 {
855 #ifdef BUF_CONSISTENCY_CHECK
856 if (inet_buf_debug)
857 memset(acc->acc_buffer->buf_data_p, 0xa5, 2*1024);
858 #endif
859 acc->acc_next= buf2K_freelist;
860 buf2K_freelist= acc;
861 }
862 #endif
863 #if BUF32K_NR
864 PRIVATE void bf_32Kfree(acc)
865 acc_t *acc;
866 {
867 #ifdef BUF_CONSISTENCY_CHECK
868 if (inet_buf_debug)
869 memset(acc->acc_buffer->buf_data_p, 0xa5, 32*1024);
870 #endif
871 acc->acc_next= buf32K_freelist;
872 buf32K_freelist= acc;
873 }
874 #endif
875
876 #ifdef BUF_CONSISTENCY_CHECK
877 PUBLIC int bf_consistency_check()
878 {
879 acc_t *acc;
880 buf_t *buf;
881 int silent;
882 int error;
883 int i;
884
885 buf_generation++;
886
887 for (i=0; i<CLIENT_NR; i++)
888 {
889 if (checkreq[i])
890 (*checkreq[i])();
891 }
892
893 /* Add information about free accessors */
894 for(acc= acc_freelist; acc; acc= acc->acc_next)
895 {
896 if (acc->acc_generation == buf_generation-1)
897 {
898 acc->acc_generation= buf_generation;
899 acc->acc_check_linkC= 0;
900 }
901 else
902 {
903 assert(acc->acc_generation == buf_generation &&
904 acc->acc_check_linkC > 0);
905 acc->acc_check_linkC= -acc->acc_check_linkC;
906 }
907 }
908
909 #if BUF512_NR
910 count_free_bufs(buf512_freelist);
911 #endif
912 #if BUF2K_NR
913 count_free_bufs(buf2K_freelist);
914 #endif
915 #if BUF32K_NR
916 count_free_bufs(buf32K_freelist);
917 #endif
918
919 error= 0;
920
921 /* Report about accessors */
922 silent= 0;
923 for (i=0, acc= accessors; i<ACC_NR; i++, acc++)
924 {
925 if (acc->acc_generation != buf_generation)
926 {
927 error++;
928 assert(acc->acc_generation == buf_generation-1);
929 acc->acc_generation= buf_generation;
930 if (!silent)
931 {
932 printf(
933 "acc[%d] (0x%x) has been lost with count %d, last allocated at %s, %d\n",
934 i, acc, acc->acc_linkC, acc->acc_alloc_file, acc->acc_alloc_line);
935 #if 0
936 silent= 1;
937 #endif
938 }
939 continue;
940 }
941 if (acc->acc_check_linkC == acc->acc_linkC)
942 continue;
943 error++;
944 if (acc->acc_check_linkC < 0)
945 {
946 if (!silent)
947 {
948 printf(
949 "acc[%d] is freed but still in use, allocated at %s, %d, freed at %s, %d\n",
950 i, acc->acc_alloc_file, acc->acc_alloc_line,
951 acc->acc_free_file, acc->acc_free_line);
952 }
953 acc->acc_check_linkC= -acc->acc_check_linkC;
954 if (acc->acc_check_linkC == acc->acc_linkC)
955 {
956 silent= 1;
957 continue;
958 }
959 }
960 if (!silent)
961 {
962 printf(
963 "# of tracked links (%d) for acc[%d] don't match with stored link count %d\n",
964 acc->acc_check_linkC, i, acc->acc_linkC);
965 printf("acc[%d] was allocated at %s, %d\n",
966 i, acc->acc_alloc_file, acc->acc_alloc_line);
967 silent=1;
968 }
969 }
970
971 /* Report about buffers */
972 #if BUF512_NR
973 {
974 for (i= 0; i<BUF512_NR; i++)
975 {
976 error |= report_buffer(&buffers512[i].buf_header,
977 "512-buffer", i);
978 }
979 }
980 #endif
981 #if BUF2K_NR
982 {
983 for (i= 0; i<BUF2K_NR; i++)
984 {
985 error |= report_buffer(&buffers2K[i].buf_header,
986 "2K-buffer", i);
987 }
988 }
989 #endif
990 #if BUF32K_NR
991 {
992 for (i= 0; i<BUF32K_NR; i++)
993 {
994 error |= report_buffer(&buffers32K[i].buf_header,
995 "32K-buffer", i);
996 }
997 }
998 #endif
999
1000 return !error;
1001 }
1002
1003 PRIVATE void count_free_bufs(list)
1004 acc_t *list;
1005 {
1006 acc_t *acc;
1007 buf_t *buf;
1008
1009 for(acc= list; acc; acc= acc->acc_next)
1010 {
1011 if (acc->acc_generation != buf_generation-1)
1012 {
1013 assert(acc->acc_generation == buf_generation &&
1014 acc->acc_check_linkC > 0);
1015 acc->acc_check_linkC= -acc->acc_check_linkC;
1016 continue;
1017 }
1018 acc->acc_generation= buf_generation;
1019 acc->acc_check_linkC= 0;
1020
1021 buf= acc->acc_buffer;
1022 if (buf->buf_generation == buf_generation-1)
1023 {
1024 buf->buf_generation= buf_generation;
1025 buf->buf_check_linkC= 0;
1026 continue;
1027 }
1028 assert(buf->buf_generation == buf_generation &&
1029 buf->buf_check_linkC > 0);
1030 buf->buf_check_linkC= -buf->buf_check_linkC;
1031 }
1032 }
1033
1034 PRIVATE int report_buffer(buf, label, i)
1035 buf_t *buf;
1036 char *label;
1037 int i;
1038 {
1039 if (buf->buf_generation != buf_generation)
1040 {
1041 assert(buf->buf_generation == buf_generation-1);
1042 buf->buf_generation= buf_generation;
1043 printf(
1044 "%s[%d] (0x%x) has been lost with count %d, last allocated at %s, %d\n",
1045 label, i, buf,
1046 buf->buf_linkC, buf->buf_alloc_file,
1047 buf->buf_alloc_line);
1048 return 1;
1049 }
1050 if (buf->buf_check_linkC == buf->buf_linkC)
1051 return 0;
1052 if (buf->buf_check_linkC < 0)
1053 {
1054 printf(
1055 "%s[%d] is freed but still in use, allocated at %s, %d, freed at %s, %d\n",
1056 label, i, buf->buf_alloc_file, buf->buf_alloc_line,
1057 buf->buf_free_file, buf->buf_free_line);
1058 buf->buf_check_linkC= -buf->buf_check_linkC;
1059 if (buf->buf_check_linkC == buf->buf_linkC)
1060 return 1;
1061 }
1062 printf(
1063 "# of tracked links (%d) for %s[%d] don't match with stored link count %d\n",
1064 buf->buf_check_linkC, label, i, buf->buf_linkC);
1065 printf("%s[%d] was allocated at %s, %d\n",
1066 label, i, buf->buf_alloc_file, buf->buf_alloc_line);
1067 return 1;
1068 }
1069
1070 PUBLIC void bf_check_acc(acc)
1071 acc_t *acc;
1072 {
1073 buf_t *buf;
1074
1075 while(acc != NULL)
1076 {
1077 if (acc->acc_generation == buf_generation)
1078 {
1079 assert(acc->acc_check_linkC > 0);
1080 acc->acc_check_linkC++;
1081 return;
1082 }
1083 assert(acc->acc_generation == buf_generation-1);
1084 acc->acc_generation= buf_generation;
1085 acc->acc_check_linkC= 1;
1086
1087 buf= acc->acc_buffer;
1088 if (buf->buf_generation == buf_generation)
1089 {
1090 assert(buf->buf_check_linkC > 0);
1091 buf->buf_check_linkC++;
1092 }
1093 else
1094 {
1095 assert(buf->buf_generation == buf_generation-1);
1096 buf->buf_generation= buf_generation;
1097 buf->buf_check_linkC= 1;
1098 }
1099
1100 acc= acc->acc_next;
1101 }
1102 }
1103
1104 PUBLIC void _bf_mark_acc(clnt_file, clnt_line, acc)
1105 char *clnt_file;
1106 int clnt_line;
1107 acc_t *acc;
1108 {
1109 buf_t *buf;
1110
1111 for (; acc; acc= acc->acc_next)
1112 {
1113 acc->acc_alloc_file= clnt_file;
1114 acc->acc_alloc_line= clnt_line;
1115 buf= acc->acc_buffer;
1116 buf->buf_alloc_file= clnt_file;
1117 buf->buf_alloc_line= clnt_line;
1118 }
1119 }
1120 #endif
1121
free_accs() is called to free accessors when more accessors are needed to store data.
free_accs() calls the functions freereq.
The freereq array functions are initialized in bf_logon.
1122 PRIVATE void free_accs()
1123 {
1124 int i, j;
1125
1126 DBLOCK(1, printf("free_accs\n"));
1127
1128 for (i=0; !acc_freelist && i<MAX_BUFREQ_PRI; i++)
1129 {
1130 for (j=0; j<CLIENT_NR; j++)
1131 {
1132 bf_free_bufsize= 0;
1133 if (freereq[j])
1134 {
1135 (*freereq[j])(i);
1136 }
1137 }
1138 }
1139 #if DEBUG
1140 printf("last level was level %d\n", i-1);
1141 #endif
1142 }
1143
bf_align(acc, size, alignment) tests if acc's buffer is aligned with the variable alignment.
If it is not and bufsize of acc > size, then the chunk of data pointed to by acc
is split in to 2 accessors so that the data at offset < size is pointed to by the
first accessor while the data at offset >= size is in the second accessor or beyond.
1144 #ifndef BUF_TRACK_ALLOC_FREE
1145 PUBLIC acc_t *bf_align(acc, size, alignment)
1146 #else
1147 PUBLIC acc_t *_bf_align(clnt_file, clnt_line, acc, size, alignment)
1148 char *clnt_file;
1149 int clnt_line;
1150 #endif
1151 acc_t *acc;
1152 size_t size;
1153 size_t alignment;
1154 {
1155 char *ptr;
1156 size_t buf_size;
1157 acc_t *head, *tail;
1158
1159 /* Fast check if the buffer is aligned already. */
1160 if (acc->acc_length >= size)
1161 {
1162 ptr= ptr2acc_data(acc);
1163 if (((unsigned)ptr & (alignment-1)) == 0)
1164 return acc;
1165 }
1166 buf_size= bf_bufsize(acc);
1167 #ifdef bf_align
1168 assert(size != 0 && buf_size != 0 ||
1169 (printf("bf_align(..., %d, %d) from %s, %d\n",
1170 size, alignment, clnt_file, clnt_line),0));
1171 #else
1172 assert(size != 0 && buf_size != 0);
1173 #endif
1174 if (buf_size <= size)
1175 {
1176 acc= bf_pack(acc);
1177 return acc;
1178 }
1179 head= bf_cut(acc, 0, size);
1180 tail= bf_cut(acc, size, buf_size-size);
1181 bf_afree(acc);
1182 head= bf_pack(head);
1183 assert(head->acc_next == NULL);
1184 head->acc_next= tail;
1185 return head;
1186 }
1187
1188 #if 0
1189 int chk_acc(acc)
1190 acc_t *acc;
1191 {
1192 int acc_nr;
1193
1194 if (!acc)
1195 return 1;
1196 if (acc < accessors || acc >= &accessors[ACC_NR])
1197 return 0;
1198 acc_nr= acc-accessors;
1199 return acc == &accessors[acc_nr];
1200 }
1201 #endif
1202
1203 /*
1204 * $PchId: buf.c,v 1.10 1995/11/23 11:25:25 philip Exp $
1205 */
We shall now discuss how inet allocates memory to store the data which is sent and received.
This is handled in buf.c.