[数据结构][LINUX内核编程]学习笔记(二)

linux内核————队列

linux内核——队列

定义:

[cpp] view plaincopy

  1. struct __kfifo{
  2. unsigned int in;  //入队偏移,写索引
  3. unsigned int out;  //出队偏移,读索引
  4. unsigned int mask;
  5. unsigned int esize;
  6. void *data;
  7. }

使用:

创建一个队列,该函数创建并初始化一个大小为size的kfifo:

[cpp] view plaincopy

  1. 38 int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
  2. 39                 size_t esize, gfp_t gfp_mask)
  3. 40 {
  4. 45         size = roundup_pow_of_two(size);
  5. 46
  6. 47         fifo->in = 0;
  7. 48         fifo->out = 0;
  8. 49         fifo->esize = esize;
  9. 50
  10. 51         if (size < 2) {
  11. 52                 fifo->data = NULL;
  12. 53                 fifo->mask = 0;
  13. 54                 return -EINVAL;
  14. 55         }
  15. 56
  16. 57         fifo->data = kmalloc(size * esize, gfp_mask);
  17. 58
  18. 59         if (!fifo->data) {
  19. 60                 fifo->mask = 0;
  20. 61                 return -ENOMEM;
  21. 62         }
  22. 63         fifo->mask = size - 1;
  23. 64
  24. 65         return 0;
  25. 66 }

判断一个整数是否是2的整数次幂

[cpp] view plaincopy

  1. static inline int is_power_of_2(unsigned long long n)
  2. {
  3. return (n!=0 &&(n&(n-1)==0))
  4. }

推入数据到队列的方法是kfifo_in()函数

[cpp] view plaincopy

  1. 102 static void kfifo_copy_in(struct __kfifo *fifo, const void *src,
  2. 103                 unsigned int len, unsigned int off)
  3. 104 {
  4. 105         unsigned int size = fifo->mask + 1;
  5. 106         unsigned int esize = fifo->esize;
  6. 107         unsigned int l;
  7. 108
  8. 109         off &= fifo->mask;  //该操作从数学角度将就是对长度fifo->mask的取模运算
  9. 110         if (esize != 1) {
  10. 111                 off *= esize;
  11. 112                 size *= esize;
  12. 113                 len *= esize;
  13. 114         }
  14. 115         l = min(len, size - off);  //size-off代表的含义是当前in到缓冲区尾的大小,
  15. 116     /*
  16. 先从buffer中拷贝l字节到缓冲区剩余空间,l<=len,也<=从real_in开始到缓冲区结尾的空间
  17. 所以这个copy可能没拷贝完,但是不会造成缓冲区越界
  18. */
  19. 117         memcpy(fifo->data + off, src, l);
  20. /*
  21. len > l时,拷贝buffer中剩余的内容,其实地址当然为buffer + l,而剩余的大小为len - l
  22. 当len == l时,下面的memcpy啥都不干
  23. */
  24. 118         memcpy(fifo->data, src + l, len - l);
  25. 123         smp_wmb();
  26. 124 }
  27. 125
  28. 126 unsigned int __kfifo_in(struct __kfifo *fifo,
  29. 127                 const void *buf, unsigned int len)  //buf指向的是请求入队的缓冲区,len表示的是请求写入的大小
  30. 128 {
  31. 129         unsigned int l;
  32. 131         l = kfifo_unused(fifo);//计算队列中剩余空间的大小,fifo->size-(fifo->in-fifo->out)
  33. 132         if (len > l)
  34. 133                 len = l;
  35. 135         kfifo_copy_in(fifo, buf, len, fifo->in);
  36. 136         fifo->in += len;
  37. 137         return len;
  38. 138 }

kfifo的巧妙之处在于in和out定义为无符号类型,在put和get时,in和out都是增加,当达到最大值时,产生溢出,使得从0开始,进行循环使用

时间: 2024-10-25 23:00:21

[数据结构][LINUX内核编程]学习笔记(二)的相关文章

[数据结构][LINUX内核编程]学习笔记(一)

linux内核使用bitmap相关 1,声明一个bitmap数组,可以表示100个bit,数组名字是bitmap [cpp] view plaincopy DECLARE_BITMAP(bitmap,100) 相关宏定义如下: [cpp] view plaincopy #define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)] #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr

[linux内核][LINUX内核编程]学习笔记(二)

linux内核————队列 linux内核——队列 定义: [cpp] view plaincopy struct __kfifo{ unsigned int in;  //入队偏移,写索引 unsigned int out;  //出队偏移,读索引 unsigned int mask; unsigned int esize; void *data; } 使用: 创建一个队列,该函数创建并初始化一个大小为size的kfifo: [cpp] view plaincopy 38 int __kfif

linux sheel编程学习笔记(二) --- grep命令

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户. grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板.如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名.搜索的结果被送到标准输出,不影响原文件内容. grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成

linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)

errno 在unix系统中对大部分系统调用非正常返回时,通常返回值为-1,并设置全局变量errno(errno.h),如socket(), bind(), accept(), listen().erron存放一个正整数来保存上次出错的错误值. 对线程而言,每个线程都有专用的errno变量,不必考虑同步问题. strerror converts to English (Note: use strerror_r for thread safety) perror is simplified str

linux网络编程学习笔记之六 -----I/O多路复用服务端

多进程和多线程的目的是在于最大限度地利用CPU资源,当某个进程不需要占用太多CPU资源,而是需要I/O资源时,可以采用I/O多路复用,基本思路是让内核把进程挂起,直到有I/O事件发生时,再把控制返回给程序.这种事件驱动模型的高效之处在于,省去了进程和线程上下文切换的开销.整个程序运行在单一的进程上下文中,所有的逻辑流共享整个进程的地址空间.缺点是,编码复杂,而且随着每个逻辑流并发粒度的减小,编码复杂度会继续上升. I/O多路复用典型应用场合(摘自UNP6.1) select的模型就是这样一个实现

Linux System Programming 学习笔记(二) 文件I/O

1.每个Linux进程都有一个最大打开文件数,默认情况下,最大值是1024 文件描述符不仅可以引用普通文件,也可以引用套接字socket,目录,管道(everything is a file) 默认情况下,子进程会获得其父进程文件表的完整拷贝 2.打开文件 open系统调用必须包含 O_RDONLY,O_WRONLY,O_RDWR 三种存取模式之一 注意 O_NONBLOCK模式 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644

linux网络编程学习笔记之四 -----多线程并发服务端

相对于使用进程实现并发,用线程的实现更加轻量.每个线程都是独立的逻辑流.线程是CPU上独立调度运行的最小单位,而进程是资源分配的单位.当然这是在微内核的操作系统上说的,简言之这种操作系统的内核是只提供最基本的OS服务,更多参看点击打开链接 每个线程有它自己的线程上下文,包括一个唯一的线程ID(linux上实现为unsigned long),栈,栈指针,程序计数器.通用目的寄存器和条件码,还有自己的信号掩码和优先级.同一个进程里的线程共享这个进程的整个虚拟地址空间,包括可执行的程序文本.程序的全局

linux网络编程学习笔记之五 -----并发机制与线程?

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我仅仅是举几个样例作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.能够在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理须要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也非常easy,在主线程中定时,定

linux网络编程学习笔记之五 -----并发机制与线程池

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我只是举几个例子作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.可以在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理需要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也很简单,在主线程中定时,定时到期,