实现共享环形缓冲区的生产消费者模型,包含用户层生产者 内核层生产者 内核层消费者
用户层
#include <fcntl.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
int total_lost_count;
void *uthread_producer(void *arg) {
int fd = open("/dev/ring_test_drv", O_RDWR);
uint32_t seq_num = 1;
while (1) {
write(fd, &seq_num, sizeof(uint32_t));
read(fd, &total_lost_count, sizeof(int));
if(total_lost_count != 0){
printf("data is lose ! stop thread");
close(fd);
break;
}
seq_num++;
}
}
int main() {
pthread_t producer_thread;
if (pthread_create(&producer_thread, NULL, uthread_producer, NULL) != 0) {
perror("Failed to create thread");
return 1;
}
pthread_join(producer_thread, NULL);
return 0;
}
内核层
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
#include <linux/sunyu_buffer.h>
static int producer_thread(void *data)
{
int num = 1;
while (!kthread_should_stop()) {
spin_lock(&rb.lock);
while (!kthread_should_stop() && is_full(&rb)) {
spin_unlock(&rb.lock);
wait_event_interruptible(rb.producer_wq, !is_full(&rb));
spin_lock(&rb.lock);
}
produce_data(&rb, KTHREAD, num);
printk("kernel_thread create num %d at index %d", num, rb.head);
num = num + 1;
spin_unlock(&rb.lock);
wake_up_interruptible(&rb.consumer_wq);
}
return 0;
}
static int consumer_thread(void *data)
{
while (!kthread_should_stop()) {
struct data *current_data = &rb.buffer[rb.tail];
wait_event_interruptible(rb.consumer_wq, !is_empty(&rb));
check_data(current_data);
consume_data(&rb, current_data);
wake_up_interruptible_all(&rb.producer_wq);
}
return 0;
}
static int ring_drv_open(struct inode *node, struct file *file)
{
wake_up_process(kthread_producer);
wake_up_process(kthread_consumer);
return 0;
}
static ssize_t ring_drv_read(struct file *file, char __user *buffer,
size_t length, loff_t *offset)
{
int ret;
ret = copy_to_user(buffer, &total_lost_count, sizeof(int));
return sizeof(int);
}
static ssize_t ring_drv_write(struct file *file, const char __user *num,
size_t size, loff_t *offset)
{
struct data user_data;
int ret;
spin_lock(&rb.lock);
while (is_full(&rb)) {
spin_unlock(&rb.lock);
wait_event_interruptible(rb.producer_wq, !is_full(&rb));
spin_lock(&rb.lock);
}
ret = copy_from_user(&user_data.seq_num, num, size);
produce_data(&rb, USER, user_data.seq_num);
printk("user_thread create num %d in index%d",
rb.buffer[rb.head].seq_num, rb.head);
spin_unlock(&rb.lock);
wake_up_interruptible(&rb.consumer_wq);
return size;
}
static int ring_drv_close(struct inode *node, struct file *file)
{
kthread_stop(kthread_producer);
kthread_stop(kthread_consumer);
return 0;
}
static struct file_operations ring_fops = {
.owner = THIS_MODULE,
.open = ring_drv_open,
.read = ring_drv_read,
.write = ring_drv_write,
.release = ring_drv_close,
}
static int __init ring_init(void)
{
rb.head = 0;
rb.tail = 0;
spin_lock_init(&rb.lock);
kthread_consumer =
kthread_create(consumer_thread, NULL, "kthread_consumer");
kthread_producer = kthread_create(producer_thread, (void *)KTHREAD,
"kthread_producer");
init_waitqueue_head(&rb.producer_wq);
init_waitqueue_head(&rb.consumer_wq);
major = register_chrdev(0, "ring_drv", &ring_fops);
ring_class = class_create(THIS_MODULE, "ring_class");
device_create(ring_class, NULL, MKDEV(major, 0), NULL, "ring_test_drv");
return 0;
}
static void __exit ring_exit(void)
{
device_destroy(ring_class, MKDEV(major, 0));
class_destroy(ring_class);
unregister_chrdev(major, "ring_drv");
}
module_init(ring_init);
module_exit(ring_exit);
MODULE_LICENSE("GPL");
内核层包含的头文件
#define RING_BUFFER_SIZE 32
static int major = 0;
static struct class *ring_class;
enum producer { KTHREAD, USER };
struct data {
enum producer p;
uint32_t seq_num;
};
struct ring_buffer {
struct data buffer[RING_BUFFER_SIZE];
int head;
int tail;
struct spinlock lock;
wait_queue_head_t consumer_wq;
wait_queue_head_t producer_wq;
};
static int lost_count_kernel = 0;
static int lost_count_user = 0;
static int total_lost_count = 0;
static uint32_t last_seq_num_kernel = 0;
static uint32_t last_seq_num_user = 0;
static struct task_struct *kthread_consumer;
static struct task_struct *kthread_producer;
static struct ring_buffer rb;
static int is_empty(struct ring_buffer *rb)
{
return rb->head == rb->tail;
}
static int is_full(struct ring_buffer *rb)
{
return (rb->head + 1) % RING_BUFFER_SIZE == rb->tail;
}
static void check_data(struct data *current_data)
{
total_lost_count = lost_count_kernel + lost_count_user;
if (current_data->p == KTHREAD) {
if (current_data->seq_num != last_seq_num_kernel + 1) {
lost_count_kernel += current_data->seq_num -
last_seq_num_kernel - 1;
printk("Producer Kernel Data lost detected! Lost count: %d %d\n",
lost_count_kernel, last_seq_num_kernel);
}
last_seq_num_kernel = current_data->seq_num;
} else if (current_data->p == USER) {
if (current_data->seq_num != last_seq_num_user + 1) {
lost_count_user += current_data->seq_num -
last_seq_num_user - 1;
printk("Producer User Data lost detected! Lost count: %d %d\n",
lost_count_user, last_seq_num_user);
}
last_seq_num_user = current_data->seq_num;
}
}
static void produce_data(struct ring_buffer *rb, enum producer p,
uint32_t seq_num)
{
rb->buffer[rb->head].p = p;
rb->buffer[rb->head].seq_num = seq_num;
rb->head = (rb->head + 1) % RING_BUFFER_SIZE;
}
static void consume_data(struct ring_buffer *rb, struct data *current_data)
{
printk("Consumer: Producer %s, Seq: %u\n",
current_data->p == KTHREAD ? "Kernel" : "User",
current_data->seq_num);
rb->tail = (rb->tail + 1) % RING_BUFFER_SIZE;
}