简介

使用内核的KFIFO作为缓冲区

API

  1. #include <linux/kfifo.h>
  2. # 声明一个FIFO
  3. #define DEFINE_KFIFO(fifo, type, size)
  4. # 使用例子
  5. static struct device *mydemodrv_device;
  6. DEFINE_KFIFO(mydemo_fifo, char, 64);
  7. # 读数据
  8. #define kfifo_to_user(fifo, to, len, copied)
  9. # 写数据
  10. #define kfifo_from_user(fifo, from, len, copied)

使用例程

  1. static struct device *mydemodrv_device;
  2. DEFINE_KFIFO(mydemo_fifo, char, 64);
  3. # 将数据读取到buf 中。
  4. kfifo_to_user(&mydemo_fifo, buf, count, &actual_readed);
  5. # 将数据从buf写入fifo
  6. kfifo_from_user(&mydemo_fifo, buf, count, &actual_write);

代码分析

  1. struct __kfifo {
  2. unsigned int in;
  3. unsigned int out;
  4. unsigned int mask;
  5. unsigned int esize;
  6. void *data; # 存放数据的指针
  7. };
  1. #include "kfifo.h"
  2. DEFINE_KFIFO(mydemo_fifo, char, 64);
  3. # gcc -E test.c -o test.i

声明

  1. # 将 DEFINE_KFIFO(mydemo_fifo, char, 64); 使用预处理以后的结果 test.i
  2. # 其中 rectype 这一个字段是
  3. struct __kfifo {
  4. unsigned int in;
  5. unsigned int out;
  6. unsigned int mask;
  7. unsigned int esize;
  8. void *data;
  9. };
  10. struct kfifo {
  11. union {
  12. struct __kfifo kfifo;
  13. unsigned char *type; # 存储类型
  14. const unsigned char *const_type; #
  15. char (*rectype)[0]; #
  16. void *ptr; #
  17. void const *ptr_const;
  18. };
  19. unsigned char buf[0];
  20. };
  21. struct kfifo_rec_ptr_1 {
  22. union {
  23. struct __kfifo kfifo;
  24. unsigned char *type;
  25. const unsigned char *const_type;
  26. char (*rectype)[1];
  27. void *ptr;
  28. void const *ptr_const;
  29. };
  30. unsigned char buf[0];
  31. };
  32. struct kfifo_rec_ptr_2 {
  33. union {
  34. struct __kfifo kfifo;
  35. unsigned char *type;
  36. const unsigned char *const_type;
  37. char (*rectype)[2];
  38. void *ptr;
  39. void const *ptr_const;
  40. };
  41. unsigned char buf[0];
  42. };
  43. static inline unsigned int __must_check
  44. __kfifo_uint_must_check_helper(unsigned int val) {
  45. return val;
  46. }
  47. static inline int __must_check __kfifo_int_must_check_helper(int val) {
  48. return val;
  49. }
  50. # 比较重要的是这里, 声明缓存区和前后指针
  51. struct {
  52. union {
  53. struct __kfifo kfifo;
  54. char *type;
  55. const char *const_type;
  56. char (*rectype)[0];
  57. char *ptr;
  58. char const *ptr_const;
  59. }; # 可以看到,Kfifio是由一个联合体组合成的,缓存区buf,以及 union 的联合体
  60. char buf[((64 < 2) || (64 & (64 - 1))) ? -1 : 64]; # 静态定义一个 64 字节的区域
  61. } mydemo_fifo = (typeof(mydemo_fifo)){{{ # 这里就是直接在声明一个结构体的时候定义并且初始化结构体。
  62. .in = 0,# 初始化的是 __kfifo 结构体里面的数据
  63. .out = 0,
  64. .mask = (sizeof(*&(mydemo_fifo)) == sizeof(struct __kfifo))
  65. ? 0
  66. : ARRAY_SIZE((mydemo_fifo).buf) - 1,
  67. .esize = sizeof(*(mydemo_fifo).buf), # 前面使用的数组存储数组,表示数组的长度
  68. .data = (sizeof(*&(mydemo_fifo)) == sizeof(struct __kfifo))
  69. ? NULL
  70. : (mydemo_fifo).buf,
  71. }}};

读数据

  1. # kfifo_to_user(&mydemo_fifo, buf, count, &actual_readed); 预处理以后的数据
  2. __kfifo_uint_must_check_helper(({
  3. typeof((&mydemo_fifo) + 1) __tmp = (&mydemo_fifo);
  4. void __user *__to = (buf);
  5. unsigned int __len = (count);
  6. unsigned int *__copied = (&actual_readed);
  7. const size_t __recsize = sizeof(*__tmp->rectype);
  8. struct __kfifo *__kfifo = &__tmp->kfifo;
  9. (__recsize) ? __kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize)
  10. : __kfifo_to_user(__kfifo, __to, __len, __copied);
  11. }));
  12. 我们可以观察到,调用的是两个函数(or
  13. extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
  14. unsigned long len, unsigned int *copied,
  15. size_t recsize);
  16. 或者
  17. extern int __kfifo_to_user(struct __kfifo *fifo, void __user *to,
  18. unsigned long len, unsigned int *copied);

__kfifo_to_user 函数

kfifo_to_user 函数将会调用 __kfifo_to_user来判断越界等操作。然后调用静态函数kfifo_copy_to_user来赋值数据。最终还是调用的 copy_to_user函数。

  1. lib/kfifo.c
  2. int __kfifo_to_user(struct __kfifo *fifo, void __user *to,
  3. unsigned long len, unsigned int *copied)
  4. kfifo_copy_to_user(fifo, to, len, fifo->out, copied);
  5. copy_to_user(to, fifo->data + off, l);