写个软驱动作进程/线程通信

1.Linux 进程通信机制

  首先来回顾下Linux下进程通信(IPC)机制方式。

【1】信号(signal)

【2】信号量(semophore)

【3】消息队列(message queue)

【4】管道(piple),包括匿名管道(s_pipe)和有名管道(FIFO)

【5】共享内存(shared memory)

【6】套接字(socket)

  如果不使用以上进程通信机制,如何实现两个进程通信?可能想到其中一个手段就是“文件”,通过文件实现两个进程通信,但访问磁盘文件速率远不如内存,加之文件寻址、文件系统映射等,更是耗时操作。


2.软驱动

  从“共享文件”思路出发,因为Linux思想是“一切皆文件”,外设驱动、管道等都是文件,因此我们可以实现一个“软驱动”作进程通信。整体思路是,申请内核一段内存,实现标准驱动接口,进程通过文件描述符(fd)访问该段内存,从而实现两个进程通信。

  从实现思路知道,该方式表象似“共享内存”机制,实质更与“管道”相像。“共享内存”是最快的进程通信机制,两个进程数据交换时只有2次的内存拷贝,进程A内存——>物理内存——进程B内存。而“管道”则存在4次内存拷贝,进程A内存——>内核空间——>物理内存——>内核空间——>进程B内存。

在这里插入图片描述

3.实现

3.1实现接口

  实现常用的接口:

【1】open,打开一个软驱动

【2】close,关闭一个软驱动

【3】read,读数据

【4】write,写数据

【5】ioctl,控制类,如改变共享内存大小

【6】lseek,地址偏移操作

3.2 Code

【driver】


#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define DEV_MEM_MEMSET		_IO('M', 0)
#define DEV_MEM_GET_SIZE	_IOR('M', 1, int)
#define DEV_MEM_SET_SIZE	_IOW('M', 2, int)

#define MEMORY_DEFULT_SIZE 	128
#define DEV_NAME			"dev_mem"

struct memory_device
{
    struct 	cdev 	dev;
	dev_t			devno;
	struct class 	*devclass;
	char			*mem_buf;
	uint32_t		mem_size;
};

static struct 	memory_device *pmemory_dev = NULL;

static int memory_open(struct inode * inode , struct file * pfile)
{
	int state = 0;

    if(pmemory_dev == NULL)
    {
		printk("empty memory.\n");
		return -EFAULT;
	}
	
	pmemory_dev->mem_buf = kmalloc(MEMORY_DEFULT_SIZE, GFP_KERNEL);
	if(pmemory_dev->mem_buf)
	{
		pmemory_dev->mem_size = MEMORY_DEFULT_SIZE;
		state = 0;
	}
	else
	{
		state = -1;
		printk("kmalloc request memory falied.\n");
	}

	pfile->private_data = pmemory_dev;
    return state;
}

static ssize_t memory_read(struct file * pfile, char __user *buffer, size_t size, loff_t *offset)
{
	unsigned long of = 0;
	struct memory_device *p;

	p = pfile->private_data;
	of = *offset;
	if(of > p->mem_size)
	{
		return 0;
	}
    if (size > (p->mem_size - of))
    {
    	size = p->mem_size - of;
    }
	
    if (copy_to_user(buffer, p->mem_buf+of, size))
    {
    	printk("read memory falied.\n");
        return -EFAULT;
    }
	else
	{
		*offset -= size;
	}
    return size;
}

static ssize_t memory_write(struct file * pfile, const char __user *buffer, size_t size, loff_t *offset)
{
	unsigned long of = 0;
	struct memory_device *p;

	p = pfile->private_data;
	of = *offset;
	if(of > p->mem_size)
	{
		return 0;
	}
   	if (size > (p->mem_size - of))
    {
    	size = p->mem_size -of;
    }
   
    if (copy_from_user(p->mem_buf+of, buffer, size))
    {
    	printk("write memory falied.\n");
        return -EFAULT;
    }
	else
	{
		*offset += size;
	}

    return size;
}

static ssize_t memory_close(struct inode * inode , struct file * pfile)
{
	int state = 0;
	struct memory_device *p;

	p = pfile->private_data;

	if(p->mem_buf)
	{
		kfree(p->mem_buf);
		p->mem_size = 0;
	}

    return state;
}

static int memory_ioctl(struct inode *inode, struct file *pfile, unsigned int cmd, unsigned long arg)
{
	int state = 0;
	int temp = 0;
	char *pmem = NULL;
	struct memory_device *p;

	p = pfile->private_data;
	switch(cmd)
	{
		case DEV_MEM_MEMSET:
			memset(p->mem_buf, 0, p->mem_size);
		break;
		
		case DEV_MEM_GET_SIZE:
			if(copy_to_user((int __user*)arg, &p->mem_size, 4)) 
			{
				return -ENOTTY;
			}
		break;

		case DEV_MEM_SET_SIZE:
			if(copy_from_user(&temp, (int __user*)arg, 4))
			{
				return -ENOTTY;
			}
			if(temp != p->mem_size)
			{
				pmem = kmalloc(temp, GFP_KERNEL);
				if(pmem)
				{
					kfree(p->mem_buf);
					p->mem_buf = NULL;
					p->mem_size = temp;
					p->mem_buf = pmem;
				}
			}
		break;

		default:
		break;
	}
	
	return state;
}

static loff_t memory_llseek(struct file *pfile, loff_t offset, int whence)
{ 
    loff_t of;
	struct memory_device *p;
	
	p = pfile->private_data;
    switch(whence) 
	{
      case SEEK_SET: 
        of = offset;
        break;

      case SEEK_CUR:
        of = pfile->f_pos + offset;
        break;

      case SEEK_END:
        of = p->mem_size -1 + offset;
        break;

      default: 
        return -EINVAL;
    }
    if ((of<0) || (of>p->mem_size))
    	return -EINVAL;
    	
    pfile->f_pos = of;
	
    return of;
}


static const struct file_operations memory_fops = 
{
    .owner 	 = THIS_MODULE,
    .open 	 = memory_open,
    .read    = memory_read,
    .write   = memory_write,
    .release = memory_close,
    .ioctl   = memory_ioctl,
    .llseek = memory_llseek,
};

static int __init memory_init(void)
{
    int ret = -1;
	dev_t	devno = 0;

	ret = alloc_chrdev_region(&devno, 0, 1, "dev_mem"); 
	if (ret)
	{
		printk("alloc dev-no failed.\n");
		return ret;
	}
	
    pmemory_dev = kmalloc(sizeof(struct memory_device), GFP_KERNEL);
    if (NULL == pmemory_dev)
    {
        ret = -ENOMEM;
        printk("kmalloc request memory falied.\n");
		return ret;
    }
    memset(pmemory_dev, 0, sizeof(struct memory_device));

	pmemory_dev->devno = devno; 
    cdev_init(&pmemory_dev->dev, &memory_fops);
    pmemory_dev->dev.owner 	= THIS_MODULE;
    pmemory_dev->dev.ops 	= &memory_fops;
    ret = cdev_add(&pmemory_dev->dev, pmemory_dev->devno, 1);
    if (ret)
    {
    	unregister_chrdev_region(pmemory_dev->devno, 1);
    	kfree(pmemory_dev);
        return ret;
    }

    pmemory_dev->devclass = class_create(THIS_MODULE, "mem_class");
	if (IS_ERR(pmemory_dev->devclass)) 
	{
		printk("class_create failed.\n");
		cdev_del(&pmemory_dev->dev);
		ret = -EIO;
		return ret;
	}
	
    device_create(pmemory_dev->devclass, NULL, pmemory_dev->devno, NULL, "dev_mem");

    return 0;
}

static void __exit memory_exit(void)
{
    device_destroy(pmemory_dev->devclass, pmemory_dev->devno);
    class_destroy(pmemory_dev->devclass);
    cdev_del(&pmemory_dev->dev);
    unregister_chrdev_region(pmemory_dev->devno, 1);
	kfree(pmemory_dev->mem_buf);
	pmemory_dev->devclass = NULL;
	pmemory_dev->mem_buf = NULL;
	pmemory_dev->mem_size = 0;
	kfree(pmemory_dev);
	pmemory_dev = NULL;
}

module_init(memory_init);
module_exit(memory_exit);
MODULE_LICENSE("GPL");

【Makefile】

ifeq ($(KERNELRELEASE),)

KERNELDIR = /usr/src/linux-headers-2.6.32-38-generic
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
	rm -rf *.o *.ko .mod.o *.mod.c *.symvers

else
	obj-m := dev_mem.o
endif

【application】


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <semaphore.h> 
#include <linux/ioctl.h>

#define DEV_MEM_MEMSET		_IO('M', 0)
#define DEV_MEM_GET_SIZE	_IOR('M', 1, int)
#define DEV_MEM_SET_SIZE	_IOW('M', 2, int)

sem_t  *r_sem;

int main(int argc, char** argv)

{
	int pid;
	char buf[16] = {0};
	int fd;
  	int mem_size = 0;

	fd = open("/dev/dev_mem", O_RDWR);
    if (-1 == fd)
    {
        perror("open error\n");
        return -2;
    }
    printf("open \"dev_mem\" success\n");
	
	r_sem = sem_open("rse", O_CREAT|O_RDWR, 0777, 0);
	if(r_sem == SEM_FAILED)
	{
		perror("sem_open");
		close(fd);
		return -1;
	}
	
	pid = fork();
	if(pid > 0)
	{
		ioctl(fd, DEV_MEM_GET_SIZE, &mem_size); 
		printf("Get dev memory size [%d]\n", mem_size);

		mem_size = 256;
		printf("Set dev memory size [%d]\n", mem_size);
		ioctl(fd, DEV_MEM_SET_SIZE, &mem_size); 
	
		mem_size = 0;
		ioctl(fd, DEV_MEM_GET_SIZE, &mem_size); 
		printf("Get dev memory size [%d]\n", mem_size);

		ioctl(fd, DEV_MEM_MEMSET); 
		write(fd, "Hello word", 10);
		//lseek(fd, 0, SEEK_CUR);
		//lseek(fd, 10, SEEK_SET);
		write(fd, " ABCD", 5);
		sem_post(r_sem);
		wait();
	}
	else if(pid == 0)
	{
		sem_wait(r_sem);
		lseek(fd, 0, SEEK_SET);
		read(fd, buf, 15);
		printf("read mem:%s\n", buf);
		close(fd);
	}
	else
	{
		perror("fork error");
		close(fd);
	}
	
    return 0;
}

3.3 运行

  可以直接在桌面Linux系统执行,非必须在嵌入式环境。编译完,加载驱动(.ko),然后编译app执行。


3.4 代码仓库

【1】https://github.com/Prry/linux-drivers/tree/master/devmem

posted @ 2019-10-19 22:32  Acuity  阅读(72)  评论(0编辑  收藏  举报