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