Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1634761
  • 博文数量: 197
  • 博客积分: 10046
  • 博客等级: 上将
  • 技术积分: 1983
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-07 12:36
个人简介

在外企做服务器开发, 目前是项目经理, 管理两个server开发的项目。不做嵌入式好久了。

文章分类
文章存档

2011年(2)

2010年(6)

2009年(18)

2008年(30)

2007年(100)

2006年(41)

分类: LINUX

2007-09-28 12:54:08

文件: chardev_test_waitqueue.rar
大小: 14KB
下载: 下载
文件: chardev_test_wait_event.rar
大小: 14KB
下载: 下载
【kernel进阶练习3】 增加read/write,实现互斥,阻塞等待


代码见附件。把rar换成.c 即可了。

 
【进阶练习2 】 遍历进程链表

注意2.4 和 2.6的不同 ,

原来2.4kernel里面的task_struct 里面有个 struct task_strct *next_task;
在 2.6里面没有了, 变成了 更通用的 struct list_head tasks ;

所以实现起来, 必然有差异才行。


要求: 实现一个函数, 要查询某个进程的pid 。

参考例子:
2.4 kernel :




/*
By process name , you can get task_struct for which wake up ,bob added
*/

int self_find_task_by_name(char *ps_name)
{
        pid_t pid = -1;
        // int counter = 0;



        struct task_struct *p = current->next_task;
        struct task_struct *p_query_head = current ;

        //loop times depends on the number of the process in current system


        while(p != NULL && p->pid != p_query_head->pid)
        {
                if( ! memcmp(p->comm,ps_name,strlen(ps_name)))
                {
                        pid = p->pid;
                        goto p_find;
                }
                p=p->next_task;
                // counter++ ;


        }
        dbg("Can't find the process named %s,you should run it in advance\n",ps_name);
        return -1;

p_find:
        return pid;

}




2.6 kernel:





By process name , you can get task_struct for which wake up ,bob added
*/
int self_find_task_by_name(char *ps_name)
{
        pid_t pid = -1;
        struct list_head *p = NULL;
        struct list_head *head = &current->tasks;

        list_for_each(p,head)
        {
               
#define this_task(p) list_entry(p,struct task_struct, tasks)
               
                struct task_struct *task = NULL;
                task = this_task(p);
                dbg("this process name = %s\n",task->comm);
                if(unlikely(!memcmp(task->comm,ps_name,strlen(ps_name))))
                {
                        pid = task->pid;
                        goto p_find;
                }
        }
        dbg("Can't find the process named %s,you should run it in advance\n",ps_name);
        return -1;

p_find:
        return pid;

}


 
+++++++++++++++++++++++++++++++++
 
 
做个双链表的练习

做个双链表的练习 , struct list_head 在内核中非常重要, 要掌握住他的用法, 参照下面的例子



#define this_job(p) list_entry(p, struct bob_jobs, list)

static __init int chardev_init(void)
{
        
        char *p_name = "smbd";
        struct list_head *p = NULL;
        
        //begin

        struct bob_jobs job1 = {
                .id = 10UL,
                //.list = LIST_HEAD_INIT(list), 因为我们的结构体刚定义,list指针本身就是未知的,需要在list_add()才能对其进行操作,不用没法赋值。

        };
        struct bob_jobs job2 = {
                .id = 20UL,
                //.list = LIST_HEAD_INIT(list), 因为我们的结构体刚定义,list指针本身就是未知的,需要在list_add()才能对其进行操作,不用没法赋值。

        };
        
               
        Major = register_chrdev(0, DEVICE_NAME, &fops);

        if (Major < 0) {
                dbg("Registering the character device failed with %d\n", Major);
                return Major;
        }

        dbg("I was assigned major number %d. To talk to\n", Major);
        dbg("the driver, create a dev file with\n");
        dbg("'mknod /dev/hello c %d 0'.\n", Major);
        dbg("Try various minor numbers. Try to cat and echo to\n");
        dbg("the device file.\n");
        dbg("Remove the device file and module when done.\n");


        //check the self_find_by_name() function

        dbg("will call self_find_by_name() \n");
        dbg("smbd pid=%d\n",self_find_task_by_name("smbd"));
        
        //only debug the functions in list.h

        dbg("only debug the functions in list.h\n");
        
        INIT_LIST_HEAD(&bob_list); //initialize the double list

        list_add(&(job1.list),&bob_list);
        list_add(&(job2.list),&bob_list);
        
        //print

        list_for_each(p,&bob_list)
        {
                struct bob_jobs *job = NULL;
               
                job = this_job(p);
                dbg("id=%lu\n",job->id);
        }

        dbg("will delete the bob_list double list\n");
        while(bob_list.next != &bob_list)
        {
                struct bob_jobs *job = NULL;
               
                p = bob_list.next;
                job = this_job(p);
               
                //delete a entry after header

// dbg("delete a entry after header , id = %lu\n",(this_job(p))->id);

                dbg("delete a entry after header , id = %lu\n",job->id);
                list_del(bob_list.next);
        }
        dbg("delete over \n");
        
        return 0;
}


用wait_event_interruptible()实现的睡眠等待的功能


/* 用信号量来保护临界区, 而且, 一次只能让一个进程管道的数据读走 */
static ssize_t device_read(struct file *filp,    /* see include/linux/fs.h */
                            char *buffer,    /* buffer to fill with data */
                            size_t length,    /* length of the buffer */
                            loff_t *offset)    /* loff_t == long long */
{
    //    Number of bytes actually written to the buffer

//    DECLARE_WAITQUEUE(wait, current);

    //int bytes_read = 0;

    int ret = 0;
    char *read_msg_ptr = msg;
        

    /* 如果msg[0] == '\0',说明无数据可读,就睡眠 */
    dbg("into device_read() function \n");
//    add_wait_queue(&read_wait, &wait);//this is versersaile

//   

//    do {

//        //这些唤醒的进程当中,肯定有一个最先获得信号量

//        down_interruptible(&char_sem); //获取信号量,实现独占

//        __set_current_state(TASK_INTERRUPTIBLE);

//        

//        if (msg[0] != '\0'){ //have data to read

//            ret = 0;

//            break;

//        }

//        

//        if (filp->f_flags & O_NONBLOCK) {

//            dbg("app has set O_NONBLOCK flag \n");

//            ret = -EAGAIN;

//            break;

//        }

//        if (signal_pending(current)) {

//            ret = -ERESTARTSYS;

//            break;

//        }

//        up(&char_sem);

//        schedule();

//    } while (1);

//   

//   

//    set_current_state(TASK_RUNNING);

//    remove_wait_queue(&read_wait, &wait);


//另外一种写法,直接调用wait_event_interruptible() 函数

    if (filp->f_flags & O_NONBLOCK) {
        dbg("app has set O_NONBLOCK \n");
        ret = -EAGAIN;
        return ret;
        }
        
    //直接调用wait_event_interruptible() 函数, 会节省很多代码行数,

    if(wait_event_interruptible(read_wait, msg[0] != '\0'))
        return -ERESTARTSYS;
   

    if (ret == 0) //正确的情况,而不是下面的两种错误情况

    {
        
#if 0 //我写成一个函数了:put_user_string

        while (length && *read_msg_ptr) {
   
            /*
            * The buffer is in the user data segment, not the kernel
            * segment so "*" assignment won't work. We have to use
            * put_user which copies data from the kernel data segment to
            * the user data segment.
            */

            //             kernel ----> user

            put_user(*(read_msg_ptr++), buffer++);
   
            length--;
            bytes_read++;
        }
        /* copy_to_user() 具体怎么用呢? */
        //    copy_to_user(buffer,msg_Ptr,length);


#endif
    //use my function instead of these code

        ret = put_user_string(read_msg_ptr,buffer,length);
        memset(msg,'\0',sizeof(msg)); //彻底清空里面的内容,以此表示pipe的内容只可以读一次,然后就没有了。

        
    }
   
    up(&char_sem);

    return ret;
}



阅读(2747) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~