当前位置: 首页 > news >正文

国务院网站建设标准/友情链接怎么购买

国务院网站建设标准,友情链接怎么购买,南通通州区网站制作,谷歌镜像网站怎么做用户空间应用中创建一个Timer(alarm/setitimer/POSIX Timer等等),然后程序继续执行; 内核进入创建/设置Timer系统调用,开始计时,在超时后通过何种方式通知用户空间; 用户空间又是如何执行回调函数的。 下面就着重这个流…

用户空间应用中创建一个Timer(alarm/setitimer/POSIX Timer等等),然后程序继续执行;

内核进入创建/设置Timer系统调用,开始计时,在超时后通过何种方式通知用户空间;

用户空间又是如何执行回调函数的。

下面就着重这个流程,梳理一下Timer周期中用户空间和内核空间涉及到的相关模块。

 1. 总体框架

关注的Timer(alarm/setitimer/POSIX Timer),都在libc/librt/libphtread中定义。librt是POSIX.1b Realtime扩展的实现,这其中就包括POSIX Timer。

其中alarm/setitimer都调用libc,POSIX Timer调用librt/libpthread。

总体框架如下:

 

应用调用库通过系统调用创建Timer,同时自身注册信号处理函数。

库提供通用接口,转换成系统调用。

内核Timer相关系统调用(setitimer/timer_create),通过hrtimer创建相应的定时器,在超时后调用hrtimer超时函数发送signal给用户空间进程。

用户空间进程在收到信号之后,执行对应的信号处理函数。

至此,Timer一个闭环完成。

下面分alarm/setitimer和POSIX Timer两种类型的Timer,来介绍其流程。

2. alarm/setitimer流程

 linux/common/alarm.c中实现了alarm,可以看到和setitimer相同的接口。

#ifdef __NR_alarm
_syscall1(unsigned int, alarm, unsigned int, seconds)
#else
#include <sys/time.h>unsigned int alarm(unsigned int seconds)
{
...if (setitimer(ITIMER_REAL, &new, &old) < 0) {return 0;}
...
}
#endif

 

即使定义了alarm系统调用,在内核中alarm和setitimer也是调用相同的do_setitimer。所以这两个API在内核的实现是一致的。

SYSCALL_DEFINE1(alarm, unsigned int, seconds)
{return alarm_setitimer(seconds);
}unsigned int alarm_setitimer(unsigned int seconds)
{
...do_setitimer(ITIMER_REAL, &it_new, &it_old);
...
}SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,struct itimerval __user *, ovalue)
{
...
error
= do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL); ...
}

 

所以研究do_setitimer就可以分析这两个API的内核实现。

int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
...switch (which) {case ITIMER_REAL:
again:spin_lock_irq(&tsk->sighand->siglock);timer = &tsk->signal->real_timer;---------------------------------这里是task_struct结构体中的real_timer这个hrtimer。所以alarm/setitimer一个进程/线程空间中只能存在一个。if (ovalue) {ovalue->it_value = itimer_get_remtime(timer);ovalue->it_interval= ktime_to_timeval(tsk->signal->it_real_incr);}/* We are sharing ->siglock with it_real_fn() */if (hrtimer_try_to_cancel(timer) < 0) {spin_unlock_irq(&tsk->sighand->siglock);goto again;}expires = timeval_to_ktime(value->it_value);if (expires.tv64 != 0) {tsk->signal->it_real_incr =timeval_to_ktime(value->it_interval);hrtimer_start(timer, expires, HRTIMER_MODE_REL);--------------启动alarm/setitimer对应的hrtimer。} elsetsk->signal->it_real_incr.tv64 = 0;trace_itimer_state(ITIMER_REAL, value, 0);spin_unlock_irq(&tsk->sighand->siglock);break;
...}return 0;
}

 

那么real_timer这个hrtimer的处理函数在何时初始化的呢?

可以看出在进程创建的时候,已经初始化了real_timer。对应的超时函数是it_real_fn,发送SIGALRM信号给对应的进程。然后用户空间执行SIGALRM处理函数。

do_fork-->copy_process-->copy_signal-->static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
{
...hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);--------初始化real_timer定时器。sig->real_timer.function = it_real_fn;
...
}/** The timer is automagically restarted, when interval != 0*/
enum hrtimer_restart it_real_fn(struct hrtimer *timer)
{struct signal_struct *sig =container_of(timer, struct signal_struct, real_timer);trace_itimer_expire(ITIMER_REAL, sig->leader_pid, 0);kill_pid_info(SIGALRM, SEND_SIG_PRIV, sig->leader_pid);--------------------发送SIGALRM信号。return HRTIMER_NORESTART;
}

 

3. POSIX Timer流程

POSIX Timer在libpthread\nptl\sysdeps\unix\sysv\linux\timer_create.c中创建。

int
timer_create (clockid_t clock_id,struct sigevent *evp,timer_t *timerid)
{
# undef timer_create
# ifndef __ASSUME_POSIX_TIMERSif  (__no_posix_timers >= 0)
# endif{
...kernel_timer_t ktimerid;int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp,-------------通过timer_create系统调用创建Timer。&ktimerid);
...}else{
# ifndef __ASSUME_POSIX_TIMERS
...if (__no_posix_timers > 0)
# endif{/* Create the helper thread.  */pthread_once (&__helper_once, __start_helper_thread);----------------------单独创建线程来处理,一次初始化。if (__helper_tid == 0){/* No resources to start the helper thread.  */__set_errno (EAGAIN);return -1;}
...res = INTERNAL_SYSCALL (timer_create, err, 3,------------------------------通过timer_create系统调用来创建Timer。syscall_clockid, &sev, &newp->ktimerid);
...}}}# ifndef __ASSUME_POSIX_TIMERS/* Compatibility code.  */return compat_timer_create (clock_id, evp, timerid);
# endif
}

__start_helper_thread-->
timer_helper_thread-->
timer_sigev_thread-----------------------------------------------------------此线程在定时器超时后,才会创建。
thrfunc------------------------------------------------------------------调用用户提供的超时回调函数。

 

再来看看内核中的实现,这里主要看common_timer_create和alarm_timer_create两种类型。

SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,struct sigevent __user *, timer_event_spec,timer_t __user *, created_timer_id)
{
...
if (timer_event_spec) {if (copy_from_user(&event, timer_event_spec, sizeof (event))) {error = -EFAULT;goto out;}rcu_read_lock();new_timer->it_pid = get_pid(good_sigevent(&event));------------如果用户提供了sigevent,获取pid。rcu_read_unlock();if (!new_timer->it_pid) {error = -EINVAL;goto out;}} else {memset(&event.sigev_value, 0, sizeof(event.sigev_value));event.sigev_notify = SIGEV_SIGNAL;event.sigev_signo = SIGALRM;event.sigev_value.sival_int = new_timer->it_id;new_timer->it_pid = get_pid(task_tgid(current));--------------如果没有提供sigevent,使用默认的SIGALRM。}new_timer->it_sigev_notify = event.sigev_notify;new_timer->sigq->info.si_signo = event.sigev_signo;new_timer->sigq->info.si_value = event.sigev_value;new_timer->sigq->info.si_tid = new_timer->it_id;new_timer->sigq->info.si_code = SI_TIMER;if (copy_to_user(created_timer_id,--------------------------------返回timer_id给用户空间&new_timer_id, sizeof (new_timer_id))) {error = -EFAULT;goto out;}error = kc->timer_create(new_timer);-----------------------------------------调用common_timer_create或者alarm_timer_create创建定时器if (error)goto out; ...
}
static int common_timer_create(struct k_itimer *new_timer) {hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0);-------------初始化hrtimerreturn 0; }

 

那么超时函数在哪里设置的呢?

static int
common_timer_set(struct k_itimer *timr, int flags,struct itimerspec *new_setting, struct itimerspec *old_setting)
{
...
mode
= flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL;hrtimer_init(&timr->it.real.timer, timr->it_clock, mode);-------------------重新初始化hrtimertimr->it.real.timer.function = posix_timer_fn;------------------------------hrtimer回调函数hrtimer_set_expires(timer, timespec_to_ktime(new_setting->it_value)); ... }

 

在回调函数中,进行了超时处理。

static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
{
...if (posix_timer_event(timr, si_private)) {----------------------------------发送信号
...}}
...
}int posix_timer_event(struct k_itimer *timr, int si_private)
{
...timr->sigq->info.si_sys_private = si_private;rcu_read_lock();task = pid_task(timr->it_pid, PIDTYPE_PID);-------------------------------根据pid获取task实体if (task) {shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID);ret = send_sigqueue(timr->sigq, task, shared);------------------------将当前信号队列发送到对应的用户空间对应的task,进程在收到信号后进行相应处理}rcu_read_unlock();/* If we failed to send the signal the timer stops. */return ret > 0;
}

 

那么如果是Alarm类型的Timer,情况如何呢?

static int alarm_timer_create(struct k_itimer *new_timer)
{
...alarm_init(&new_timer->it.alarm.alarmtimer, type, alarm_handle_timer);-----------初始化alarmtimer,回调函数是alarm_handle_timer
...
}static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,ktime_t now)
{
...if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) {if (posix_timer_event(ptr, 0) != 0)------------------------------------------和其他POSIX Timer一样发送signal信号ptr->it_overrun++;}
...
}static int alarm_timer_set(struct k_itimer *timr, int flags,struct itimerspec *new_setting,struct itimerspec *old_setting)
{
...alarm_start(&timr->it.alarm.alarmtimer, exp);-------------------------------------启动AlarmTimer
...
}

 4. 总结

所以无论是alarm/setitimer,还是POSIX Timer都是通过发送signal来通知用户应用。只是用户空间处理消息的方式有所不同。

由于Timer经过库的封装,不光要看内核,还需要研究库对API进行了何种封装。才能更好的了解其行为。

也由于库的种类(lig/glib/ulib等)和版本千差万别,所以也需要引起重视。

 

一个关于libpthread引起的POSIX Timer执行异常情况。

描述:在一个进程中创建三个SIGEV_THREAD类型POSIX Timer,但是超时只执行一个回调函数。其他两个没有被调用。

问题分析:SIGCANCEL这个信号导致,timer_create创建helper thread失败。Timer超时后,回调函数也不会被执行。

解决方法:

void
attribute_hidden
__start_helper_thread (void)
{
...sigset_t ss;sigset_t oss;sigfillset (&ss);/*__sigaddset (&ss, SIGCANCEL); - already done by sigfillset */
  __sigaddset (&ss, SIGCANCEL);--------------------------------修改方法
...
}

 

http://www.lbrq.cn/news/1331659.html

相关文章:

  • 网站后台编辑内容不显示/windows优化工具
  • 桂电做网站的毕设容易过嘛/推广引流方法有哪些推广方法
  • web后端是做什么的/北京网站优化方式
  • 做seo网站优化价格/360竞价推广登录入口
  • 安庆网站建设工作室/网络卖货平台有哪些
  • ui中国网站/优化深圳seo
  • java企业门户网站开发教程/山东16市最新疫情
  • 佛山专业网站设计/网络营销是什么专业类别
  • 北京常用网站/广州seo优化费用
  • 北京门户网站制作费用/百度seo公司哪家好一点
  • 有什么做衣服的网站吗/历下区百度seo
  • 360网站制作潍坊/厦门seo推广优化
  • 装潢公司网站源码php/网站优化排名首页
  • jsp做网站图片怎么存储/百度新闻头条
  • 网站开发项目可行性/nba交易最新消息
  • app开发学习网站/百度网盘app手机版
  • 微信商城与网站一体/google网址直接打开
  • 网站建设百灵鸟优化/百度快照是什么意思
  • 微信分享 淘宝网站 怎么做/万网域名官网
  • 初中信息科技怎么自己做网站/2023半夜免费b站推广
  • 新疆建设工程建设云官网/北京seo的排名优化
  • 定制型网站制作价格/html网页制作模板
  • 深圳网站搭建电话/东莞网络营销网站建设
  • 建设通网站账号/聊城今日头条最新
  • 无锡网络公司官网/河南郑州网站推广优化外包
  • 东游科技网站建设/赵阳竞价培训
  • wordpress 文章 来源/seo深圳网络推广
  • 网页设计公司开设需要投资多少钱/seo 公司
  • 网站开发w亿玛酷1专注/线上招生引流推广方法
  • 做优化的网站用什么空间好/营销方式有哪几种
  • 我从 Web2 转型到 Web3 的 9 条经验总结
  • 图像轮廓与凸包
  • 创建属于自己的github Page主页
  • OpenCv中的 KNN 算法实现手写数字的识别
  • [2025CVPR-图象超分辨方向]DORNet:面向退化的正则化网络,用于盲深度超分辨率
  • 使用uni-app开发一个点餐收银台系统前端静态项目练习