]> rtime.felk.cvut.cz Git - ulut.git/commitdiff
Added implementation of multi-tail circular buffer with O1 head space
authorppisa <ppisa>
Sat, 29 Apr 2006 09:37:38 +0000 (09:37 +0000)
committerppisa <ppisa>
Sat, 29 Apr 2006 09:37:38 +0000 (09:37 +0000)
allocation.
This intended for situation, where more asynchronous sources
need to write data into queue. Because of uLUt is intended
to not enforce any policy to its users, the locking is not
part of the code and operations are divided to the shorter sequences.
Some of these has to be called with lock, spinlock or even IRQ
protection. Synchronization selection is fully in client hands.

ulut/ul_cbuff.c [new file with mode: 0644]
ulut/ul_cbuff.h [new file with mode: 0644]
ulut/ul_dbufflog.h

diff --git a/ulut/ul_cbuff.c b/ulut/ul_cbuff.c
new file mode 100644 (file)
index 0000000..0c00f39
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************
+  uLan Utilities Library - C library of basic reusable constructions
+
+  ul_cbuff.c   - circular buffer
+
+  (C) Copyright 2005-2006 by Pavel Pisa - Originator
+
+  The uLan utilities library can be used, copied and modified under
+  next licenses
+    - GPL - GNU General Public License
+    - LGPL - GNU Lesser General Public License
+    - MPL - Mozilla Public License
+    - and other licenses added by project originators
+  Code can be modified and re-distributed under any combination
+  of the above listed licenses. If contributor does not agree with
+  some of the licenses, he/she can delete appropriate line.
+  Warning, if you delete all lines, you are not allowed to
+  distribute source code and/or binaries utilizing code.
+
+  See files COPYING and README for details.
+
+ *******************************************************************/
+
+#include <string.h>
+#include "ul_utmalloc.h"
+
+#define UL_CBUFF_INCLUDE_INTERNAL
+
+#include "ul_cbuff.h"
+
+int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
+                 void *buff_start, ul_cbuff_loc_t size)
+{
+  ul_cbuff_msg_head_t *msg_head;
+  int state_alloc=(state==NULL);
+
+  if(state_alloc){
+    state=(ul_cbuff_state_t *)malloc(sizeof(ul_cbuff_state_t));
+    if(state==NULL)
+      return -1;
+  }
+
+  if(buff_start!=NULL){
+    size=ul_cbuff_align(size+1)-ul_cbuff_align(1);
+  }else{
+    size=ul_cbuff_align(size);
+    buff_start=malloc(size);
+    if(buff_start==NULL){
+      if(state_alloc)
+        free(state);
+      return -1;
+    }
+  }
+
+  state->buff_size=size;
+  state->head=0;
+  state->lasttail=0;
+  state->cycles=0;
+  state->readers=0;
+  state->rear_size=0;
+
+  buff->state=state;
+  buff->buff_start=(unsigned char *)buff_start;
+
+  msg_head=(ul_cbuff_msg_head_t *)buff_start;
+  msg_head->flags=0;
+
+  return 0;
+}
diff --git a/ulut/ul_cbuff.h b/ulut/ul_cbuff.h
new file mode 100644 (file)
index 0000000..d846a25
--- /dev/null
@@ -0,0 +1,505 @@
+/*******************************************************************
+  uLan Utilities Library - C library of basic reusable constructions
+
+  ul_cbuff.h   - circular buffer
+
+  (C) Copyright 2006 by Pavel Pisa - Originator
+
+  The uLan utilities library can be used, copied and modified under
+  next licenses
+    - GPL - GNU General Public License
+    - LGPL - GNU Lesser General Public License
+    - MPL - Mozilla Public License
+    - and other licenses added by project originators
+  Code can be modified and re-distributed under any combination
+  of the above listed licenses. If contributor does not agree with
+  some of the licenses, he/she can delete appropriate line.
+  Warning, if you delete all lines, you are not allowed to
+  distribute source code and/or binaries utilizing code.
+
+  See files COPYING and README for details.
+
+ *******************************************************************/
+
+#ifndef _UL_CBUFF_H
+#define _UL_CBUFF_H
+
+#include "ul_utdefs.h"
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UL_CBUFF_NO_INLINE
+
+#ifndef UL_CBUFF_NO_INLINE
+#define UL_CBUFF_INLINE
+#endif
+
+#ifndef ul_cbuff_inline
+#ifdef UL_CBUFF_INLINE
+#define ul_cbuff_inline static inline
+#else
+#define ul_cbuff_inline
+#endif
+#endif
+
+#define ul_cbuff_align(x) (((x)+3)&~3)
+
+typedef unsigned int ul_cbuff_loc_t;
+
+typedef struct ul_cbuff_msg_head_t {
+  unsigned short flags;
+  unsigned short length;
+} ul_cbuff_msg_head_t;
+
+#define UL_CBUFF_MSG_READY    0x8000
+#define UL_CBUFF_MSG_OVERFLOW 0x4000
+#define UL_CBUFF_MSG_READERS  0x3fff
+
+#define ul_cbuff_msg_head_size (ul_cbuff_align(sizeof(ul_cbuff_msg_head_t)))
+
+typedef struct ul_cbuff_state_t {
+  ul_cbuff_loc_t buff_size;
+  ul_cbuff_loc_t head;
+  ul_cbuff_loc_t lasttail;
+  ul_cbuff_loc_t firsttail;
+  unsigned int   cycles;
+  unsigned int   readers;
+  ul_cbuff_loc_t rear_size;
+} ul_cbuff_state_t;
+
+typedef struct ul_cbuff_t {
+  unsigned char    *buff_start;
+  ul_cbuff_state_t *state;
+} ul_cbuff_t;
+
+typedef struct ul_cbuff_data_info_t {
+  unsigned char *ptr;
+  unsigned char *wrap_ptr;
+  unsigned int  cont_len;
+  unsigned int  wrap_len;
+} ul_cbuff_data_info_t;
+
+typedef struct ul_cbuff_put_info_t {
+  ul_cbuff_data_info_t data;
+  ul_cbuff_msg_head_t *msg_head;
+} ul_cbuff_put_info_t;
+
+typedef struct ul_cbuff_tail_info_t {
+  ul_cbuff_data_info_t data;
+  ul_cbuff_msg_head_t *msg_head;
+} ul_cbuff_tail_info_t;
+
+#if !defined(UL_CBUFF_INLINE)
+
+void ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg);
+int ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg);
+int ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags);
+int ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info);
+ul_cbuff_loc_t ul_cbuff_head_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
+ul_cbuff_loc_t ul_cbuff_next_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
+int ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode);
+int ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next);
+void ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info);
+int ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size);
+int ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size);
+int ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size);
+void *ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
+void *ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc);
+
+#endif /* UL_CBUFF_INLINE */
+
+#if defined(UL_CBUFF_INLINE) || defined(UL_CBUFF_INCLUDE_INTERNAL)
+
+ul_cbuff_inline void
+ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg)
+{
+  msg->flags|=UL_CBUFF_MSG_READY;
+}
+
+ul_cbuff_inline int
+ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg)
+{
+  return msg->flags&UL_CBUFF_MSG_READY;
+}
+
+ul_cbuff_inline int
+ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags)
+{
+  ul_cbuff_state_t *state=buff->state;
+  unsigned int length=size;
+
+  size=ul_cbuff_align(size+state->rear_size)+ul_cbuff_msg_head_size;
+
+  if((state->lasttail > state->head) &&
+     (state->lasttail-state->head <= size))
+      return -1;
+
+  if((state->lasttail > state->head) ||
+     (state->buff_size-state->head > size)){
+    put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
+
+    put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
+    put_info->data.cont_len=length;
+    put_info->data.wrap_ptr=NULL;
+    put_info->data.wrap_len=0;
+
+    state->head+=size;
+  }else{
+    ul_cbuff_loc_t res_size=state->buff_size-state->head;
+    if(size-res_size >= state->lasttail)
+      return -1;
+
+    put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
+
+    if(res_size != ul_cbuff_msg_head_size){
+      put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
+      put_info->data.cont_len=res_size-ul_cbuff_msg_head_size;
+      if(put_info->data.cont_len<length){
+       put_info->data.wrap_ptr=buff->buff_start;
+       put_info->data.wrap_len=length-put_info->data.cont_len;
+      }else{
+       put_info->data.wrap_ptr=NULL;
+       put_info->data.wrap_len=0;
+      }
+    }else{
+      put_info->data.ptr=buff->buff_start;
+      put_info->data.cont_len=length;
+      put_info->data.wrap_ptr=NULL;
+      put_info->data.wrap_len=0;
+    }
+
+    state->cycles++;
+    state->head=size-res_size;
+  }
+
+  ((ul_cbuff_msg_head_t *)(buff->buff_start+state->head))->flags=0;
+
+  put_info->msg_head->flags|=flags;
+  put_info->msg_head->length=length;
+
+  return 0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info)
+{
+  if(buff->state->readers>0)
+    put_info->msg_head->flags+=buff->state->readers;
+  ul_cbuff_mark_ready(put_info->msg_head);
+  put_info->msg_head=NULL;
+  return 0;
+}
+
+ul_cbuff_inline ul_cbuff_loc_t
+ul_cbuff_head_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
+{
+  return (unsigned char*)msg_head-buff->buff_start;
+}
+
+ul_cbuff_inline ul_cbuff_loc_t
+ul_cbuff_next_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
+{
+  ul_cbuff_loc_t loc;
+  unsigned int size;
+
+  size=ul_cbuff_align(msg_head->length+buff->state->rear_size)+ul_cbuff_msg_head_size;
+
+  loc=(unsigned char*)msg_head-buff->buff_start;
+  if(buff->state->buff_size-loc > size)
+    loc+=size;
+  else
+    loc=size-(buff->state->buff_size-loc);
+
+  return loc;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode)
+{
+  ul_cbuff_state_t *state=buff->state;
+  ul_cbuff_msg_head_t *msg_head;
+
+  msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
+  if(state->readers>=0)
+    state->readers++;
+  if((state->readers<0)||(state->firsttail==state->head)){
+    tail_info->msg_head=msg_head;
+    tail_info->data.ptr=NULL;
+  }else{
+    /* There is already some message(s) write in progress */
+    tail_info->msg_head=NULL;
+    tail_info->msg_head->flags++;
+    /* Some data fields are abused for ready condition checking */
+    tail_info->data.ptr=(unsigned char*)msg_head;
+    tail_info->data.wrap_ptr=buff->buff_start+state->firsttail;
+    tail_info->data.wrap_len=state->cycles;
+  }
+  return 0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+  if(tail_info->msg_head==NULL){
+    unsigned char *new_firsttail=buff->buff_start+buff->state->firsttail;
+    unsigned char *old_head=tail_info->data.ptr;
+    unsigned char *old_firsttail=tail_info->data.wrap_ptr;
+    unsigned int old_cycles=tail_info->data.wrap_len;
+    unsigned int new_cycles=buff->state->cycles;
+
+    if(old_firsttail<old_head){
+      if((new_firsttail<old_head)&&(new_cycles==old_cycles))
+        return 0;
+    }else{
+      if(new_cycles==old_cycles)
+        return 0;
+      if((new_firsttail<old_head)&&((new_cycles-old_cycles)==1))
+        return 0;
+    }
+    tail_info->msg_head=(ul_cbuff_msg_head_t *)old_head;
+    return 1;
+  }
+  return 1;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+  ul_cbuff_loc_t res_size;
+  unsigned int length;
+  ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
+
+  if(!msg_head)
+    return -1;
+
+  if(!ul_cbuff_is_ready(msg_head))
+    return 0;
+
+  res_size=buff->state->buff_size-((unsigned char*)msg_head-buff->buff_start);
+  length=msg_head->length;
+
+  if(res_size > ul_cbuff_msg_head_size){
+    tail_info->data.ptr=(unsigned char*)msg_head+ul_cbuff_msg_head_size;
+    if(res_size-ul_cbuff_msg_head_size >= length){
+      tail_info->data.cont_len=length;
+      tail_info->data.wrap_ptr=NULL;
+      tail_info->data.wrap_len=0;
+    }else{
+      tail_info->data.cont_len=res_size-ul_cbuff_msg_head_size;
+      tail_info->data.wrap_ptr=buff->buff_start;
+      tail_info->data.wrap_len=length-(res_size-ul_cbuff_msg_head_size);
+    }
+  } else {
+    tail_info->data.ptr=buff->buff_start;
+    tail_info->data.cont_len=length;
+    tail_info->data.wrap_ptr=NULL;
+    tail_info->data.wrap_len=0;
+  }
+  return msg_head->flags;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+  ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
+  unsigned msg_readers;
+
+  if(!ul_cbuff_is_ready(msg_head))
+    return -1;
+
+  if(buff->state->readers<=0)
+    return 1;
+
+  msg_readers=msg_head->flags&UL_CBUFF_MSG_READERS;
+  if(msg_readers)
+    msg_head->flags--;
+
+  return msg_readers<=1?1:0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+  ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
+
+  if(!ul_cbuff_is_ready(msg_head))
+    return -1;
+
+  tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+
+                       ul_cbuff_next_loc(buff, msg_head));
+  return 0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next)
+{
+  if(loc==buff->state->firsttail)
+    buff->state->firsttail=loc_next;
+
+  if(release_result<=0)
+    return 0;
+
+  if(loc==buff->state->lasttail){
+    buff->state->lasttail=loc_next;
+    return 1;
+  }else{
+    return -1;
+  }
+}
+
+ul_cbuff_inline void
+ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info)
+{
+  data_info->ptr=data_info->wrap_ptr;
+  data_info->cont_len=data_info->wrap_len;
+  data_info->wrap_ptr=NULL;
+  data_info->wrap_len=0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size)
+{
+  int cont_len;
+
+  *pptr=data_info->ptr;
+  if(!data_info->ptr)
+    return 0;
+  cont_len=data_info->cont_len;
+  if(cont_len>size){
+    cont_len=size;
+    data_info->ptr+=size;
+    data_info->cont_len-=cont_len;
+  }else{
+    ul_cbuff_data_do_wrap(data_info);
+  }
+  return cont_len;
+}
+
+ul_cbuff_inline int
+ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size)
+{
+  void *ptr;
+  int count;
+  int cont_len;
+
+  ptr=data_info->ptr;
+  if(!ptr)
+    return 0;
+  cont_len=data_info->cont_len;
+  if(cont_len>size){
+    cont_len=size;
+    data_info->ptr+=size;
+    data_info->cont_len-=cont_len;
+  }else{
+    ul_cbuff_data_do_wrap(data_info);
+  }
+  if(cont_len<=0)
+    return 0;
+  memcpy(ptr,data,cont_len);
+  count=cont_len;
+  cont_len=size-cont_len;
+  if(!cont_len)
+    return count;
+
+  ptr=data_info->ptr;
+  if(!ptr)
+    return count;
+  data=(char*)data+count;
+  if(cont_len>data_info->cont_len)
+    cont_len=data_info->cont_len;
+  data_info->ptr+=cont_len;
+  data_info->cont_len-=cont_len;
+  memcpy(ptr,data,cont_len);
+
+  return cont_len+count;
+}
+
+ul_cbuff_inline int
+ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size)
+{
+  void *ptr;
+  int count;
+  int cont_len;
+
+  ptr=data_info->ptr;
+  if(!ptr)
+    return 0;
+  cont_len=data_info->cont_len;
+  if(cont_len>size){
+    cont_len=size;
+    data_info->ptr+=size;
+    data_info->cont_len-=cont_len;
+  }else{
+    ul_cbuff_data_do_wrap(data_info);
+  }
+  if(cont_len<=0)
+    return 0;
+  memcpy(data,ptr,cont_len);
+  count=cont_len;
+  cont_len=size-cont_len;
+  if(!cont_len)
+    return count;
+
+  ptr=data_info->ptr;
+  if(!ptr)
+    return count;
+  data=(char*)data+count;
+  if(cont_len>data_info->cont_len)
+    cont_len=data_info->cont_len;
+  data_info->ptr+=cont_len;
+  data_info->cont_len-=cont_len;
+  memcpy(data,ptr,cont_len);
+
+  return cont_len+count;
+}
+
+
+ul_cbuff_inline void *
+ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
+{
+  ul_cbuff_loc_t loc;
+  unsigned int size;
+  ul_cbuff_state_t *state=buff->state;
+
+  size=ul_cbuff_align(msg_head->length+state->rear_size)+ul_cbuff_msg_head_size;
+  size-=state->rear_size;
+
+  loc=(unsigned char*)msg_head-buff->buff_start;
+  if(state->buff_size-loc > size)
+    loc+=size;
+  else
+    loc=size-(state->buff_size-loc);
+
+  return buff->buff_start+loc;
+}
+
+ul_cbuff_inline void *
+ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc)
+{
+  ul_cbuff_state_t *state=buff->state;
+
+  if(loc>state->rear_size)
+    return buff->buff_start+loc-state->rear_size;
+  else
+    return buff->buff_start+loc+state->buff_size-state->rear_size;
+}
+
+#endif /*UL_CBUFF_INLINE*/
+
+int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
+                 void *buff_start, ul_cbuff_loc_t size);
+
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* _UL_CBUFF_H */
index a2f8a0e9bcaa2ec9279c82326d18525b14afadc8..436e8d597e00ca9957b47b2544ac0d9e7977d6f5 100644 (file)
@@ -3,12 +3,6 @@
 
 #include "ul_dbuff.h"
 
-#define LOG_FATAL   0
-#define LOG_ERR     1
-#define LOG_MSG     2
-#define LOG_INF     3
-#define LOG_DEB     4
-
 /**
  * ul_dbuff_log_hex - writes content of dbuff to log
  * @buf: buffer structure