Linux


モックデバイスドライバ

Makefile

obj-m += mock.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

mock.c

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>

#include "mock.h"

#define MODNAME "mock"
#define MODNUM MOCKNUM

#define INFOPRINT(fmt, ...) printk(KERN_INFO "[%s] %s:%d :: " fmt, MODNAME, __func__, __LINE__, ##__VA_ARGS__)
#define DBGPRINT(fmt, ...) printk(KERN_DEBUG "[%s] %s:%d :: " fmt, MODNAME, __func__, __LINE__, ##__VA_ARGS__)
#define ERRPRINT(fmt, ...) printk(KERN_ERR "[%s] %s:%d :: <ERROR> " fmt, MODNAME, __func__, __LINE__, ##__VA_ARGS__)

static int mock_major;
static struct class *mock_class;

#define MAX_PACKET_NUM 10
typedef struct mock_packet_store_s {
    mock_packet_t packet[MAX_PACKET_NUM];
    unsigned int stored_num;
    unsigned int cur_idx;
} mock_packet_store_t;


typedef struct mock_dev_s {
    struct cdev c_dev;
    dev_t dev;

    mock_packet_store_t store;
    wait_queue_head_t wait_queue;
} mock_dev_t;
static mock_dev_t mock_dev[MODNUM];

typedef enum mock_act_type_e {
    MOCK_ACT_TYPE_EXPECT = 0,
    MOCK_ACT_TYPE_RETURN,
} mock_act_type_t;

static int mock_open(struct inode *inode, struct file *filp)
{
    mock_dev_t *dev;

    INFOPRINT("%s is called\n", __func__);

    dev = container_of(inode->i_cdev, mock_dev_t, c_dev);

    filp->private_data = dev;

    INFOPRINT("minor : %d\n", MINOR(dev->dev));

    return 0;
}

static int mock_release(struct inode *inode, struct file *filp)
{
    mock_dev_t *dev = filp->private_data;

    INFOPRINT("%s is called\n", __func__);

    INFOPRINT("minor : %d\n", MINOR(dev->dev));

    return 0;
}


static ssize_t mock_wait_act(mock_dev_t *mock_dev, mock_act_t act,
                             unsigned char *buf, mock_act_type_t act_type)
{
    mock_packet_store_t *store = &mock_dev->store;
    unsigned char cmp_buf[MOCK_MAX_DATA_SIZE];
    int ret;

    ret = wait_event_interruptible(mock_dev->wait_queue,
                                   store->packet[store->cur_idx].act == act);
    if (ret < 0) {
        ERRPRINT("wait_event_interruptible failed\n");
        return -ERESTARTSYS;
    }

    if (0 < store->packet[store->cur_idx].size) {

        if (act_type == MOCK_ACT_TYPE_EXPECT) {
            copy_from_user(cmp_buf, buf, store->packet[store->cur_idx].size);

            ret = memcmp(store->packet[store->cur_idx].data, buf,
                         store->packet[store->cur_idx].size);
            if (ret != 0) {
                ERRPRINT("unexpected value\n");
                return -EINVAL;
            }
        }
        else {
            copy_to_user(buf, store->packet[store->cur_idx].data,
                         store->packet[store->cur_idx].size);
        }

    }

    store->cur_idx++;

    wake_up_interruptible(&mock_dev->wait_queue);

    return 0;
}


static ssize_t mock_read(struct file *filp, char *buf, size_t count,
                          loff_t *offset)
{
    mock_dev_t *dev = filp->private_data;
    ssize_t size_ret;

    INFOPRINT("%s is called\n", __func__);

    INFOPRINT("minor : %d\n", MINOR(dev->dev));


    size_ret = mock_wait_act(dev, MOCK_ACT_RETURN_READ,
                             (unsigned char *)buf, MOCK_ACT_TYPE_RETURN);


    return size_ret;
}

static ssize_t mock_write(struct file *filp, const char *buf, size_t count,
                           loff_t *offset)
{
    mock_dev_t *dev = filp->private_data;

    INFOPRINT("%s is called\n", __func__);

    INFOPRINT("minor : %d\n", MINOR(dev->dev));

    return 0;
}

static void mock_ioctl_clear(mock_dev_t *mock_dev)
{
    mock_dev->store.stored_num = 0;
    mock_dev->store.cur_idx = 0;

    return;
}

static void mock_ioctl_set_act(mock_dev_t *mock_dev, unsigned long arg)
{
    mock_packet_t packet;
    mock_packet_store_t *store = &mock_dev->store;

    copy_from_user(&packet, (void *)arg, sizeof(mock_packet_t));

    {
        int i;
        DBGPRINT("act : %d\n", packet.act);
        DBGPRINT("ret : %d\n", packet.ret_val);
        for (i=0; i<packet.size; i++) {
            DBGPRINT("data[%d] : %u\n", i, packet.data[i]);
        }
    }
    

    store->packet[store->stored_num] = packet;
    store->stored_num++;

    return;
}

static long mock_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    mock_dev_t *dev = filp->private_data;

    INFOPRINT("%s is called\n", __func__);

    INFOPRINT("minor : %d\n", MINOR(dev->dev));

    switch(cmd) {
    case MOCK_CLEAR:
        INFOPRINT("MOCK_CLEAR\n");
        mock_ioctl_clear(dev);
        break;

    case MOCK_SET_ACT:
        INFOPRINT("MOCK_SET_ACT\n");
        mock_ioctl_set_act(dev, arg);
        break;

    default:
        ERRPRINT("unknown cmd (cmd=%u)\n", cmd);
        return -EINVAL;
    }

    return 0;
}

static struct file_operations mock_fops ={
    .owner   = THIS_MODULE,
    .open    = mock_open,
    .release = mock_release,
    .read    = mock_read,
    .write   = mock_write,
    .unlocked_ioctl   = mock_ioctl,
};

static int __init mock_init(void)
{
    struct device *dev;
    dev_t dev_id;
    int cdev_init_idx = -1;
    int device_create_idx = -1;
    int i;
    int ret;
    int err;

    ret = alloc_chrdev_region(&dev_id, 0, MODNUM, MODNAME);
    if (ret < 0) {
        ERRPRINT("alloc_chrdev_region failed (ret=%d)\n", ret);
        return ret;
    }

    mock_major = MAJOR(dev_id);


    for (i=0; i<MODNUM; i++) {
        cdev_init(&mock_dev[i].c_dev, &mock_fops);
        ret = cdev_add(&mock_dev[i].c_dev, dev_id, i+1);
        if (ret < 0) {
            ERRPRINT("cdev_add (%d) failed (ret=%d)\n", i, ret);
            err = ret;
            goto ERR_CDEV_DEL;
        }
        mock_dev[i].dev = MKDEV(mock_major, i);
        init_waitqueue_head(&mock_dev[i].wait_queue);
        cdev_init_idx = i;
    }


    mock_class = class_create(THIS_MODULE, MODNAME);
    if (IS_ERR(mock_class)) {
        ERRPRINT("class_create failed (ret=%d)\n", ret);
        err = PTR_ERR(mock_class);
        goto ERR_CDEV_DEL;
    }

    for (i=0; i<MODNUM; i++) {
        dev_id = MKDEV(mock_major, i);
        dev = device_create(mock_class, NULL, dev_id, NULL, MODNAME"%d", i);
        if (IS_ERR(dev)) {
            ERRPRINT("device_create (%d) failed (ret=%d)\n", i, ret);
            err = PTR_ERR(mock_dev);
            goto ERR_DEVICE_DESTROY;
        }

        device_create_idx = i;
    }


    INFOPRINT("%s is loaded\n", MODNAME);

    return 0;


ERR_DEVICE_DESTROY:
    for (i=0; i<device_create_idx+1; i++) {
        dev_id = MKDEV(mock_major, i);
        device_destroy(mock_class, dev_id);
    }

    class_destroy(mock_class);

ERR_CDEV_DEL:
    for (i=0; i<cdev_init_idx+1; i++) {
        cdev_del(&mock_dev[i].c_dev);
    }

    unregister_chrdev_region(dev_id, MODNUM);

    return err;
}

static void __exit mock_exit(void)
{
    int i;
    dev_t dev_id;

    for (i=0; i<MODNUM; i++) {
        dev_id = MKDEV(mock_major, i);
        device_destroy(mock_class, dev_id);
    }
    class_destroy(mock_class);
    for (i=0; i<MODNUM; i++) {
        cdev_del(&mock_dev[i].c_dev);
    }
    dev_id = MKDEV(mock_major, 0);
    unregister_chrdev_region(dev_id, MODNUM);

    INFOPRINT("%s is unloaded\n", MODNAME);
}

module_init(mock_init);
module_exit(mock_exit);

MODULE_AUTHOR("Hiroshi Sakaida");
MODULE_DESCRIPTION("Mock Module");
MODULE_LICENSE("GPL v2");

mock.h

#ifndef _MOCK_H_
#define _MOCK_H_

#ifdef __cplusplus
extern "C" {
#endif


#include <linux/ioctl.h>


#define MOCKNUM 3
#define MOCKDEV_BASE "/dev/mock"


typedef enum mock_act_e {
  MOCK_ACT_EXPECT_WRITE = 0,
  MOCK_ACT_RETURN_READ,
} mock_act_t;

#define MOCK_MAX_DATA_SIZE 256

typedef struct mock_packet_s {
  mock_act_t act;
  int ret_val;
  unsigned char data[MOCK_MAX_DATA_SIZE];
  size_t size;
} mock_packet_t;



#define MOCKDEV_MAGIC 0xAE

#define MOCK_CLEAR     _IOC(_IOC_NONE,  MOCKDEV_MAGIC, 0, 0)
#define MOCK_SET_ACT   _IOC(_IOC_WRITE, MOCKDEV_MAGIC, 1, sizeof(mock_packet_t))


#ifdef __cplusplus
}
#endif

#endif /* _MOCK_H_ */

main.c

#include <stdio.h>
/* #include <sys/stat.h> */
#include <fcntl.h>
#include <assert.h>

#include "mock.h"


#define DEVNUM 3
static int fd[DEVNUM];

#define PATHLEN 128


typedef int (*test_func)(void);

#define TEST_NUM 2
static test_func tests[TEST_NUM];


static void get_dev_path(char path[], size_t pathlen, int idx)
{
    snprintf(path, pathlen, "%s%d", MOCKDEV_BASE, idx);
    printf("%s\n", path);
    return;
}

static void test_setup(void)
{
    int i;
    char path[PATHLEN];
    int ret;

    for (i=0; i<DEVNUM; i++) {
        get_dev_path(path, PATHLEN, i);
        fd[i] = open(path, O_RDWR);
        assert(0 <= fd[i]);

        ret = ioctl(fd[i], MOCK_CLEAR, NULL);
        assert(0 <= ret);
    }

    return;
}

static int test_exit(void)
{
    int i;
 
    for (i=0; i<DEVNUM; i++) {
        close(fd[i]);
    }

    return 0;
}


static int open_close_test(void)
{

    return 0;
}


static int read_test(void)
{
    mock_packet_t packet;
    unsigned char buf[256];
    int idx = 0;
    int i, j;
    int ret;

    packet.data[idx++] = 7;
    packet.data[idx++] = 8;
    packet.data[idx++] = 9;
    packet.size = idx;

    for (i=0; i<DEVNUM; i++) {
        ret = ioctl(fd[i], MOCK_EXPECT_READ, &packet);
        assert(0 <= ret);

        ret = ioctl(fd[i], MOCK_EXPECT_READ, &packet);
        assert(0 <= ret);

        ret = read(fd[i], buf, 256);
        assert(ret == idx);

        for (j=0; j<idx; j++) {
            printf("buf[%d] : %u\n", j, buf[j]);
            assert(buf[j] == packet.data[j]);
        }

        ret = read(fd[i], buf, 256);
        assert(ret == idx);

        for (j=0; j<idx; j++) {
            printf("buf[%d] : %u\n", j, buf[j]);
            assert(buf[j] == packet.data[j]);
        }
    }

    return 0;
}


static int exec_tests(void)
{
    int i;
    int test_ret = 0;
    int exit_ret = 0;
    int self_ret = 0;

    for (i = 0; i<TEST_NUM; i++) {
        printf("-----------------\n");
        printf(" TEST [%d]\n", i);
        printf("-----------------\n\n");
        test_setup();
        test_ret = tests[i]();
        exit_ret = test_exit();
        if (test_ret < 0 || exit_ret < 0) {
            printf("Failure\n");
            self_ret = -1;
        }
        else {
            printf("Success\n");
        }
    }

    return self_ret;
}


int main(int argc, char *argv[])
{
    int idx = 0;
    int ret;

    tests[idx++] = open_close_test;
    tests[idx++] = read_test;


    ret = exec_tests();
    printf("\n\n- - - - - - - - - - -\n");
    if (ret < 0) {
        printf("Tests Failed\n");
    }
    else {
        printf("Tests Succeeded\n");
    }

    return 0;
}

プロセス間mutex/cond

共通ヘッダ com.h

#ifndef _COM_H_
#define _COM_H_

#include <pthread.h>

#define SHARE_FILE "/tmp/libcmd"

#define CMD_MAX_LEN 256

typedef struct _shared_data_t {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    char cmd[CMD_MAX_LEN];
    unsigned int count;
} shared_data_t;

#endif /* _COM_H_ */

送信側

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/mman.h>

#include "com.h"


int main(int argc, char *argv[])
{
    int fd;
    char *name;
    int id;
    char cmd[CMD_MAX_LEN];
    int memsize = sizeof(shared_data_t);
    shared_data_t *shared_data;


    if (argc < 3) {
        fprintf(stderr, "cmd [\"name\"] [id]\n");
        return 1;
    }

    fd = open(SHARE_FILE, O_RDWR);
    if (fd < 0) {
        perror("open failed");
        return 1;
    }

    shared_data = (shared_data_t *)mmap(NULL, memsize,
                                      PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (shared_data == NULL) {
        perror("mmap failed");
        close(fd);
        return 1;
    }

    name = argv[1];
    id = atoi(argv[2]);
    
    printf("execute %s %d\n", name, id);

    pthread_mutex_lock(&shared_data->mutex);

    snprintf(shared_data->cmd, CMD_MAX_LEN, "%s %d", name, id);

    shared_data->count += 1;

    pthread_cond_broadcast(&shared_data->cond);

    pthread_mutex_unlock(&shared_data->mutex);

    close(fd);
}

受信側

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/mman.h>

#include "com.h"


int main(int argc, char *argv[])
{
    int fd;
    char *name;
    int id;
    char cmd[CMD_MAX_LEN];
    int memsize = sizeof(shared_data_t);
    shared_data_t *shared_data;
    struct stat st;
    int init_flg = 0;
    unsigned int count;


    if (stat(SHARE_FILE, &st) < 0) {
        printf("Create share file...\n");
        fd = open(SHARE_FILE, O_RDWR | O_CREAT, S_IRWXU);
        if (fd < 0) {
            perror("open failed");
            return 1;
        }

        if (ftruncate(fd, memsize) < 0) {
            perror("ftruncate failed");
            close(fd);
            return 1;
        }

        init_flg = 1;
    }
    else {
        fd = open(SHARE_FILE, O_RDWR);
        if (fd < 0) {
            perror("open failed");
            return 1;
        }
    }

    shared_data = (shared_data_t *)mmap(NULL, memsize,
                                        PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (shared_data == NULL) {
        perror("mmap failed");
        close(fd);
        return 1;
    }

    if (init_flg) {
        pthread_mutex_init(&shared_data->mutex, NULL);
        pthread_cond_init(&shared_data->cond, NULL);
        shared_data->count = 0;
    }

    pthread_mutex_lock(&shared_data->mutex);

    count = shared_data->count;

    while (count == shared_data->count) {
        pthread_cond_wait(&shared_data->cond, &shared_data->mutex);
    }

    printf("receive %s (count=%d)\n", shared_data->cmd, shared_data->count);

    pthread_mutex_unlock(&shared_data->mutex);

    close(fd);
}

最新の20件

2021-03-31 2020-06-09 2020-05-30 2019-12-02 2018-10-18 2018-07-05 2018-01-11 2015-12-07
  • Linux
2015-08-03 2015-07-20 2012-07-19 2012-06-30 2012-06-23 2012-01-25 2011-11-09 2011-11-08 2011-10-02

今日の8件

  • counter: 230
  • today: 1
  • yesterday: 0
  • online: 1