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