linux内核的队列实现移植

[!TOC]

在c编程中有时会使用一些常用的数据结构,如队列。每次都手写一遍有些麻烦,写一个通用的比较好,而内核有实现队列,直接移植出来就好了。

内核的队列实现

  内核的队列实现在linux-2.6.32.68/kernel/kfifo.c和对应的kfifo.h中,主要接口罗列如下:

struct kfifo {unsigned char *buffer;  /* the buffer holding the data */unsigned int size;  /* the size of the allocated buffer */unsigned int in;    /* data is added at offset (in % size) */unsigned int out;   /* data is extracted from off. (out % size) */spinlock_t *lock;   /* protects concurrent modifications */
};extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,spinlock_t *lock);
extern void kfifo_free(struct kfifo *fifo);
static inline void kfifo_reset(struct kfifo *fifo);
static inline unsigned int kfifo_put(struct kfifo *fifo,const unsigned char *buffer, unsigned int len);
static inline unsigned int kfifo_get(struct kfifo *fifo,unsigned char *buffer, unsigned int len);
static inline unsigned int kfifo_len(struct kfifo *fifo);                     

函数名字已非常清晰的表明了用途,无需多言。说一下,它的实现里面我觉得比较好的几个点。

  • 内核实现的亮点
    较我自己以前实现的队列而言,在队列发生循环时,会通过取余的方式去更新队尾和队头下标。这样队尾下标有可能比队头下标小。计算队列长度时,相减又需要考虑此种情况。
    而内核in和out是一直递增的(因为是无符号,溢出也没关系),put和get时通过fifo->in & (fifo->size - 1)方式取余计算,分开拷贝。内核的put核心代码如下:
unsigned int __kfifo_put(struct kfifo *fifo,const unsigned char *buffer, unsigned int len)
{unsigned int l;len = min(len, fifo->size - fifo->in + fifo->out);/* first put the data starting from fifo->in to buffer end */l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);/* then put the rest (if any) at the beginning of the buffer */memcpy(fifo->buffer, buffer + l, len - l);fifo->in += len;return len;
}

移植

  移植到普通应用,可以视情况去掉还是保留锁机制,在这儿就去掉了,再替换掉一些kmalloc这样的内核函数,实现is_power_of_2和roundup_pow_of_two两个函数就可以了。为了通用性,fifo.c里的代码都是对char型指针结合长度参数进行写入读取,而在自己使用时,可以在fifo.h里封装一下,方便自己的数据存放和读取。我在测试时封装成了存取int整数。


fifo.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "fifo.h"static inline int is_power_of_2(unsigned int n)
{return !((n - 1) & n);
}unsigned int roundup_pow_of_two(unsigned int n)
{if(is_power_of_2(n))return n;int i = 32;while(i--){if((n >> i) & 1)break;}n = 1 << (i + 1);return n;
} struct fifo *fifo_init(unsigned char *buffer, unsigned int size)
{struct fifo *fifo;fifo = malloc(sizeof(struct fifo));if (!fifo){fprintf(stderr, "malloc %ubyte failed\n", sizeof(struct fifo));return NULL;}fifo->buffer = buffer;fifo->size = size;fifo->in = fifo->out = 0;return fifo;
}struct fifo *fifo_alloc(unsigned int size)
{unsigned char *buffer;struct fifo *ret;/* round up to the next power of 2 */if(size > 0x80000000){fprintf(stderr, "The size is too lager\n");return NULL;}size = roundup_pow_of_two(size);buffer = malloc(size);if (!buffer){fprintf(stderr, "malloc %ubyte failed\n", size);return NULL;}ret = fifo_init(buffer, size);if (!ret)free(buffer);return ret;
}void fifo_free(struct fifo *fifo)
{free(fifo->buffer);free(fifo);
}unsigned int _fifo_put(struct fifo *fifo, const unsigned char *buffer, unsigned int len)
{unsigned int l;len = min(len, fifo->size - fifo->in + fifo->out);/* first put the data starting from fifo->in to buffer end */l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);/* then put the rest (if any) at the beginning of the buffer */memcpy(fifo->buffer, buffer + l, len - l);fifo->in += len;return len;
}unsigned int _fifo_get(struct fifo *fifo, unsigned char *buffer, unsigned int len)
{unsigned int l;len = min(len, fifo->in - fifo->out);/* first get the data from fifo->out until the end of the buffer */l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);/* then get the rest (if any) from the beginning of the buffer */memcpy(buffer + l, fifo->buffer, len - l);fifo->out += len;return len;
}

fifo.h

#ifndef _FIFO_H_
#define _FIFO_H_struct fifo {unsigned char *buffer;  /* the buffer holding the data */unsigned int size;  /* the size of the allocated buffer */unsigned int in;    /* data is added at offset (in % size) */unsigned int out;   /* data is extracted from off. (out % size) */
};#define min(a, b) ((a) > (b) ? (b) : (a))extern struct fifo *fifo_alloc(unsigned int size);
extern void fifo_free(struct fifo *fifo);
extern unsigned int _fifo_put(struct fifo *fifo, const unsigned char *buffer, unsigned int len);
extern unsigned int _fifo_get(struct fifo *fifo,unsigned char *buffer, unsigned int len);static inline void _fifo_reset(struct fifo *fifo)
{fifo->in = fifo->out = 0;
}static inline unsigned int _fifo_len(struct fifo *fifo)
{return fifo->in - fifo->out;
}/****************************************************/
/* 根据需要进行封装,这儿我封装为保存int数
/****************************************************/static inline void fifo_reset(struct fifo *fifo)
{_fifo_reset(fifo);
}static inline unsigned int fifo_len(struct fifo *fifo)
{return _fifo_len(fifo)/4;
}static inline unsigned int fifo_put(struct fifo *fifo, int n)
{return _fifo_put(fifo, (unsigned char *)&n, sizeof(int));
}static inline unsigned int fifo_get(struct fifo *fifo, int *n)
{return _fifo_get(fifo, (unsigned char *)n, sizeof(int));
}#endif

linux内核的队列实现移植相关推荐

  1. Linux内核的裁剪和移植

    linux内核的裁剪和移植具体都在这个网址里面. https://blog.csdn.net/xie0812/article/details/10816059 https://blog.csdn.ne ...

  2. 话说linux内核-uboot和系统移植第14部分-朱有鹏-专题视频课程

    话说linux内核-uboot和系统移植第14部分-5304人已学习 课程介绍         本课程为linux kernel移植的第1部分,主要内容是对linux内核有关的知识和概念的补充.认识清 ...

  3. 基于ARM的嵌入式linux 内核的裁剪与移植

    0 引言     微处理器的产生为价格低廉.结构小巧的CPU和外设的连 接提供了稳定可靠的硬件架构,这样,限制嵌入式系统发展的瓶颈就突出表现在了软件方面.尽管从八十年代末开始,已经陆续出现了一些嵌入式 ...

  4. linux内核的裁剪和移植实验,实验5 linux内核的裁剪移植.doc

    实验5 linux内核的裁剪移植 一.实验目的: 学习利用menuconfig配置文件进行裁减内核,编译内核并移植到开发板上. 二.实验内容 一.开发环境 宿主机:ubuntu10.04 开发板:ti ...

  5. 移植linux内核-映像文件,移植Linux内核-映像文件

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://tigerwang202.blogbus.com/logs/43927976.html 首先从Blackfin uCli ...

  6. STM32MP157 Linux系统移植开发篇14:Linux内核RGB LCD驱动移植

    本文章为<STM32MP157 Linux系统移植开发篇>系列中的一篇,笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板).stm32mp157是ARM双核,2 ...

  7. linux内核多队列,Linux Kernel 中 Workqueue 使用系统默认队列和创建队列的方法

    关于workqueue,我们还是有很多话要说. 想必大家对workqueue相关的函数(schedule_work .queue_work.INIT_WORK.create_singlethread_ ...

  8. Linux内核RED队列实现

    关于RED队列的TC配置命令,参见:RED队列tc设置. 1 RED入队列 首先计算平均队列长度qavg,参见之后函数red_calc_qavg的介绍.如果队列处于空闲状态,退出空闲状态,清空空闲开始 ...

  9. linux 内核主线,为AM335x移植Linux内核主线代码(41)Ethernet结论篇

    一口老血喷到屏幕上! 请自动略过之前的第36-40小节=_=!!! ===================================== https://www.tuicool.com/arti ...

最新文章

  1. Oracle to_char函数的使用方法
  2. windows mobile开发循序渐进(5)移动应用程序与webservice之间的数据交互
  3. mysql弱口令加强_MySQL弱口令利用
  4. 一起撸个朋友圈吧(step5) - 控件篇【评论控件优化】
  5. undi是什么意思_undefined是什么意思啊
  6. [Swift]数组排序:sort和sorted
  7. 在Teams Hackathon上介绍LuckyDraw
  8. MAVEN简介之——settings.xml
  9. 大家一起讨论一下朋友网的人脉关系算法是怎么实现的
  10. FFmpeg总结(二)AV系列结构体之AVFrame
  11. 国密SM2算法的只求理解不求甚解 (3/5)SM2算法数学模型
  12. c语言将一句英文逆序输出,C++实现英文句子中的单词逆序输出的方法
  13. JavaScript复习,this指向、原型链、变量提升、作用域、闭包
  14. Cassandra启动过程详解【原创】
  15. 小白一看就懂的性能调优
  16. 天翼云携手华为,强强联合,共创数据存储新生态
  17. LaTex关于数学公式的使用(7)--- 函数单边大括号
  18. 30多种免费的高级WordPress主题,适用于令人惊叹的照片,教育和房地产网站
  19. 阿里云为啥在云服务器市场输给腾讯云
  20. CV2逐步学习-2:cv2.GaussianBlur()详解

热门文章

  1. matlab中round函数_Excel中round函数的使用方法
  2. TF-IDF算法-golang实现
  3. 【新手向】阿里云上ubuntu+flask+gunicorn+nginx服务器部署(二)项目部署
  4. 软件工程网络15个人阅读作业1(201521123062 杨钧宇)
  5. Jmeter-Ant 生成测试报告
  6. 图 | 为什么存在关于图的研究
  7. su root 后还是不能使用useradd ,useradd 等命令
  8. javascript 200列(3)
  9. 文件上传 文件大小和类型
  10. 【Vue】—Vue脚手架创建项目时的 linter / formatter config配置选择