linux环形缓冲区kfifo实践1

本次实验使用的kfifo相关宏

cpp 复制代码
struct __kfifo {
	unsigned int	in;
	unsigned int	out;
	unsigned int	mask;
	unsigned int	esize;
	void		*data;

	
};
cpp 复制代码
/*
 * define compatibility "struct kfifo" for dynamic allocated fifos
 */
struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);

判空:kfifo_is_empty

cpp 复制代码
/**
 * kfifo_is_empty - returns true if the fifo is empty
 * @fifo: address of the fifo to be used
 */
#define	kfifo_is_empty(fifo) \
({ \
	typeof((fifo) + 1) __tmpq = (fifo); \
	__tmpq->kfifo.in == __tmpq->kfifo.out; \
})

判满:kfifo_is_full

cpp 复制代码
/**
 * kfifo_is_full - returns true if the fifo is full
 * @fifo: address of the fifo to be used
 */
#define	kfifo_is_full(fifo) \
({ \
	typeof((fifo) + 1) __tmpq = (fifo); \
	kfifo_len(__tmpq) > __tmpq->kfifo.mask; \
})

判断fifo可用空间大小 kfifo_avail

cpp 复制代码
/**
 * kfifo_avail - returns the number of unused elements in the fifo
 * @fifo: address of the fifo to be used
 */
#define	kfifo_avail(fifo) \
__kfifo_uint_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmpq = (fifo); \
	const size_t __recsize = sizeof(*__tmpq->rectype); \
	unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \
	(__recsize) ? ((__avail <= __recsize) ? 0 : \
	__kfifo_max_r(__avail - __recsize, __recsize)) : \
	__avail; \
}) \
)

为kfifo分配空间kfifo_alloc

和kfifo_free成对使用。

cpp 复制代码
/**
 * kfifo_alloc - dynamically allocates a new fifo buffer
 * @fifo: pointer to the fifo
 * @size: the number of elements in the fifo, this must be a power of 2
 * @gfp_mask: get_free_pages mask, passed to kmalloc()
 *
 * This macro dynamically allocates a new fifo buffer.
 *
 * The numer of elements will be rounded-up to a power of 2.
 * The fifo will be release with kfifo_free().
 * Return 0 if no error, otherwise an error code.
 */
#define kfifo_alloc(fifo, size, gfp_mask) \
__kfifo_int_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	__is_kfifo_ptr(__tmp) ? \
	__kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \
	-EINVAL; \
}) \
)

释放为kfifo分配的空间kfifo_free

cpp 复制代码
/**
 * kfifo_free - frees the fifo
 * @fifo: the fifo to be freed
 */
#define kfifo_free(fifo) \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	if (__is_kfifo_ptr(__tmp)) \
		__kfifo_free(__kfifo); \
})

kfifo_from_user:复制用户空间的数据到kfifo

kfifo_from_user()宏用来将用户空间的数据写入环形缓冲区中,其中参数fifo表示使用哪个环形缓冲区;from 表示用户空间缓冲区的起始地址;len 表示要复制多少个元素;copied保存了成功复制元素的数量,通常用作返回值。

cpp 复制代码
/**
 * kfifo_from_user - puts some data from user space into the fifo
 * @fifo: address of the fifo to be used
 * @from: pointer to the data to be added
 * @len: the length of the data to be added
 * @copied: pointer to output variable to store the number of copied bytes
 *
 * This macro copies at most @len bytes from the @from into the
 * fifo, depending of the available space and returns -EFAULT/0.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
#define	kfifo_from_user(fifo, from, len, copied) \
__kfifo_uint_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	const void __user *__from = (from); \
	unsigned int __len = (len); \
	unsigned int *__copied = (copied); \
	const size_t __recsize = sizeof(*__tmp->rectype); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	(__recsize) ? \
	__kfifo_from_user_r(__kfifo, __from, __len,  __copied, __recsize) : \
	__kfifo_from_user(__kfifo, __from, __len, __copied); \
}) \
)

kfifo_to_user:复制kfifo中的数据到用户空间

kfifo_to_user()宏用来读出环形缓冲区的数据并且复制到用户空间中,其中参数fifo表示使用哪个环形缓冲区;to表示用户空间缓冲区的起始地址;len 表示要复制多少个元素;copied保存了成功复制元素的数量,通常用作返回值。

cpp 复制代码
/**
 * kfifo_to_user - copies data from the fifo into user space
 * @fifo: address of the fifo to be used
 * @to: where the data must be copied
 * @len: the size of the destination buffer
 * @copied: pointer to output variable to store the number of copied bytes
 *
 * This macro copies at most @len bytes from the fifo into the
 * @to buffer and returns -EFAULT/0.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
#define	kfifo_to_user(fifo, to, len, copied) \
__kfifo_uint_must_check_helper( \
({ \
	typeof((fifo) + 1) __tmp = (fifo); \
	void __user *__to = (to); \
	unsigned int __len = (len); \
	unsigned int *__copied = (copied); \
	const size_t __recsize = sizeof(*__tmp->rectype); \
	struct __kfifo *__kfifo = &__tmp->kfifo; \
	(__recsize) ? \
	__kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \
	__kfifo_to_user(__kfifo, __to, __len, __copied); \
}) \
)

实验代码:

驱动代码:

cpp 复制代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/kfifo.h>

#define DEBUG_INFO(format, ...) printk("%s:%d -- "format"\n",\
__func__,__LINE__,##__VA_ARGS__)

struct ch5_kfifo_struct{
    struct miscdevice misc;
    struct file_operations fops;
    // struct __kfifo fifo;
    // DECLARE_KFIFO(fifo, char, 64);
    struct kfifo fifo;
    char buf[64];
};

static int ch5_open (struct inode *inode, struct file *file){
    struct ch5_kfifo_struct *p = (struct ch5_kfifo_struct *)container_of(file->f_op,struct ch5_kfifo_struct,fops);
    file->private_data = p;
    DEBUG_INFO("major = %d, minor = %d\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
    DEBUG_INFO("name = %s",p->misc.name);
    return 0;
}
static int ch5_release (struct inode *inode, struct file *file){
    DEBUG_INFO("close");
    return 0;
}

static ssize_t ch5_read (struct file *file, char __user *buf, size_t size, loff_t *pos){
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    int ret;
    int actual_readed = 0;
    if(kfifo_is_empty(&p->fifo)){
        DEBUG_INFO("kfifo is null");
        return 0;
    }
    ret = kfifo_to_user(&p->fifo, buf, size, &actual_readed);
    if (ret){
        DEBUG_INFO("kfifo_to_user error");
		return -EIO;
    }
    
    DEBUG_INFO("size = %d,actual_readed = %d\n",size,actual_readed);

    memset(p->buf,0,sizeof(p->buf));
    ret = copy_from_user(p->buf, buf, actual_readed);
    
    if(ret != 0){
        DEBUG_INFO("copy_from_user error ret = %d\n",ret);
    }else{
        DEBUG_INFO("p->buf = %s\n",p->buf);
    }
    return 0;
}
static ssize_t ch5_write (struct file *file, const char __user *buf, size_t size, loff_t* pos){
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    int actual_writed = 0;
    int ret;
    ret = kfifo_from_user(&p->fifo, buf, size, &actual_writed);
    if (ret){
        DEBUG_INFO("kfifo_from_user error");
		return -EIO;
    }
    DEBUG_INFO("actual_writed = %d\n",actual_writed);

    if(*pos == 0){
        *pos = size;
        return size;
    }
    *pos = *pos + size;
    return size;
}

struct ch5_kfifo_struct ch5_kfifo = {
    .misc = { 
        .name = "ch5-03-kfifo",
        .minor = MISC_DYNAMIC_MINOR,
    },
    .fops = {
        .owner = THIS_MODULE,
        .read = ch5_read,
        .write = ch5_write,
        .open = ch5_open,
        .release = ch5_release,
    },
};

static int __init ch5_init(void){
    int ret = 0;
    DEBUG_INFO("start init\n");
    ch5_kfifo.misc.fops = &ch5_kfifo.fops;
    ret = kfifo_alloc(&ch5_kfifo.fifo,
				64,
				GFP_KERNEL);
    if (ret) {
        DEBUG_INFO("kfifo_alloc error: %d\n", ret);
        ret = -ENOMEM;
        return ret;
    }
    DEBUG_INFO("kfifo_alloc ok");

    ret = misc_register(&ch5_kfifo.misc);
    if(ret < 0){
        DEBUG_INFO("misc_register error: %d\n", ret);
        return ret;
    }
    DEBUG_INFO("misc_register ok");
    return 0;
}

static void __exit ch5_exit(void){
    DEBUG_INFO("exit\n");
    misc_deregister(&ch5_kfifo.misc);
    kfifo_free(&ch5_kfifo.fifo);
}

module_init(ch5_init);
module_exit(ch5_exit);

MODULE_LICENSE("GPL");

应用代码

cpp 复制代码
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>

#define DEBUG_INFO(format, ...) printf("%s:%d -- "format"\n",\
__func__,__LINE__,##__VA_ARGS__)

int main(int argc, char**argv){
    int fd;
    char buf[1024];
    char *filename = NULL;
    if(argc < 2){
        filename = "/dev/ch5-03-kfifo";
    }else{
        filename = argv[1];
    }

    fd = open(argv[1], O_WRONLY);
    if(fd < 0){
        perror("open");
        return -1;
    }
    write(fd, filename, strlen(filename));
    memset(buf, 0, sizeof(buf));
    close(fd);

    fd = open(argv[1], O_RDONLY);
    if(fd < 0){
        perror("open");
        return -1;
    }
    memset(buf, 0, sizeof(buf));
    read(fd, buf, sizeof(buf));
    DEBUG_INFO("buf = %s",buf);
    close(fd);

    return 0;
}

makefile

bash 复制代码
modname:=ch5-03-kfifo
obj-m:=$(modname).o
PWD :=$(shell pwd)
MAKE :=make
KERNELDIR = /home/lkmao/running_github/runninglinuxkernel_4.0
CROSS_COMPILE=arm-linux-gnueabi-
ARCH=arm
all:
	$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
	cp $(modname).ko /home/lkmao/running_github/runninglinuxkernel_4.0/kmodules
	arm-linux-gnueabi-gcc -o app app.c --static
	cp app /home/lkmao/running_github/runninglinuxkernel_4.0/kmodules

clean:
	rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions *.ko
.PHONY: all clean

测试结果:

小结

相关推荐
Konwledging7 小时前
kernel-devel_kernel-headers_libmodules
linux
Web极客码7 小时前
CentOS 7.x如何快速升级到CentOS 7.9
linux·运维·centos
一位赵8 小时前
小练2 选择题
linux·运维·windows
代码游侠8 小时前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
Lw老王要学习9 小时前
CentOS 7.9达梦数据库安装全流程解析
linux·运维·数据库·centos·达梦
CRUD酱9 小时前
CentOS的yum仓库失效问题解决(换镜像源)
linux·运维·服务器·centos
zly350010 小时前
VMware vCenter Converter Standalone 转换Linux系统,出现两个磁盘的处理
linux·运维·服务器
Albert Edison10 小时前
【Python】函数
java·linux·python·pip
General_G10 小时前
Linux中的信号
linux·运维·服务器
诸神缄默不语10 小时前
当无法直接用apt instll时,Linux如何离线安装软件包(以make为例)
linux·运维·服务器