随想:看了Posix的timer后而发的一些感慨

昨天研究了linux的用户timer,其实不是linux的用户timer而是posix规定的一个timer接口,这个接口规定了一些规 则,linux具体在内核或用户空间来实现而不一定非要在内核空间实现,posix标准只是一些接口规范,具体怎么实现就不管了,典型的在 linux2.6内核之前,内核并没有实现posix规定的异步io,而linux承诺实现posix,那么怎么办呢?只好在用户空间实现,做成一个库,这个库封装了异步io的实现,实际上就是用户使用异步io的时候,库负责fork出来一个新的进程(或者线程)来协助完成异步io,这个新fork出来的 进程实际在进行同步io,但是调用库的用户进程却可以注册一个完成回调后直接返回或者不注册完成回调而直接返回,在以后的时间查询完成状态,待库新 fork出的进程完成io的时候发信号给用户进程或者置位一些标志以等待用户查询,这个实现一点不违背posix的语义,我们就说linux的异步io库 实现了posix的异步io标准接口。当然这是一种方式,内核设计的好坏直接关系到这种用户库实现posix标准的难易程度,好在linux内核的低耦合 性,库实现就简单多了。另一种更好更有效率的方式就是直接在内核实现posix,还是以异步io为例,2.6以上的内核在内核实现了异步io,实际是由工 作队列实现的,这样我们同样说linux实现了posix的异步io。由此看来posix根本不管你的实现方式,只要符合接口规范就成。
谈到timer,很多了解linux内核的人就会想到内核中的timer_list,时钟中断中检测到到期的timer们,然后依次执行这些timer们 的回调函数,这是其一,还有就是linux的信号机制,它会发送信号到任何进程,只要进程不阻塞该信号,用户注册的信号处理函数就会捕获发送给该进程的信号,这是其二,这两种简单的机制使得在内核实现posix的timer很容易。在linux内核的设计上来说也将内核实现posix的timer简单化 了,linux内核的数据结构和管理实体都是一些低耦合的松散对象,各司其职,实现了unix的kiss原则,只做一件事并把它做好,这样组合这些小对象 的余地就会更大,它们没有那种藕断丝连,牵一发而动全身的拙劣特性,简单就是好。不只是内核,你可以看看/bin或/sbin的目录,很少有巨大的程序, 都是一些小程序,这些小程序的协作就可以完成强大的功能,这归功于linux的设计粒度,本质上也是kiss原则,不会牵一发而动全身在稳定性的意义上就是如果一个协作者出了问题,那么不会导致连锁反应。另外小对象也有利于扩展,扩展的时候无非就是三件事,一个是添,一个是改,另一个是重组,linux都 是小对象组成,添加一个或修改一个很简单,大多数时候不用添加,也不需要修改,只需要重组就可以了,类比一下细胞学的遗传和变异就会得到很大启发,无非就是线嘌呤,鸟嘌呤,胞嘧啶,胸腺嘧啶这四种“小对象”组成了美女,帅哥,毛泽东,希特勒...当然前提是你的“小对象”必须设计的足够好,足够自洽,足够正交,DNA不去讨论,那是上帝设计的,一定没错,就算错了我也不敢说,还是仔细品一下linux内核吧,参考我前面的文章,list_head和 kobject就是两个杰作。试想一些大结构组成的系统,比如人体是由很大的结构组成,那么生一个孩子的代价就太大了,基因复制的时候就不单单是双链解旋了,可能就不是仅仅基因复制了,为何基因可以决定一切,再想想蛋白质,组成我们就是蛋白质,而蛋白质也不是一个大对象,它也是一些被称为氨基酸的小对象组 合而成的,而哪些氨基酸具体合成什么样的蛋白质是由基因决定的,而基因是那四个小对象决定的,四个小对象洗牌重组后的输出给了基因的输入,进一步又输出给了转运核糖核酸即tRNA,tRNA的输出给了氨基酸的输入,最终氨基酸的输出就是最后的蛋白质。然后先看看linux内核的数据结构和函数,其本质也是 协作完成创建,看看sys_fork是不是和合成蛋白质有些类似,再看看用户程序:ps -aux|grep mypro是不是也有些味道。既然都能和蛋白质合成类比了,那么《黑客帝国》里的场景可能要首先在linux或unix上成为现实了,linux和 unix真的很恐怖
简单就是美,简单又纯真则更美,linux做到了。
瞎扯完了,来看看posix的timer吧,内核实现在:/kernel/posix-timers.c中,timer_create就是:
asmlinkage long
559 sys_timer_create(clockid_t which_clock,
                  struct sigevent __user *timer_event_spec,
                  timer_t __user * created_timer_id)
{
         int error = 0;
         struct k_itimer *new_timer = NULL;
         int new_timer_id;
         struct task_struct *process = NULL;
         unsigned long flags;
         sigevent_t event;
         int it_id_set = IT_ID_NOT_SET;
         if ((unsigned) which_clock >= MAX_CLOCKS || !posix_clocks[which_clock].res)
                 return -EINVAL;
         new_timer = alloc_posix_timer();
         if (unlikely(!new_timer))
                 return -EAGAIN;
         spin_lock_init(&new_timer->it_lock);
  retry:
         if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) {
                 error = -EAGAIN;
                 goto out;
         }
         spin_lock_irq(&idr_lock);
         error = idr_get_new(&posix_timers_id, (void *) new_timer, &new_timer_id);
         spin_unlock_irq(&idr_lock);
         if (error == -EAGAIN)
                 goto retry;
         else if (error) {
                 error = -EAGAIN;
                 goto out;
         }
         it_id_set = IT_ID_SET;
         new_timer->it_id = (timer_t) new_timer_id;
         new_timer->it_clock = which_clock;
         new_timer->it_incr = 0;
         new_timer->it_overrun = -1;
         init_timer(&new_timer->it_timer);
         new_timer->it_timer.expires = 0;
         new_timer->it_timer.data = (unsigned long) new_timer;
         new_timer->it_timer.function = posix_timer_fn;    //定时器到期以后要调用的定时器回调函数,该函数就是往用户进程发送信号,顺便将一个siginfo作为参数提供给用户的信号处理函数,该siginfo里包含了用户当初创建posix的timer的时候置入的信息,比如用户参数
         set_timer_inactive(new_timer);
         if (copy_to_user(created_timer_id,
                          &new_timer_id, sizeof (new_timer_id))) {
                 error = -EFAULT;
                 goto out;
         }
         if (timer_event_spec) {  //这个结构要拷贝到内核,最终提供某些用户设置的字段作为一个siginfo给用户的信号处理函数
                 if (copy_from_user(&event, timer_event_spec, sizeof (event))) {
                         error = -EFAULT;
                         goto out;
                 }
                 new_timer->it_sigev_notify = event.sigev_notify;
                 new_timer->it_sigev_signo = event.sigev_signo;
                 new_timer->it_sigev_value = event.sigev_value;    //将用户参数传入,实现了回调函数传参
                 read_lock(&tasklist_lock);
                 if ((process = good_sigevent(&event))) {
                         spin_lock_irqsave(&process->sighand->siglock, flags);
                         if (!(process->flags & PF_EXITING)) {
                                 new_timer->it_process = process;
                                 list_add(&new_timer->list,
                                          &process->signal->posix_timers);
                                 spin_unlock_irqrestore(&process->sighand->siglock, flags);
                                 if (new_timer->it_sigev_notify == (SIGEV_SIGNAL|SIGEV_THREAD_ID))
                                         get_task_struct(process);
                         } else {
                                 spin_unlock_irqrestore(&process->sighand->siglock, flags);
                                 process = NULL;
                         }
                 }
                 read_unlock(&tasklist_lock);
                 if (!process) {
                         error = -EINVAL;
                         goto out;
                 }
         } else {
                 new_timer->it_sigev_notify = SIGEV_SIGNAL;
                 new_timer->it_sigev_signo = SIGALRM;
                 new_timer->it_sigev_value.sival_int = new_timer->it_id;
                 process = current->group_leader;
                 spin_lock_irqsave(&process->sighand->siglock, flags);
                 new_timer->it_process = process;
                 list_add(&new_timer->list, &process->signal->posix_timers);
                 spin_unlock_irqrestore(&process->sighand->siglock, flags);
         }
out:
         if (error)
                 release_posix_timer(new_timer, it_id_set);
         return error;
}
通 过查看源代码我们发现,posix的timer是个结构,该结构内包含了一个内核通用的timer_list结构,用OO的语言可以说该timer继承了 内核的通用timer,用非OO的语言可以说posix的timer是在内核通用timer的基础上实现的,最底层的实现还是timer_list,而且 timer_list根本没有向上依赖posix,可以说内核仅仅提供了一个正交的最小集,既然是最小集当然是最少集了,既然是最少集当然就简单了,既然 简单当然就不容易出错,好管理了,用户和驱动可以自由在这个正交最小集上发挥,重组这些小对象,实现强大的功能。

原文链接: https://blog.csdn.net/dog250/article/details/5303633

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    随想:看了Posix的timer后而发的一些感慨

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/410027

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午11:46
下一篇 2023年4月26日 上午11:46

相关推荐