Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3129713
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2015-02-03 10:46:36

原文地址:
linux 2.6.11中worker_thread被调用的流程如下:
create_workqueue->__create_workqueue->create_workqueue_thread->kthread_create->worker_thread:
worker_thread其中有这么一段:
  1. /* Block and flush all signals */
  2. 194        sigfillset(&blocked);
  3. 195        sigprocmask(SIG_BLOCK, &blocked, NULL);
  4. 196        flush_signals(current);
  5. 197
  6. 198        /* SIG_IGN makes children autoreap: see do_notify_parent(). */
  7. 199        sa.sa.sa_handler = SIG_IGN;
  8. 200        sa.sa.sa_flags = 0;
  9. 201        siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
  10. 202        do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
复制代码
创建工作者线程的时候,block and flush all signals,但是为什么单独设置了SIGCHLD呢,而且处理方式还是SIG_IGN的。
  1. 212fastcall void recalc_sigpending_tsk(struct task_struct *t)
  2. 213{
  3. 214        if (t->signal->group_stop_count > 0 ||
  4. 215            PENDING(&t->pending, &t->blocked) ||
  5. 216            PENDING(&t->signal->shared_pending, &t->blocked))
  6. 217                set_tsk_thread_flag(t, TIF_SIGPENDING);
  7. 218        else
  8. 219                clear_tsk_thread_flag(t, TIF_SIGPENDING);
  9. 220}
复制代码
从recalc_sigpending_tsk的代码来看,即使上边设置了SIGCHLD,但是
  1. 194        sigfillset(&blocked);
  2. 195        sigprocmask(SIG_BLOCK, &blocked, NULL);
复制代码
worker_thread函数中这两句已经把所有的信号都block掉了,这样即使有SIGCHLD信号到来,recalc_sigpending_tsk仍然不会设置TIF_SIGCHLD,那么在worker_thread中多此一举有什么作用呢?
China linux内核开发者qq群 110604406
拒绝新手加入
  |    |    |    |  

Rank: 2

帖子 主题 精华 可用积分 1874 专家积分 200 在线时间 2900 小时 注册时间 2006-11-16 最后登录 2014-11-10 论坛徽章: 0
 发表于 2012-04-24 13:51:36 |
去看一下do_notify_parent函数。子进程退出的时候,会向其父进程发送SIGCHLD信号(默认)作为通知。然后子进程进入zombie状态,等待父进程wait4。
而如果父进程设置SIGCHLD的handler为Ignore,或者handler的sa_flags包含SA_NOCLDWAIT,则不会通知父进程,并且子进程直接就退出了,而不需要进入zombie状态。
  1. bool do_notify_parent(struct task_struct *tsk, int sig)
  2. {
  3.         ......
  4.         psig = tsk->parent->sighand;
  5.         spin_lock_irqsave(&psig->siglock, flags);
  6.         if (!tsk->ptrace && sig == SIGCHLD &&
  7.             (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
  8.              (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) {
  9.                 /*
  10.                  * We are exiting and our parent doesn't care.  POSIX.1
  11.                  * defines special semantics for setting SIGCHLD to SIG_IGN
  12.                  * or setting the SA_NOCLDWAIT flag: we should be reaped
  13.                  * automatically and not left for our parent's wait4 call.
  14.                  * Rather than having the parent do it as a magic kind of
  15.                  * signal handler, we just set this to tell do_exit that we
  16.                  * can be cleaned up without becoming a zombie.  Note that
  17.                  * we still call __wake_up_parent in this case, because a
  18.                  * blocked sys_wait4 might now return -ECHILD.
  19.                  *
  20.                  * Whether we send SIGCHLD or not for SA_NOCLDWAIT
  21.                  * is implementation-defined: we do (if you don't want
  22.                  * it, just use SIG_IGN instead).
  23.                  */
  24.                 autoreap = true;
  25.                 if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
  26.                         sig = 0;
  27.         }
  28.         if (valid_signal(sig) && sig)
  29.                 __group_send_sig_info(sig, &info, tsk->parent);
  30.         __wake_up_parent(tsk, tsk->parent);
  31.         spin_unlock_irqrestore(&psig->siglock, flags);

  32.         return autoreap;
  33. }
复制代码
 , welcome~
I am thirst for magic...
| |  | 
Wanpeng Li

Rank: 8Rank: 8

帖子 主题 精华 可用积分 792 专家积分 0 在线时间 6185 小时 注册时间 2011-04-24 最后登录 2015-02-03 论坛徽章: 13
水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47CU十二周年纪念徽章
日期:2013-10-24 15:41:34卯兔
日期:2013-09-24 09:57:16午马
日期:2013-08-29 07:14:40酉鸡
日期:2014-12-07 09:06:19
 发表于 2012-04-24 14:50:42 |
本帖最后由 embeddedlwp 于 2012-04-24 14:52 编辑

回复  kouu 


thank you kouu! 但是仍然有一些不明白的地方:
1)如你列出的do_notify_parent的代码:
  1. if (valid_signal(sig) && sig)
  2.                 __group_send_sig_info(sig, &info, tsk->parent);
  3.         __wake_up_parent(tsk, tsk->parent);
复制代码
如果parent SIGCHLD的handler是Ignore的或者handler的sa_flags包含SA_NOCLDWAIT,那么会设置sig为0,这样就不发信号了,但是可能parent调用了sys_wait4,需要唤醒parent,这个理解的对吧?
2)如果parent SIGCHLD的handler是Ignore的或者handler的sa_flags包含SA_NOCLDWAIT的时候,child不会发信号给parent,也就是说parent不会执行release_task释放child,那么child岂不还是zombie吗?
  1. 738        /* If something other than our normal parent is ptracing us, then
  2. 739         * send it a SIGCHLD instead of honoring exit_signal.  exit_signal
  3. 740         * only has special meaning to our real parent.
  4. 741         */
  5. 742        if (tsk->exit_signal != -1 && thread_group_empty(tsk)) {
  6. 743                int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD;
  7. 744                do_notify_parent(tsk, signal);
  8. 745        } else if (tsk->ptrace) {
  9. 746                do_notify_parent(tsk, SIGCHLD);
  10. 747        }
  11. 748
  12. 749        state = EXIT_ZOMBIE;
  13. 750        if (tsk->exit_signal == -1 &&
  14. 751            (likely(tsk->ptrace == 0) ||
  15. 752             unlikely(tsk->parent->signal->flags & SIGNAL_GROUP_EXIT)))
  16. 753                state = EXIT_DEAD;
  17. 754        tsk->exit_state = state;
  18. 755
  19. 756        /*
  20. 757         * Clear these here so that update_process_times() won't try to deliver
  21. 758         * itimer, profile or rlimit signals to this task while it is in late exit.
  22. 759         */
  23. 760        tsk->it_virt_value = cputime_zero;
  24. 761        tsk->it_prof_value = cputime_zero;
  25. 762
  26. 763        write_unlock_irq(&tasklist_lock);
  27. 764
  28. 765        list_for_each_safe(_p, _n, &ptrace_dead) {
  29. 766                list_del_init(_p);
  30. 767                t = list_entry(_p,struct task_struct,ptrace_list);
  31. 768                release_task(t);
  32. 769        }
  33. 770
  34. 771        /* If the process is dead, release it - nobody will wait for it */
  35. 772        if (state == EXIT_DEAD)
  36. 773                release_task(tsk);
复制代码
从这段exit_notify函数中摘取的代码来看,child的状态不可能是EXIT_DEAD啊,也就是说自己不会调用release_task的。
   
China linux内核开发者qq群 110604406
拒绝新手加入
| |  | 

Rank: 2

帖子 主题 精华 可用积分 1874 专家积分 200 在线时间 2900 小时 注册时间 2006-11-16 最后登录 2014-11-10 论坛徽章: 0
 发表于 2012-04-24 15:52:18 |
回复  embeddedlwp 

我看的代码版本比较新,跟你的还不太一样。3.x版本是通过do_notify_parent的返回值来决定子进程应该置为什么状态(EXIT_DEAD或EXIT_ZOMBIE)。

而2.6.11里面do_notify_parent并没有返回值。不过里面多了一个操作,如果父进程ignore的话,会将子进程的“tsk->exit_signal = -1;”,这样在exit_notify里面就会走到“state = EXIT_DEAD;”的逻辑了。

如果父进程ignore了SIGCHLD,而又去调用wait4。还真不知道会怎样,死等?还是不等?呵呵

 , welcome~
I am thirst for magic...
| |  | 
Wanpeng Li

Rank: 8Rank: 8

帖子 主题 精华 可用积分 792 专家积分 0 在线时间 6185 小时 注册时间 2011-04-24 最后登录 2015-02-03 论坛徽章: 13
水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47CU十二周年纪念徽章
日期:2013-10-24 15:41:34卯兔
日期:2013-09-24 09:57:16午马
日期:2013-08-29 07:14:40酉鸡
日期:2014-12-07 09:06:19
 发表于 2012-04-24 16:00:18 |
本帖最后由 embeddedlwp 于 2012-04-24 16:05 编辑

回复  kouu 

如果父进程ignore了SIGCHLD,而又去调用wait4。还真不知道会怎样,死等?还是不等?呵呵

=====================================================================
  1. bool do_notify_parent(struct task_struct *tsk, int sig)
  2. {
  3.        ....................
  4.         if (valid_signal(sig) && sig)
  5.                 __group_send_sig_info(sig, &info, tsk->parent);
  6.         __wake_up_parent(tsk, tsk->parent);
  7.         spin_unlock_irqrestore(&psig->siglock, flags);

  8.         return autoreap;
  9. }
复制代码
do_notify_parent函数中不是有这段代码嘛,那么如果是Ignore或者SA_NOCLDWAIT的情况,只是不会发送信号。仍然会调用__wake_up_parent函数将parent唤醒啊。


还有一个问题,我们上边讨论的都是这个worker_thread函数中的SIGCHLD信号。那么工作者线程什么时候需要自己fork一个子进程,准确点说应该是一个内核线程??





   
China linux内核开发者qq群 110604406
拒绝新手加入
| |  | 

Rank: 2

帖子 主题 精华 可用积分 1874 专家积分 200 在线时间 2900 小时 注册时间 2006-11-16 最后登录 2014-11-10 论坛徽章: 0
 发表于 2012-04-24 16:25:34 |
回复  embeddedlwp 

嗯,貌似的确如此。这种情况下父进程被唤醒后,wait4的返回值将是-ECHILD。

workqueue接触很少,不知道是否有在work_struct->func()中又创建子线程的这种情况。好像并不排斥这样做吧~
 , welcome~
I am thirst for magic...
| |  | 
Wanpeng Li

Rank: 8Rank: 8

帖子 主题 精华 可用积分 792 专家积分 0 在线时间 6185 小时 注册时间 2011-04-24 最后登录 2015-02-03 论坛徽章: 13
水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47CU十二周年纪念徽章
日期:2013-10-24 15:41:34卯兔
日期:2013-09-24 09:57:16午马
日期:2013-08-29 07:14:40酉鸡
日期:2014-12-07 09:06:19
 发表于 2012-05-02 16:12:09 |
回复  kouu 


do_signal函数处理的应该是非阻塞的挂起信号,但是看上边worker thread的代码,既然已经屏蔽掉了所有信号,又搞一个SIGCHLD是不是没有意思啊?


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