高級字符驅動之堵塞與非堵塞IO

/**
  *此實例涉及到線程的掛起與競態,字符IO的堵塞與非堵塞
  */

struct scull_pipe {
    wait_queue_head_t inp, outp;
    char *buffer, *end;
    char *rp, wp;
    //int buffersize;
    int nreaders, nwriters;
    struct fasync_struct *async_queue;
    struct semaphore sem;
    struct cdev cdev;
};


/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 * /inlcude/linux/kernel.h
 *
 */
/*#define container_of(ptr, type, member) ({            \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})
*/

static ssize_t scull_p_read (struct file *filp, char __user *buffer, size_t count, loff_t *f_pos)
{
    /*得到指向結構體scull_pipe的指針*/
    /*
    (void *private_data)private_data指針是file結構體中的成員之一,
    它是跨系統挑用是保存狀態信息的非常有用的資源,這裏我們
    在open階段使用container_of函數得到指向結構體scull_pipe的指針並將private_data指向它
    記住要在release方法中釋放其內存  
    */

    struct scull_pipe *dev = filp->private_data;

    /*使用信號量限制在同一時刻只有一個線程執行*/
    /*若被中斷則返回非零值,若無法撤銷任何用戶可見的修改return -    EINTR*/
    if (down_interruptible(&dev->sem))
        return -ERESTARTSYS;

    while (dev->rp == dev->wp)
    {
        up_interruptible(&dev->sem);

        /*判斷用戶是否設置了非堵塞IO*/
        if (filp->f_flags & O_NONBLOCK)
            return -EAGAIN;

        /*將線程掛起*/
        if (wait_event_interruptible(&dev->inp, dev->rp != dev->wp))
            return -ERESTARTSYS;

        if (down_interruptible(&dev->sem))
            return -ERESTARTSYS;
    }

    /*min函數在Linux內核/include/linux/kernel.h中*/
    if (dev->wp > dev->rp)
        count = min(count, (size_t) (dev->wp - dev->rp));
    else
        count = min(count, (size_t) (dev->end - dev->rp));

    if (copy_to_user(buffer, dev->rp, count))
    {
        up_interruptible(&dev->sem);
        return -EFAULT;
    }

    dev->rp += count;
    if (dev->rp == dev->end)
        dev->rp = dev->buffer

    up_interruptible(&dev->sem);
    wake_up_interruptible(&dev->outp);
    return count;
}

/*個人仿照上方寫的管道寫操作代碼*/
static ssize_t scull_p_write (struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos)
{
    struct scull_pipe *dev = filp->private_data;

    if (down_interruptible(&dev->sem))
        return -ERESTARTSYS;

    /*判斷條件有所不同*/
    while (strlen(dev->buffer) && dev->rp == dev->wp)
    {
        up_interruptible(&dev->sem);

        if (filp->f_flags & O_NONBLOCK)
            return -EAGAIN;

        if (wait_event_interruptible(&dev->outp))
            return -ERESTARTSYS;

        down_interruptible(&dev->sem);
    }

    if (dev->wp > dev->rp)
        count = min(count, (size_t) (dev->end - dev->wp));
    else
        count = min(count, (size_t) (dev->rp - dev->wp - 1));

    if (copy_form_user(dev->wp, buffer, count))
    {
        up_interruptible(&dev->sem);
        return -EFAULT;
    }

    dev->wp += count;
    if (dev->wp == dev->end)
        dev->wp = dev->buffer;

    up_interruptible(&dev->sem);
    wake_up_interruptible(&dev->inp);
    return count;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章