Chinaunix首页 | 论坛 | 博客
  • 博客访问: 116911
  • 博文数量: 16
  • 博客积分: 2044
  • 博客等级: 中士
  • 技术积分: 165
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-15 22:15
文章分类

全部博文(16)

文章存档

2012年(1)

2011年(9)

2010年(6)

分类:

2011-02-16 15:17:19

NFS文件系统采用的是RPC技术,不同的文件操作在底层最终都会通过不同的RPC调用来实现。但是这些RPC任务生成以后,内核是如何调度发送到远程主机呢?在参考了网络上的一些资料和内核中的代码,将其总结一下。

为了高效的调度各个RPC请求,Linux的PRC调度实际上是一个事件驱动模型。C/S结构,大多使用多进程服务模型,这种模型的优点是编程简单,因为操作系统都是基于进程调度的,可以直接使用操作系统的接口。缺点是不适用于大规模的服务。服务进程或者线程的数目越多,用于切换调度的开销就越多,一旦进程或者线程的个数超过一定值,系统就会变的响应异常缓慢。而事件驱动模型正好相反,由于缺乏通用的事件调度接口,只有全部由自己实现,但是不管遇到多少数量的服务,都不会在切换上花费太多开销。

为了没有切换开销,简单点当然是完全由一个进程单干。更高级的做法是每个处理器一个进程,同时跑,多彻底。内核里面的工作队列机制实际上就是这样干的,因此RPC对于异步处理的调度就是使用的工作队列的接口。

rpc在一个函数中处理了同步和异步两种情况。事实上,如果是同步情况,则会在该函数中睡眠,直到醒来的条件满足。如果是异步情况,则处理完后会直接返回,任务的睡眠和后续启动由专门的异步机制,也就是工作队列来完成

的。

在linux内核中RPC任务调度的代码位于net\sunrpc\sched.c中,具体的函数是_rpc_execute().

函数名称:static void __rpc_execute(struct rpc_task *task)这是一个RPC的调度器,更准确的说,是采用有限状态机。

for(;;)

{

 if (task->tk_callback)  save_callback(task)//当前任务是否有回调函数,有则处理

if (!RPC_IS_QUEUED(task))  task->tk_action(task)//处理当前任务

if (task_is_async)

out_of_line_wait_on_bit(&task->tk_runstate,RPC_TASK_QUEUED, rpc_wait_bit_killable,TASK_KILLABLE);//异步任务处理,则返回,同步任务则进入睡眠状态。

rpc_set_running(task)

//一些其他的处理。

}

rpc_release_task(task)//处理完成后清除相关的资源。

该函数被rpc_execute和 rpc_async_schedule函数调用。最终rpc_async_schedule通过rpc_make_runable函数被rpc_execute函数调用。具体代码为:

void rpc_execute(struct rpc_task *task)

{

rpc_set_active(task);

rpc_make_runnable(task);

if (!RPC_IS_ASYNC(task))

__rpc_execute(task);

}

通过调用rpc_execute函数来实现对RPC任务的调度。这个函数一般是被递归的调用。

这些关于调度的函数是通过工作队列机制来实现的。具体是在rpc_make_runable函数中调用的。这里采用了一个叫做rpciod_workqueue的工作队列来完成。

工作队列的介绍

1。默认情况下内核只有名字为event的一类工作队列,这一类工作队列在每个cpu上都有一个内核线程。RPC新建了一类,取名为rpciod工作队列。
    wq = create_workqueue("rpciod");
    if (wq == NULL) {
        // errorr process
    }
    rpciod_workqueue = wq;

2。随后没个rpc任务初始化时候都会有
    task->tk_workqueue = rpciod_workqueue;

3。当一个task启动时候,如果是异步的,便启动函数rpc_async_schedule()作为异步rpc请求的处理函数。
        INIT_WORK(&task->u.tk_work, rpc_async_schedule, (void *)task);
        status = queue_work(task->tk_workqueue, &task->u.tk_work);


参考:linux rpc结构的一种事件驱动的状态处理

      linux内核2.6.37\net\sunrpc\sched.c


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