new kfifo API
Stefani Seibold
maintainerPATCH 7/7 new kfifo API
include/linux/kfifo.h | 381 ++++++++++++++++++++++++++++++++++++++++++++++++--
kernel/kfifo.c | 275 ++++++++++++++++++++++++------------ 2 files changed, 551 insertions(+), 105 deletions(-)
Signed-off-by Stefani Seibold <[email protected]>
include/linux/kfifo.h +367 -14
@@ -60,9 +60,9 @@ unsigned int size, gfp_t gfp_mask);extern void kfifo_free (struct kfifo *fifo);extern __must_check unsigned int kfifo_in (struct kfifo *fifo, -const unsigned char *buffer,unsigned int len); +const unsigned char *from,unsigned int len);extern __must_check unsigned int kfifo_out (struct kfifo *fifo, -unsigned char *buffer,unsigned int len); +unsigned char *to,unsigned int len);/** * kfifo_reset - removes the entire FIFO contents
@@ -83,7 +83,7 @@ }/** -* kfifo_reset_in - skip output FIFO contents +* kfifo_reset_out - skip output FIFO contents * @fifo: the fifo to be emptied. */ static inline void kfifo_reset_out (struct kfifo *fifo)
@@ -92,6 +92,15 @@ }/** +* kfifo_is_empty - returns true if the fifo is empty +* @fifo: the fifo to be used. +*/ +static inline __must_check int kfifo_is_empty (struct kfifo *fifo) +{ +return fifo->in == fifo->out; +} + +/** * kfifo_in_locked - puts some data into the FIFO using a spinlock for locking * @fifo: the fifo to be used. * @buffer: the data to be added.
@@ -141,8 +150,8 @@* optimization: if the FIFO is empty, set the indices to 0 * so we don't wrap the next time */ -if (fifo->in == fifo->out) - fifo->in = fifo->out =0 ; +if (kfifo_is_empty (fifo)) +kfifo_reset (fifo);spin_unlock_irqrestore (lock, flags);
@@ -172,15 +181,6 @@ }/** -* kfifo_is_empty - returns true if the fifo is empty -* @fifo: the fifo to be used. -*/ -static inline __must_check int kfifo_is_empty (struct kfifo *fifo) -{ -return fifo->in == fifo->out; -} - -/** * kfifo_is_full - returns true if the fifo is full * @fifo: the fifo to be used. */
@@ -204,4 +204,357 @@extern __must_check unsigned int kfifo_to_user (struct kfifo *fifo,void __user *to,unsigned int n); +/** +* __kfifo_add_out internal helper function for updating the out offset +*/ +static inline void __kfifo_add_out (struct kfifo *fifo, +unsigned int off) +{ +smp_mb (); + fifo->out += off; +} + +/** +* __kfifo_add_in internal helper function for updating the in offset +*/ +static inline void __kfifo_add_in (struct kfifo *fifo, +unsigned int off) +{ +smp_wmb (); + fifo->in += off; +} + +/** +* __kfifo_off internal helper function for calculating the index of a +* given offeset +*/ +static inline unsigned int __kfifo_off (struct kfifo *fifo,unsigned int off) +{ +return off & (fifo->size-1 ); +} + +/** +* __kfifo_peek_n internal helper function for determinate the length of +* the next record in the fifo +*/ +static inline unsigned int __kfifo_peek_n (struct kfifo *fifo, +unsigned int recsize) +{ +#define KFIFO_GET (fifo, off, shift) \ + ((fifo)->buffer[__kfifo_off((fifo), (fifo)->out+(off))] << (shift)) + +unsigned int l; + + l =KFIFO_GET (fifo,0 ,0 ); + +if (unlikely (--recsize)) + l |=KFIFO_GET (fifo,1 ,8 ); + +return l; +} + +/** +* __kfifo_poke_n internal helper function for storing the length of +* the next record into the fifo +*/ +static inline void __kfifo_poke_n (struct kfifo *fifo, +unsigned int recsize,unsigned int n) +{ +#define KFIFO_PUT (fifo, off, val, shift) \ + ( \ + (fifo)->buffer[__kfifo_off((fifo), (fifo)->in+(off))] = \ + (unsigned char)((val) >> (shift)) \ + ) + +KFIFO_PUT (fifo,0 , n,0 ); + +if (unlikely (--recsize)) +KFIFO_PUT (fifo,1 , n,8 ); +} + +/** +* __kfifo_in_... internal functions for put date into the fifo +* do not call it directly, use kfifo_in_rec() instead +*/ +extern unsigned int __kfifo_in_n (struct kfifo *fifo, +const unsigned char *from,unsigned int n,unsigned int recsize); + +extern unsigned int __kfifo_in_generic (struct kfifo *fifo, +const unsigned char *from,unsigned int n,unsigned int recsize); + +static inline unsigned int __kfifo_in_rec (struct kfifo *fifo, +const unsigned char *from,unsigned int n,unsigned int recsize) +{ +unsigned int ret; + + ret =__kfifo_in_n (fifo, from, n, recsize); + +if (ret > n) +return ret; + +if (likely (ret ==0 )) { +if (recsize) +__kfifo_poke_n (fifo, recsize, n); +__kfifo_add_in (fifo, n + recsize); + } +return ret; +} + +/** +* kfifo_in_rec - puts some record data into the FIFO +* @fifo: the fifo to be used. +* @from: the data to be added. +* @n: the length of the data to be added. +* @recsize: size of record field +* +* This function copies @n bytes from the @from into +* the FIFO and returns the number of bytes which cannot be copied. +* A returned value greater than the @n value means that the record doesn't +* fit into the buffer. +* +* Note that with only one concurrent reader and one concurrent +* writer, you don't need extra locking to use these functions. +*/ +static inline __must_check unsigned int kfifo_in_rec (struct kfifo *fifo, +unsigned char *from,unsigned int n,unsigned int recsize) +{ +if (!__builtin_constant_p (recsize)) +return __kfifo_in_generic (fifo, from, n, recsize); + +return __kfifo_in_rec (fifo, from, n, recsize); +} + +/** +* __kfifo_out_... internal functions for get date from the fifo +* do not call it directly, use kfifo_out_rec() instead +*/ +extern unsigned int __kfifo_out_n (struct kfifo *fifo, +unsigned char *to,unsigned int n,unsigned int reclen, +unsigned int recsize); + +extern unsigned int __kfifo_out_generic (struct kfifo *fifo, +unsigned char *to,unsigned int n, +unsigned int recsize,unsigned int *total); + +static inline unsigned int __kfifo_out_rec (struct kfifo *fifo, +unsigned char *to,unsigned int n,unsigned int recsize, +unsigned int *total) +{ +unsigned int l; + +if (!recsize) { + l = n; +if (total) + *total = l; + }else { + l =__kfifo_peek_n (fifo, recsize); +if (total) + *total = l; +if (n < l) +return l; + } + +return __kfifo_out_n (fifo, to, n, l, recsize); +} + +/** +* kfifo_out_rec - gets some record data from the FIFO +* @fifo: the fifo to be used. +* @to: where the data must be copied. +* @n: the size of the destination buffer. +* @recsize: size of record field +* @total: pointer where the total number of to copied bytes should stored +* +* This function copies at most @n bytes from the @to into +* the FIFO and returns the number of bytes which cannot be copied. +* A returned value greater than the @n value means that the record doesn't +* fit into the @to buffer. +* +* Note that with only one concurrent reader and one concurrent +* writer, you don't need extra locking to use these functions. +*/ +static inline __must_check unsigned int kfifo_out_rec (struct kfifo *fifo, +unsigned char *to,unsigned int n,unsigned int recsize, +unsigned int *total) + +{ +if (!__builtin_constant_p (recsize)) +return __kfifo_out_generic (fifo, to, n, recsize, total); + +return __kfifo_out_rec (fifo, to, n, recsize, total); +} + +/** +* __kfifo_from_user_... internal functions for transfer from user space into +* the fifo. do not call it directly, use kfifo_from_user_rec() instead +*/ +extern unsigned int __kfifo_from_user_n (struct kfifo *fifo, +const void __user *from,unsigned int n,unsigned int recsize); + +extern unsigned int __kfifo_from_user_generic (struct kfifo *fifo, +const void __user *from,unsigned int n,unsigned int recsize); + +static inline unsigned int __kfifo_from_user_rec (struct kfifo *fifo, +const void __user *from,unsigned int n,unsigned int recsize) +{ +unsigned int ret; + + ret =__kfifo_from_user_n (fifo, from, n, recsize); + +if (ret > n) +return ret; + +if (likely (ret ==0 )) { +if (recsize) +__kfifo_poke_n (fifo, recsize, n); +__kfifo_add_in (fifo, n + recsize); + } +return ret; +} + +/** +* kfifo_from_user_rec - puts some data from user space into the FIFO +* @fifo: the fifo to be used. +* @from: pointer to the data to be added. +* @n: the length of the data to be added. +* @recsize: size of record field +* +* This function copies @n bytes from the @from into the +* FIFO and returns the number of bytes which cannot be copied. +* +* If the returned value is equal or less the @n value, the copy_from_user() +* functions has failed. Otherwise the record doesn't fit into the buffer. +* +* Note that with only one concurrent reader and one concurrent +* writer, you don't need extra locking to use these functions. +*/ +static inline __must_check unsigned int kfifo_from_user_rec (struct kfifo *fifo, +const void __user *from,unsigned int n,unsigned int recsize) +{ +if (__builtin_constant_p (recsize)) +return __kfifo_from_user_rec (fifo, from, n, recsize); +return __kfifo_from_user_generic (fifo, from, n, recsize); +} + +/** +* __kfifo_to_user_... internal functions for transfer fifo data into user space +* do not call it directly, use kfifo_to_user_rec() instead +*/ +extern unsigned int __kfifo_to_user_n (struct kfifo *fifo, +void __user *to,unsigned int n,unsigned int reclen, +unsigned int recsize); + +extern unsigned int __kfifo_to_user_generic (struct kfifo *fifo, +void __user *to,unsigned int n,unsigned int recsize, +unsigned int *total); + +static inline unsigned int __kfifo_to_user_rec (struct kfifo *fifo, +void __user *to,unsigned int n, +unsigned int recsize,unsigned int *total) +{ +unsigned int l; + +if (!recsize) { + l = n; +if (total) + *total = l; + }else { + l =__kfifo_peek_n (fifo, recsize); +if (total) + *total = l; +if (n < l) +return l; + } + +return __kfifo_to_user_n (fifo, to, n, l, recsize); +} + +/** +* kfifo_to_user_rec - gets data from the FIFO and write it to user space +* @fifo: the fifo to be used. +* @to: where the data must be copied. +* @n: the size of the destination buffer. +* @recsize: size of record field +* @total: pointer where the total number of to copied bytes should stored +* +* This function copies at most @n bytes from the FIFO into the +* @to. +* In case of an error, the function returns the number of bytes which cannot +* be copied. +* If the returned value is equal or less the @n value, the copy_to_user() +* functions has failed. Otherwise the record doesn't fit into the @to buffer. +* +* Note that with only one concurrent reader and one concurrent +* writer, you don't need extra locking to use these functions. +*/ +static inline __must_check unsigned int kfifo_to_user_rec (struct kfifo *fifo, +void __user *to,unsigned int n,unsigned int recsize, +unsigned int *total) +{ +if (__builtin_constant_p (recsize)) +return __kfifo_to_user_rec (fifo, to, n, recsize, total); +return __kfifo_to_user_generic (fifo, to, n, recsize, total); +} + +/** +* __kfifo_peek_... internal functions for peek into the next fifo record +* do not call it directly, use kfifo_peek_rec() instead +*/ +extern unsigned int __kfifo_peek_generic (struct kfifo *fifo, +unsigned int recsize); + +/** +* kfifo_peek_rec - gets the size of the next FIFO record data +* @fifo: the fifo to be used. +* @recsize: size of record field +* +* This function returns the size of the next FIFO record in number of bytes +*/ +static inline __must_check unsigned int kfifo_peek_rec (struct kfifo *fifo, +unsigned int recsize) +{ +if (__builtin_constant_p (recsize)) { +if (!recsize) +return kfifo_len (fifo); +return __kfifo_peek_n (fifo, recsize); + } +return __kfifo_peek_generic (fifo, recsize); +} + +/** +* __kfifo_skip_... internal functions for peek into the next fifo record +* do not call it directly, use kfifo_skip_rec() instead +*/ +extern unsigned int __kfifo_peek_generic (struct kfifo *fifo, +unsigned int recsize); + +static inline __must_check void __kfifo_skip_rec (struct kfifo *fifo, +unsigned int recsize) +{ +if (!recsize) +kfifo_reset_out (fifo); + + l =__kfifo_peek_n (fifo, recsize); + +if (l + recsize >kfifo_len ()) +kfifo_reset_out (fifo); + +__kfifo_add_out (fifo, l + recsize); +} + +/** +* kfifo_skip_rec - skip the next output record +* @fifo: the fifo to be used. +* @recsize: size of record field +* +* This function skips the next FIFO record +*/ +static inline __must_check unsigned int kfifo_skip_rec (struct kfifo *fifo, +unsigned int recsize) +{ +if (__builtin_constant_p (recsize)) +return __kfifo_skip_rec (fifo, recsize); +return __kfifo_skip_generic (fifo, recsize); +} +#endif
kernel/kfifo.c +184 -91
384 lines not on this page · raw message