]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_cbuff.h
Simplify CBUFF tail/consumer attachment.
[ulut.git] / ulut / ul_cbuff.h
1 /*******************************************************************
2   uLan Utilities Library - C library of basic reusable constructions
3
4   ul_cbuff.h    - circular buffer
5
6   (C) Copyright 2006 by Pavel Pisa - Originator
7
8   The uLan utilities library can be used, copied and modified under
9   next licenses
10     - GPL - GNU General Public License
11     - LGPL - GNU Lesser General Public License
12     - MPL - Mozilla Public License
13     - and other licenses added by project originators
14   Code can be modified and re-distributed under any combination
15   of the above listed licenses. If contributor does not agree with
16   some of the licenses, he/she can delete appropriate line.
17   Warning, if you delete all lines, you are not allowed to
18   distribute source code and/or binaries utilizing code.
19
20   See files COPYING and README for details.
21
22  *******************************************************************/
23
24 #ifndef _UL_CBUFF_H
25 #define _UL_CBUFF_H
26
27 #include "ul_utdefs.h"
28
29 #include <string.h>
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #define UL_CBUFF_NO_INLINE
36
37 #ifndef UL_CBUFF_NO_INLINE
38 #define UL_CBUFF_INLINE
39 #endif
40
41 #ifndef ul_cbuff_inline
42 #ifdef UL_CBUFF_INLINE
43 #define ul_cbuff_inline static inline
44 #else
45 #define ul_cbuff_inline
46 #endif
47 #endif
48
49 #define ul_cbuff_align(x) (((x)+3)&~3)
50
51 typedef unsigned int ul_cbuff_loc_t;
52
53 typedef struct ul_cbuff_msg_head_t {
54   unsigned short flags;
55   unsigned short length;
56 } ul_cbuff_msg_head_t;
57
58 #define UL_CBUFF_MSG_READY    0x8000
59 #define UL_CBUFF_MSG_OVERFLOW 0x4000
60 #define UL_CBUFF_MSG_READERS  0x3fff
61
62 #define ul_cbuff_msg_head_size (ul_cbuff_align(sizeof(ul_cbuff_msg_head_t)))
63
64 typedef struct ul_cbuff_state_t {
65   ul_cbuff_loc_t buff_size;
66   ul_cbuff_loc_t head;
67   ul_cbuff_loc_t lasttail;
68   ul_cbuff_loc_t firsttail;
69   unsigned int   cycles;
70   unsigned int   readers;
71   ul_cbuff_loc_t rear_size;
72 } ul_cbuff_state_t;
73
74 typedef struct ul_cbuff_t {
75   unsigned char    *buff_start;
76   ul_cbuff_state_t *state;
77 } ul_cbuff_t;
78
79 typedef struct ul_cbuff_data_info_t {
80   unsigned char *ptr;
81   unsigned char *wrap_ptr;
82   unsigned int  cont_len;
83   unsigned int  wrap_len;
84 } ul_cbuff_data_info_t;
85
86 typedef struct ul_cbuff_put_info_t {
87   ul_cbuff_data_info_t data;
88   ul_cbuff_msg_head_t *msg_head;
89 } ul_cbuff_put_info_t;
90
91 typedef struct ul_cbuff_tail_info_t {
92   ul_cbuff_data_info_t data;
93   ul_cbuff_msg_head_t *msg_head;
94 } ul_cbuff_tail_info_t;
95
96 #if !defined(UL_CBUFF_INLINE)
97
98 void ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg);
99 int ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg);
100 int ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags);
101 int ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info);
102 ul_cbuff_loc_t ul_cbuff_head_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head);
103 ul_cbuff_loc_t ul_cbuff_next_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head);
104 int ul_cbuff_msg_head2data(const ul_cbuff_t *buff, ul_cbuff_data_info_t *data, const ul_cbuff_msg_head_t *msg_head);
105 int ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode);
106 int ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
107 int ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
108 int ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
109 int ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
110 int ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next);
111 void ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info);
112 int ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size);
113 int ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size);
114 int ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size);
115 void *ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
116 void *ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc);
117
118 #endif /* UL_CBUFF_INLINE */
119
120 #if defined(UL_CBUFF_INLINE) || defined(UL_CBUFF_INCLUDE_INTERNAL)
121
122 ul_cbuff_inline void
123 ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg)
124 {
125   msg->flags|=UL_CBUFF_MSG_READY;
126 }
127
128 ul_cbuff_inline int
129 ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg)
130 {
131   return msg->flags&UL_CBUFF_MSG_READY;
132 }
133
134 ul_cbuff_inline int
135 ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags)
136 {
137   ul_cbuff_state_t *state=buff->state;
138   unsigned int length=size;
139
140   size=ul_cbuff_align(size+state->rear_size)+ul_cbuff_msg_head_size;
141
142   if((state->lasttail > state->head) &&
143      (state->lasttail-state->head <= size))
144       return -1;
145
146   if((state->lasttail > state->head) ||
147      (state->buff_size-state->head > size)){
148     put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
149
150     put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
151     put_info->data.cont_len=length;
152     put_info->data.wrap_ptr=NULL;
153     put_info->data.wrap_len=0;
154
155     state->head+=size;
156   }else{
157     ul_cbuff_loc_t res_size=state->buff_size-state->head;
158     if(size-res_size >= state->lasttail)
159       return -1;
160
161     put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
162
163     if(res_size != ul_cbuff_msg_head_size){
164       put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
165       put_info->data.cont_len=res_size-ul_cbuff_msg_head_size;
166       if(put_info->data.cont_len<length){
167         put_info->data.wrap_ptr=buff->buff_start;
168         put_info->data.wrap_len=length-put_info->data.cont_len;
169       }else{
170         put_info->data.wrap_ptr=NULL;
171         put_info->data.wrap_len=0;
172       }
173     }else{
174       put_info->data.ptr=buff->buff_start;
175       put_info->data.cont_len=length;
176       put_info->data.wrap_ptr=NULL;
177       put_info->data.wrap_len=0;
178     }
179
180     state->cycles++;
181     state->head=size-res_size;
182   }
183
184   ((ul_cbuff_msg_head_t *)(buff->buff_start+state->head))->flags=0;
185
186   flags&=~(UL_CBUFF_MSG_READY|UL_CBUFF_MSG_READERS);
187
188   put_info->msg_head->flags|=flags;
189   if(buff->state->readers>0)
190     put_info->msg_head->flags+=buff->state->readers;
191
192   put_info->msg_head->length=length;
193
194   return 0;
195 }
196
197 ul_cbuff_inline int
198 ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info)
199 {
200   ul_cbuff_mark_ready(put_info->msg_head);
201   put_info->msg_head=NULL;
202   return 0;
203 }
204
205 ul_cbuff_inline ul_cbuff_loc_t
206 ul_cbuff_head_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
207 {
208   return (unsigned char*)msg_head-buff->buff_start;
209 }
210
211 ul_cbuff_inline ul_cbuff_loc_t
212 ul_cbuff_next_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
213 {
214   ul_cbuff_loc_t loc;
215   unsigned int size;
216
217   size=ul_cbuff_align(msg_head->length+buff->state->rear_size)+ul_cbuff_msg_head_size;
218
219   loc=(unsigned char*)msg_head-buff->buff_start;
220   if(buff->state->buff_size-loc > size)
221     loc+=size;
222   else
223     loc=size-(buff->state->buff_size-loc);
224
225   return loc;
226 }
227
228 ul_cbuff_inline int
229 ul_cbuff_msg_head2data(const ul_cbuff_t *buff, ul_cbuff_data_info_t *data, const ul_cbuff_msg_head_t *msg_head)
230 {
231   ul_cbuff_loc_t res_size;
232   unsigned int length;
233   ul_cbuff_loc_t msg_loc=(unsigned char *)msg_head-buff->buff_start;
234
235   res_size=buff->state->buff_size-msg_loc;
236   length=msg_head->length;
237
238   if(res_size > ul_cbuff_msg_head_size){
239     data->ptr=(unsigned char*)msg_head+ul_cbuff_msg_head_size;
240     if(res_size-ul_cbuff_msg_head_size >= length){
241       data->cont_len=length;
242       data->wrap_ptr=NULL;
243       data->wrap_len=0;
244     }else{
245       data->cont_len=res_size-ul_cbuff_msg_head_size;
246       data->wrap_ptr=buff->buff_start;
247       data->wrap_len=length-(res_size-ul_cbuff_msg_head_size);
248     }
249   } else {
250     data->ptr=buff->buff_start;
251     data->cont_len=length;
252     data->wrap_ptr=NULL;
253     data->wrap_len=0;
254   }
255   return msg_head->flags;
256 }
257
258 ul_cbuff_inline int
259 ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode)
260 {
261   ul_cbuff_state_t *state=buff->state;
262   ul_cbuff_msg_head_t *msg_head;
263
264   msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
265   if(state->readers>=0)
266     state->readers++;
267   tail_info->msg_head=msg_head;
268   tail_info->data.ptr=NULL;
269   return 0;
270 }
271
272 ul_cbuff_inline int
273 ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
274 {
275   if(tail_info->msg_head==NULL){
276     return 0;
277   }
278   return 1;
279 }
280
281 ul_cbuff_inline int
282 ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
283 {
284   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
285
286   if(!msg_head)
287     return -1;
288
289   if(!ul_cbuff_is_ready(msg_head))
290     return 0;
291
292   return ul_cbuff_msg_head2data(buff, &tail_info->data, msg_head);
293 }
294
295 ul_cbuff_inline int
296 ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
297 {
298   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
299   unsigned msg_readers;
300
301   if(!ul_cbuff_is_ready(msg_head))
302     return -1;
303
304   if(buff->state->readers<=0)
305     return 1;
306
307   msg_readers=msg_head->flags&UL_CBUFF_MSG_READERS;
308   if(msg_readers)
309     msg_head->flags--;
310
311   return msg_readers<=1?1:0;
312 }
313
314 ul_cbuff_inline int
315 ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
316 {
317   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
318
319   if(!ul_cbuff_is_ready(msg_head))
320     return -1;
321
322   tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+
323                         ul_cbuff_next_loc(buff, msg_head));
324   return 0;
325 }
326
327 ul_cbuff_inline int
328 ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next)
329 {
330   if(loc==buff->state->firsttail)
331     buff->state->firsttail=loc_next;
332
333   if(release_result<=0)
334     return 0;
335
336   if(loc==buff->state->lasttail){
337     buff->state->lasttail=loc_next;
338     return 1;
339   }else{
340     return -1;
341   }
342 }
343
344 ul_cbuff_inline void
345 ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info)
346 {
347   data_info->ptr=data_info->wrap_ptr;
348   data_info->cont_len=data_info->wrap_len;
349   data_info->wrap_ptr=NULL;
350   data_info->wrap_len=0;
351 }
352
353 ul_cbuff_inline int
354 ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size)
355 {
356   int cont_len;
357
358   *pptr=data_info->ptr;
359   if(!data_info->ptr)
360     return 0;
361   cont_len=data_info->cont_len;
362   if(cont_len>size){
363     cont_len=size;
364     data_info->ptr+=size;
365     data_info->cont_len-=cont_len;
366   }else{
367     ul_cbuff_data_do_wrap(data_info);
368   }
369   return cont_len;
370 }
371
372 ul_cbuff_inline int
373 ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size)
374 {
375   void *ptr;
376   int count;
377   int cont_len;
378
379   ptr=data_info->ptr;
380   if(!ptr)
381     return 0;
382   cont_len=data_info->cont_len;
383   if(cont_len>size){
384     cont_len=size;
385     data_info->ptr+=size;
386     data_info->cont_len-=cont_len;
387   }else{
388     ul_cbuff_data_do_wrap(data_info);
389   }
390   if(cont_len<=0)
391     return 0;
392   memcpy(ptr,data,cont_len);
393   count=cont_len;
394   cont_len=size-cont_len;
395   if(!cont_len)
396     return count;
397
398   ptr=data_info->ptr;
399   if(!ptr)
400     return count;
401   data=(char*)data+count;
402   if(cont_len>data_info->cont_len)
403     cont_len=data_info->cont_len;
404   data_info->ptr+=cont_len;
405   data_info->cont_len-=cont_len;
406   memcpy(ptr,data,cont_len);
407
408   return cont_len+count;
409 }
410
411 ul_cbuff_inline int
412 ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size)
413 {
414   void *ptr;
415   int count;
416   int cont_len;
417
418   ptr=data_info->ptr;
419   if(!ptr)
420     return 0;
421   cont_len=data_info->cont_len;
422   if(cont_len>size){
423     cont_len=size;
424     data_info->ptr+=size;
425     data_info->cont_len-=cont_len;
426   }else{
427     ul_cbuff_data_do_wrap(data_info);
428   }
429   if(cont_len<=0)
430     return 0;
431   memcpy(data,ptr,cont_len);
432   count=cont_len;
433   cont_len=size-cont_len;
434   if(!cont_len)
435     return count;
436
437   ptr=data_info->ptr;
438   if(!ptr)
439     return count;
440   data=(char*)data+count;
441   if(cont_len>data_info->cont_len)
442     cont_len=data_info->cont_len;
443   data_info->ptr+=cont_len;
444   data_info->cont_len-=cont_len;
445   memcpy(data,ptr,cont_len);
446
447   return cont_len+count;
448 }
449
450
451 ul_cbuff_inline void *
452 ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
453 {
454   ul_cbuff_loc_t loc;
455   unsigned int size;
456   ul_cbuff_state_t *state=buff->state;
457
458   size=ul_cbuff_align(msg_head->length+state->rear_size)+ul_cbuff_msg_head_size;
459   size-=state->rear_size;
460
461   loc=(unsigned char*)msg_head-buff->buff_start;
462   if(state->buff_size-loc > size)
463     loc+=size;
464   else
465     loc=size-(state->buff_size-loc);
466
467   return buff->buff_start+loc;
468 }
469
470 ul_cbuff_inline void *
471 ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc)
472 {
473   ul_cbuff_state_t *state=buff->state;
474
475   if(loc>state->rear_size)
476     return buff->buff_start+loc-state->rear_size;
477   else
478     return buff->buff_start+loc+state->buff_size-state->rear_size;
479 }
480
481 #endif /*UL_CBUFF_INLINE*/
482
483 int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
484                   void *buff_start, ul_cbuff_loc_t size);
485
486
487 #ifdef __cplusplus
488 } /* extern "C"*/
489 #endif
490
491 #endif /* _UL_CBUFF_H */