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