]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_cbuff.h
Updated cyclic buffer code.
[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   put_info->msg_head->flags|=flags;
187   put_info->msg_head->length=length;
188
189   return 0;
190 }
191
192 ul_cbuff_inline int
193 ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info)
194 {
195   if(buff->state->readers>0)
196     put_info->msg_head->flags+=buff->state->readers;
197   ul_cbuff_mark_ready(put_info->msg_head);
198   put_info->msg_head=NULL;
199   return 0;
200 }
201
202 ul_cbuff_inline ul_cbuff_loc_t
203 ul_cbuff_head_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
204 {
205   return (unsigned char*)msg_head-buff->buff_start;
206 }
207
208 ul_cbuff_inline ul_cbuff_loc_t
209 ul_cbuff_next_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
210 {
211   ul_cbuff_loc_t loc;
212   unsigned int size;
213
214   size=ul_cbuff_align(msg_head->length+buff->state->rear_size)+ul_cbuff_msg_head_size;
215
216   loc=(unsigned char*)msg_head-buff->buff_start;
217   if(buff->state->buff_size-loc > size)
218     loc+=size;
219   else
220     loc=size-(buff->state->buff_size-loc);
221
222   return loc;
223 }
224
225 ul_cbuff_inline int
226 ul_cbuff_msg_head2data(const ul_cbuff_t *buff, ul_cbuff_data_info_t *data, const ul_cbuff_msg_head_t *msg_head)
227 {
228   ul_cbuff_loc_t res_size;
229   unsigned int length;
230   ul_cbuff_loc_t msg_loc=(unsigned char *)msg_head-buff->buff_start;
231
232   res_size=buff->state->buff_size-msg_loc;
233   length=msg_head->length;
234
235   if(res_size > ul_cbuff_msg_head_size){
236     data->ptr=(unsigned char*)msg_head+ul_cbuff_msg_head_size;
237     if(res_size-ul_cbuff_msg_head_size >= length){
238       data->cont_len=length;
239       data->wrap_ptr=NULL;
240       data->wrap_len=0;
241     }else{
242       data->cont_len=res_size-ul_cbuff_msg_head_size;
243       data->wrap_ptr=buff->buff_start;
244       data->wrap_len=length-(res_size-ul_cbuff_msg_head_size);
245     }
246   } else {
247     data->ptr=buff->buff_start;
248     data->cont_len=length;
249     data->wrap_ptr=NULL;
250     data->wrap_len=0;
251   }
252   return msg_head->flags;
253 }
254
255 ul_cbuff_inline int
256 ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode)
257 {
258   ul_cbuff_state_t *state=buff->state;
259   ul_cbuff_msg_head_t *msg_head;
260
261   msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
262   if(state->readers>=0)
263     state->readers++;
264   if((state->readers<0)||(state->firsttail==state->head)){
265     tail_info->msg_head=msg_head;
266     tail_info->data.ptr=NULL;
267   }else{
268     /* There is already some message(s) write in progress */
269     tail_info->msg_head=NULL;
270     tail_info->msg_head->flags++;
271     /* Some data fields are abused for ready condition checking */
272     tail_info->data.ptr=(unsigned char*)msg_head;
273     tail_info->data.wrap_ptr=buff->buff_start+state->firsttail;
274     tail_info->data.wrap_len=state->cycles;
275   }
276   return 0;
277 }
278
279 ul_cbuff_inline int
280 ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
281 {
282   if(tail_info->msg_head==NULL){
283     unsigned char *new_firsttail=buff->buff_start+buff->state->firsttail;
284     unsigned char *old_head=tail_info->data.ptr;
285     unsigned char *old_firsttail=tail_info->data.wrap_ptr;
286     unsigned int old_cycles=tail_info->data.wrap_len;
287     unsigned int new_cycles=buff->state->cycles;
288
289     if(old_firsttail<old_head){
290       if((new_firsttail<old_head)&&(new_cycles==old_cycles))
291         return 0;
292     }else{
293       if(new_cycles==old_cycles)
294         return 0;
295       if((new_firsttail<old_head)&&((new_cycles-old_cycles)==1))
296         return 0;
297     }
298     tail_info->msg_head=(ul_cbuff_msg_head_t *)old_head;
299     return 1;
300   }
301   return 1;
302 }
303
304 ul_cbuff_inline int
305 ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
306 {
307   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
308
309   if(!msg_head)
310     return -1;
311
312   if(!ul_cbuff_is_ready(msg_head))
313     return 0;
314
315   return ul_cbuff_msg_head2data(buff, &tail_info->data, msg_head);
316 }
317
318 ul_cbuff_inline int
319 ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
320 {
321   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
322   unsigned msg_readers;
323
324   if(!ul_cbuff_is_ready(msg_head))
325     return -1;
326
327   if(buff->state->readers<=0)
328     return 1;
329
330   msg_readers=msg_head->flags&UL_CBUFF_MSG_READERS;
331   if(msg_readers)
332     msg_head->flags--;
333
334   return msg_readers<=1?1:0;
335 }
336
337 ul_cbuff_inline int
338 ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
339 {
340   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
341
342   if(!ul_cbuff_is_ready(msg_head))
343     return -1;
344
345   tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+
346                         ul_cbuff_next_loc(buff, msg_head));
347   return 0;
348 }
349
350 ul_cbuff_inline int
351 ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next)
352 {
353   if(loc==buff->state->firsttail)
354     buff->state->firsttail=loc_next;
355
356   if(release_result<=0)
357     return 0;
358
359   if(loc==buff->state->lasttail){
360     buff->state->lasttail=loc_next;
361     return 1;
362   }else{
363     return -1;
364   }
365 }
366
367 ul_cbuff_inline void
368 ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info)
369 {
370   data_info->ptr=data_info->wrap_ptr;
371   data_info->cont_len=data_info->wrap_len;
372   data_info->wrap_ptr=NULL;
373   data_info->wrap_len=0;
374 }
375
376 ul_cbuff_inline int
377 ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size)
378 {
379   int cont_len;
380
381   *pptr=data_info->ptr;
382   if(!data_info->ptr)
383     return 0;
384   cont_len=data_info->cont_len;
385   if(cont_len>size){
386     cont_len=size;
387     data_info->ptr+=size;
388     data_info->cont_len-=cont_len;
389   }else{
390     ul_cbuff_data_do_wrap(data_info);
391   }
392   return cont_len;
393 }
394
395 ul_cbuff_inline int
396 ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size)
397 {
398   void *ptr;
399   int count;
400   int cont_len;
401
402   ptr=data_info->ptr;
403   if(!ptr)
404     return 0;
405   cont_len=data_info->cont_len;
406   if(cont_len>size){
407     cont_len=size;
408     data_info->ptr+=size;
409     data_info->cont_len-=cont_len;
410   }else{
411     ul_cbuff_data_do_wrap(data_info);
412   }
413   if(cont_len<=0)
414     return 0;
415   memcpy(ptr,data,cont_len);
416   count=cont_len;
417   cont_len=size-cont_len;
418   if(!cont_len)
419     return count;
420
421   ptr=data_info->ptr;
422   if(!ptr)
423     return count;
424   data=(char*)data+count;
425   if(cont_len>data_info->cont_len)
426     cont_len=data_info->cont_len;
427   data_info->ptr+=cont_len;
428   data_info->cont_len-=cont_len;
429   memcpy(ptr,data,cont_len);
430
431   return cont_len+count;
432 }
433
434 ul_cbuff_inline int
435 ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size)
436 {
437   void *ptr;
438   int count;
439   int cont_len;
440
441   ptr=data_info->ptr;
442   if(!ptr)
443     return 0;
444   cont_len=data_info->cont_len;
445   if(cont_len>size){
446     cont_len=size;
447     data_info->ptr+=size;
448     data_info->cont_len-=cont_len;
449   }else{
450     ul_cbuff_data_do_wrap(data_info);
451   }
452   if(cont_len<=0)
453     return 0;
454   memcpy(data,ptr,cont_len);
455   count=cont_len;
456   cont_len=size-cont_len;
457   if(!cont_len)
458     return count;
459
460   ptr=data_info->ptr;
461   if(!ptr)
462     return count;
463   data=(char*)data+count;
464   if(cont_len>data_info->cont_len)
465     cont_len=data_info->cont_len;
466   data_info->ptr+=cont_len;
467   data_info->cont_len-=cont_len;
468   memcpy(data,ptr,cont_len);
469
470   return cont_len+count;
471 }
472
473
474 ul_cbuff_inline void *
475 ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
476 {
477   ul_cbuff_loc_t loc;
478   unsigned int size;
479   ul_cbuff_state_t *state=buff->state;
480
481   size=ul_cbuff_align(msg_head->length+state->rear_size)+ul_cbuff_msg_head_size;
482   size-=state->rear_size;
483
484   loc=(unsigned char*)msg_head-buff->buff_start;
485   if(state->buff_size-loc > size)
486     loc+=size;
487   else
488     loc=size-(state->buff_size-loc);
489
490   return buff->buff_start+loc;
491 }
492
493 ul_cbuff_inline void *
494 ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc)
495 {
496   ul_cbuff_state_t *state=buff->state;
497
498   if(loc>state->rear_size)
499     return buff->buff_start+loc-state->rear_size;
500   else
501     return buff->buff_start+loc+state->buff_size-state->rear_size;
502 }
503
504 #endif /*UL_CBUFF_INLINE*/
505
506 int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
507                   void *buff_start, ul_cbuff_loc_t size);
508
509
510 #ifdef __cplusplus
511 } /* extern "C"*/
512 #endif
513
514 #endif /* _UL_CBUFF_H */