进程间通信:KPIPE

源代码:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <linux/module.h>  
#include <linux/fs.h>  
#include <linux/errno.h>  
#include <linux/mm.h>  
#include <linux/cdev.h>  

//module_param(dev_major, int, S_IRUGO);  
#define MY_DEV_MAJOR        260     /*预设的mem的主设备号*/  
static int dev_major = 0; //MY_DEV_MAJOR;  

#define MY_DEV_NR_DEVS      2       /*设备数*/  

#define CHAR_DEV_NAME       "kpipe"
  
/*
'k'为幻数,要按照Linux内核的约定方法为驱动程序选择ioctl编号,
应该首先看看include/asm/ioctl.h和Documentation/ioctl-number.txt这两个文件.

对幻数的编号千万不能重复定义,如ioctl-number.txt已经说明‘k'的编号已经被占用的范围为:
'k'    00-0F    linux/spi/spidev.h    conflict!
'k'    00-05    video/kyro.h        conflict!
所以我们在这里分别编号为0x1a和0x1b
*/
#define CMD_MAGIC   'k'
#define MEM_CMD1    _IO(CMD_MAGIC, 0x1a)
#define MEM_CMD2    _IO(CMD_MAGIC, 0x1b)
#define MEM_CMD3    _IO(CMD_MAGIC, 0x1c)

#if 1
#define MAX_UID_NUM     32

typedef struct tagUSER_MSG_INFO
{
    int  uid;
    int  param1;
    int  param2;
    int  param3;
    char *msg;
}USER_MSG_INFO;

typedef struct tagUSER_QUEUE_INFO
{
    int  rd_ptr;
    int  wt_ptr;
    int  max_msg;
    int  msg_max_len;
    char *msg_queue;
}USER_QUEUE_INFO;

USER_QUEUE_INFO usr_queue[MAX_UID_NUM];

static int user_queue_init(void)
{
    int i;

    for(i = 0; i < MAX_UID_NUM; i++) {
        memset(&usr_queue[i], 0, sizeof(USER_QUEUE_INFO));
    }
    return 0;
}

static int user_queue_alloc(int uid, int max_msg, int msg_max_len)
{
    int total_size;
    
    if (uid >= MAX_UID_NUM) return -1;
    if (max_msg < 1 || msg_max_len < 1) return -1;
    if (usr_queue[uid].msg_queue != NULL) return -2;

    total_size = max_msg * msg_max_len;
    usr_queue[uid].msg_queue = kmalloc(total_size, GFP_KERNEL);  
    if (NULL == usr_queue[uid].msg_queue) return -3;

    usr_queue[uid].max_msg = max_msg;
    usr_queue[uid].msg_max_len = msg_max_len;
    usr_queue[uid].rd_ptr = 0;
    usr_queue[uid].wt_ptr = 0;
    
    return 0;
}

static int user_queue_push(USER_MSG_INFO *usr_msg)
{
    int uid;
    char *ptr;
    
    if (NULL == usr_msg) return -1;
    uid = usr_msg->uid;
    if (usr_queue[uid].msg_queue == NULL) return -2;

    if ( (usr_queue[uid].wt_ptr + 1) % usr_queue[uid].max_msg == usr_queue[uid].rd_ptr)
        return -3; // full

    ptr = usr_queue[uid].msg_queue + usr_queue[uid].wt_ptr * usr_queue[uid].msg_max_len;
    memset(ptr, 0, usr_queue[uid].msg_max_len);
    copy_from_user((int *)ptr, (int *)usr_msg->msg, usr_queue[uid].msg_max_len);
    usr_queue[uid].wt_ptr = (usr_queue[uid].wt_ptr + 1) % usr_queue[uid].max_msg;
        
    return 0;
}

static int user_queue_pop(USER_MSG_INFO *usr_msg)
{
    int uid;
    char *ptr;
    
    if (NULL == usr_msg) return -1;
    uid = usr_msg->uid;
    if (usr_queue[uid].msg_queue == NULL) return -2;

    if ( usr_queue[uid].rd_ptr == usr_queue[uid].wt_ptr)
        return -3; // empty

    ptr = usr_queue[uid].msg_queue + usr_queue[uid].rd_ptr * usr_queue[uid].msg_max_len;
    copy_to_user((int *)usr_msg->msg, (int *)ptr, usr_queue[uid].msg_max_len);
    usr_queue[uid].rd_ptr = (usr_queue[uid].rd_ptr + 1) % usr_queue[uid].max_msg;
        
    return 0;
}

static int user_queue_destroy(void)
{
    int i;

    for(i = 0; i < MAX_UID_NUM; i++) {
        usr_queue[i].max_msg = 0;
        if (NULL != usr_queue[i].msg_queue)
            kfree(usr_queue[i].msg_queue);
        usr_queue[i].msg_queue = NULL;
    }
    return 0;
}


#endif

#if 1
int my_dev_open(struct inode *inode, struct file *filp)  
{  
    return 0;   
}  
  
int my_dev_release(struct inode *inode, struct file *filp)  
{  
    return 0;  
}  
static int my_dev_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{    
    USER_MSG_INFO user_msg;
    int ret = 0;
    
    switch(cmd)
    {
        case MEM_CMD1: // init mq for uid
            if(copy_from_user(&user_msg,  (int *)arg, sizeof(USER_MSG_INFO))) 
                return -EFAULT;
            
            ret = user_queue_alloc(user_msg.uid, user_msg.param1, user_msg.param2);
            break;
            
        case MEM_CMD2: // send msg to uid
            if(copy_from_user(&user_msg,  (int *)arg, sizeof(USER_MSG_INFO))) 
                return -EFAULT;

            ret = user_queue_push(&user_msg);
            break;
        
        case MEM_CMD3: // get msg from uid
            if(copy_from_user(&user_msg,  (int *)arg, sizeof(USER_MSG_INFO))) 
                return -EFAULT;
            
            ret = user_queue_pop(&user_msg);
            break;
    }
    
    return ret;
}

static const struct file_operations my_dev_fops =  
{  
    .owner = THIS_MODULE,  
    .unlocked_ioctl = my_dev_ioctl,
    .open = my_dev_open,  
    .release = my_dev_release,  
};  

struct class *pclass = NULL;  
  
struct cdev my_dev;   

static int my_dev_init(void)  
{  
    int result;  
    dev_t devno = MKDEV(dev_major, 0);  

    if (dev_major) { /* 静态申请设备号*/  
        result = register_chrdev_region(devno, 2, CHAR_DEV_NAME);  
    } else { /* 动态分配设备号 */  
        result = alloc_chrdev_region(&devno, 0, 2, CHAR_DEV_NAME);  
        dev_major = MAJOR(devno);  
    }   

    if (result < 0)  
        return result;  

    cdev_init(&my_dev, &my_dev_fops);  
    my_dev.owner = THIS_MODULE;  
    my_dev.ops = &my_dev_fops;  
    cdev_add(&my_dev, MKDEV(dev_major, 0), MY_DEV_NR_DEVS);  

    pclass = class_create(THIS_MODULE, CHAR_DEV_NAME);  
    if (IS_ERR(pclass))  
    {  
        printk("class_create failed!/n");  
        goto failed;  
    }  

    user_queue_init();
    device_create(pclass, NULL, devno, NULL, CHAR_DEV_NAME);  
    return 0;  

failed:   
    cdev_del(&my_dev);
    unregister_chrdev_region(devno, 1);  
    return result;  
}  
  
static void my_dev_exit(void)  
{  
    device_destroy(pclass, MKDEV(dev_major, 0));  
    class_destroy(pclass);
    
    cdev_del(&my_dev);
    unregister_chrdev_region(MKDEV(dev_major, 0), 2); 
    user_queue_destroy();
}  

#endif

MODULE_AUTHOR("derek.yi");  
MODULE_LICENSE("GPL");  
  
module_init(my_dev_init);  
module_exit(my_dev_exit);  

 

测试代码:

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

#define CMD_MAGIC   'k'
#define MEM_CMD1    _IO(CMD_MAGIC, 0x1a) // init
#define MEM_CMD2    _IO(CMD_MAGIC, 0x1b) // write
#define MEM_CMD3    _IO(CMD_MAGIC, 0x1c) // read

typedef struct tagUSER_MSG_INFO
{
    int  uid;
    int  param1;
    int  param2;
    int  param3;
    char *msg;
}USER_MSG_INFO;


#define _APP_001_

#ifdef _APP_001_
int main()
{
    int fd;
    int ret;
    char buff[256];
    USER_MSG_INFO usr_msg;

    fd = open("/dev/kpipe", O_RDWR);
    if( fd < 0 ) {
        printf("open kpipe WRONG!\n");
        return 0;
    }

    usr_msg.uid = 0;
    usr_msg.param1 = 64; // max msg
    usr_msg.param2 = 128; // max len
    
    ret = ioctl(fd, MEM_CMD1, &usr_msg);
    printf("ioctl: ret=%d\n", ret);

    usr_msg.msg = &buff[0];
    sprintf(buff, "hello,pipe\n");
    ret = ioctl(fd, MEM_CMD2, &usr_msg);
    printf("ioctl: ret=%d\n", ret);

    usr_msg.msg = &buff[0];
    memset(buff, 0, 256);
    ret = ioctl(fd, MEM_CMD3, &usr_msg);
    printf("ioctl: ret=%d rdata=%s\n", ret, buff);
    
    close(fd);
    return 0;
}

#endif

 

上一篇:Android--读取通讯录并添加联系人


下一篇:演示:配置安全的shell属性