1 /*******************************************************************
2 uLan Utilities Library - C library of basic reusable constructions
4 ul_cbuff.h - circular buffer
6 (C) Copyright 2006 by Pavel Pisa - Originator
8 The uLan utilities library can be used, copied and modified under
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.
20 See files COPYING and README for details.
22 *******************************************************************/
27 #include "ul_utdefs.h"
35 #define UL_CBUFF_NO_INLINE
37 #ifndef UL_CBUFF_NO_INLINE
38 #define UL_CBUFF_INLINE
41 #ifndef ul_cbuff_inline
42 #ifdef UL_CBUFF_INLINE
43 #define ul_cbuff_inline static inline
45 #define ul_cbuff_inline
49 #define ul_cbuff_align(x) (((x)+3)&~3)
51 typedef unsigned int ul_cbuff_loc_t;
53 typedef struct ul_cbuff_msg_head_t {
55 unsigned short length;
56 } ul_cbuff_msg_head_t;
58 #define UL_CBUFF_MSG_READY 0x8000
59 #define UL_CBUFF_MSG_OVERFLOW 0x4000
60 #define UL_CBUFF_MSG_READERS 0x3fff
62 #define ul_cbuff_msg_head_size (ul_cbuff_align(sizeof(ul_cbuff_msg_head_t)))
64 typedef struct ul_cbuff_state_t {
65 ul_cbuff_loc_t buff_size;
67 ul_cbuff_loc_t lasttail;
68 ul_cbuff_loc_t firsttail;
71 ul_cbuff_loc_t rear_size;
74 typedef struct ul_cbuff_t {
75 unsigned char *buff_start;
76 ul_cbuff_state_t *state;
79 typedef struct ul_cbuff_data_info_t {
81 unsigned char *wrap_ptr;
82 unsigned int cont_len;
83 unsigned int wrap_len;
84 } ul_cbuff_data_info_t;
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;
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;
96 #if !defined(UL_CBUFF_INLINE)
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);
119 #endif /* UL_CBUFF_INLINE */
121 #if defined(UL_CBUFF_INLINE) || defined(UL_CBUFF_INCLUDE_INTERNAL)
124 ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg)
126 msg->flags|=UL_CBUFF_MSG_READY;
130 ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg)
132 return msg->flags&UL_CBUFF_MSG_READY;
136 ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags)
138 ul_cbuff_state_t *state=buff->state;
139 unsigned int length=size;
141 size=ul_cbuff_align(size+state->rear_size)+ul_cbuff_msg_head_size;
143 if((state->lasttail > state->head) &&
144 (state->lasttail-state->head <= size))
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);
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;
158 ul_cbuff_loc_t res_size=state->buff_size-state->head;
159 if(size-res_size >= state->lasttail)
162 put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
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;
171 put_info->data.wrap_ptr=NULL;
172 put_info->data.wrap_len=0;
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;
182 state->head=size-res_size;
185 ((ul_cbuff_msg_head_t *)(buff->buff_start+state->head))->flags=0;
187 flags&=~(UL_CBUFF_MSG_READY|UL_CBUFF_MSG_READERS);
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;
195 put_info->msg_head->length=length;
201 ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info)
203 ul_cbuff_mark_ready(put_info->msg_head);
204 put_info->msg_head=NULL;
208 ul_cbuff_inline ul_cbuff_loc_t
209 ul_cbuff_head_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
211 return (unsigned char*)msg_head-buff->buff_start;
214 ul_cbuff_inline ul_cbuff_loc_t
215 ul_cbuff_next_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
220 size=ul_cbuff_align(msg_head->length+buff->state->rear_size)+ul_cbuff_msg_head_size;
222 loc=(unsigned char*)msg_head-buff->buff_start;
223 if(buff->state->buff_size-loc > size)
226 loc=size-(buff->state->buff_size-loc);
232 ul_cbuff_msg_head2data(const ul_cbuff_t *buff, ul_cbuff_data_info_t *data, const ul_cbuff_msg_head_t *msg_head)
234 ul_cbuff_loc_t res_size;
236 ul_cbuff_loc_t msg_loc=(unsigned char *)msg_head-buff->buff_start;
238 res_size=buff->state->buff_size-msg_loc;
239 length=msg_head->length;
241 if(res_size > ul_cbuff_msg_head_size){
242 data->ptr=(unsigned char*)msg_head+ul_cbuff_msg_head_size;
243 if(res_size-ul_cbuff_msg_head_size >= length){
244 data->cont_len=length;
248 data->cont_len=res_size-ul_cbuff_msg_head_size;
249 data->wrap_ptr=buff->buff_start;
250 data->wrap_len=length-(res_size-ul_cbuff_msg_head_size);
253 data->ptr=buff->buff_start;
254 data->cont_len=length;
258 return msg_head->flags;
262 ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode)
264 ul_cbuff_state_t *state=buff->state;
265 ul_cbuff_msg_head_t *msg_head;
268 msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
269 else if(state->readers==0)
270 msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->lasttail);
271 if(state->readers>=0)
273 tail_info->msg_head=msg_head;
274 tail_info->data.ptr=NULL;
279 ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
281 if(tail_info->msg_head==NULL){
288 ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
290 ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
295 if(!ul_cbuff_is_ready(msg_head))
298 return ul_cbuff_msg_head2data(buff, &tail_info->data, msg_head);
302 ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
304 ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
305 unsigned msg_readers;
307 if(!ul_cbuff_is_ready(msg_head))
310 if(buff->state->readers<=0)
313 msg_readers=msg_head->flags&UL_CBUFF_MSG_READERS;
317 return msg_readers<=1?1:0;
321 ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
323 ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
325 if(!ul_cbuff_is_ready(msg_head))
328 tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+
329 ul_cbuff_next_loc(buff, msg_head));
334 ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next)
336 if(loc==buff->state->firsttail)
337 buff->state->firsttail=loc_next;
339 if(release_result<=0)
342 if(loc==buff->state->lasttail){
343 buff->state->lasttail=loc_next;
351 ul_cbuff_tail_detach_onestep(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
353 ul_cbuff_state_t *state=buff->state;
355 ul_cbuff_loc_t loc_next;
356 unsigned msg_readers;
358 if(tail_info->msg_head==NULL)
361 loc = ul_cbuff_head_loc(buff, tail_info->msg_head);
363 if(loc!=state->head) {
364 if(!ul_cbuff_is_ready(tail_info->msg_head))
366 msg_readers=tail_info->msg_head->flags&UL_CBUFF_MSG_READERS;
367 loc_next=ul_cbuff_next_loc(buff, tail_info->msg_head);
369 tail_info->msg_head->flags--;
370 tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+loc_next);
371 ul_cbuff_tail_state_update(buff, msg_readers<=1? 1: 0, loc, loc_next);
377 tail_info->msg_head=NULL;
378 tail_info->data.ptr=NULL;
384 ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info)
386 data_info->ptr=data_info->wrap_ptr;
387 data_info->cont_len=data_info->wrap_len;
388 data_info->wrap_ptr=NULL;
389 data_info->wrap_len=0;
393 ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size)
397 *pptr=data_info->ptr;
400 cont_len=data_info->cont_len;
403 data_info->ptr+=size;
404 data_info->cont_len-=cont_len;
406 ul_cbuff_data_do_wrap(data_info);
412 ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size)
421 cont_len=data_info->cont_len;
424 data_info->ptr+=size;
425 data_info->cont_len-=cont_len;
427 ul_cbuff_data_do_wrap(data_info);
431 memcpy(ptr,data,cont_len);
433 cont_len=size-cont_len;
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(ptr,data,cont_len);
447 return cont_len+count;
451 ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size)
460 cont_len=data_info->cont_len;
463 data_info->ptr+=size;
464 data_info->cont_len-=cont_len;
466 ul_cbuff_data_do_wrap(data_info);
470 memcpy(data,ptr,cont_len);
472 cont_len=size-cont_len;
479 data=(char*)data+count;
480 if(cont_len>data_info->cont_len)
481 cont_len=data_info->cont_len;
482 data_info->ptr+=cont_len;
483 data_info->cont_len-=cont_len;
484 memcpy(data,ptr,cont_len);
486 return cont_len+count;
490 ul_cbuff_inline void *
491 ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
495 ul_cbuff_state_t *state=buff->state;
497 size=ul_cbuff_align(msg_head->length+state->rear_size)+ul_cbuff_msg_head_size;
498 size-=state->rear_size;
500 loc=(unsigned char*)msg_head-buff->buff_start;
501 if(state->buff_size-loc > size)
504 loc=size-(state->buff_size-loc);
506 return buff->buff_start+loc;
509 ul_cbuff_inline void *
510 ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc)
512 ul_cbuff_state_t *state=buff->state;
514 if(loc>state->rear_size)
515 return buff->buff_start+loc-state->rear_size;
517 return buff->buff_start+loc+state->buff_size-state->rear_size;
520 #endif /*UL_CBUFF_INLINE*/
522 int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
523 void *buff_start, ul_cbuff_loc_t size);
530 #endif /* _UL_CBUFF_H */