免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: xltao
打印 上一主题 下一主题

关于SIGCHLD的不排队,丢弃的问题 [复制链接]

论坛徽章:
0
41 [报告]
发表于 2006-09-19 10:09 |只看该作者
原帖由 googleboy 于 2006-9-19 08:27 发表


进程表用完了之后,应该就不会再fork进程了,跟init进程和父进程应该没有什么关系吧。

可以详细地说说你的意思吗?谢谢。


你说的没错,

我记得我们老师好像说过:(不对请批评我)
进程表用完的时候系统会进行一次清理(或者是叫别的),回收一些已经是退出状态而没被清理的注册表项。然后重新使用。(操作系统应该有这方面的详细解释)

其实我们在做开发过程中也可以看到,进程号大到一定程序就又回到小值了。也就是一个循环使用的过程。

当然,这只是我的理解,因为理论知识学得不好,不敢说对的。(不对请拍砖)

论坛徽章:
0
42 [报告]
发表于 2006-09-19 10:14 |只看该作者
原帖由 linternt 于 2006-9-19 10:09 发表


你说的没错,

我记得我们老师好像说过:(不对请批评我)
进程表用完的时候系统会进行一次清理(或者是叫别的),回收一些已经是退出状态而没被清理的注册表项。然后重新使用。(操作系统应该有这方面的详 ...

进程号是一个循环累加的过程,但是新进程的基本规则是进程号唯一,而你的说法显然违反了这条规则,不仅如此,还敢“自动清理”,试问,谁给系统自动清理的权利了?

论坛徽章:
0
43 [报告]
发表于 2006-09-19 14:30 |只看该作者
我知道进程是累加的,可是到一定数值后就又回到很小的值了。
照你所说,进程只无限增大的了。

另外的自动清理是我个人的理解,就是说如果进程没被回收的话,INIT进程会去处理。然后重用这个进程表。

论坛徽章:
0
44 [报告]
发表于 2006-09-19 14:56 |只看该作者
原帖由 linternt 于 2006-9-19 14:30 发表
我知道进程是累加的,可是到一定数值后就又回到很小的值了。
照你所说,进程只无限增大的了。

另外的自动清理是我个人的理解,就是说如果进程没被回收的话,INIT进程会去处理。然后重用这个进程表。

重用小的PID的前提是这个PID是空闲的。

论坛徽章:
0
45 [报告]
发表于 2006-09-19 16:03 |只看该作者
如果又回到小的值得话,应该是数值溢出了吧。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
46 [报告]
发表于 2006-09-19 17:28 |只看该作者
原帖由 思一克 于 2006-9-15 17:16 发表
这也基本是个伪命题。不存在丢失,还有排队的问题

存在

论坛徽章:
0
47 [报告]
发表于 2006-09-19 22:34 |只看该作者
原帖由 linternt 于 2006-9-19 14:30 发表
我知道进程是累加的,可是到一定数值后就又回到很小的值了。
照你所说,进程只无限增大的了。

另外的自动清理是我个人的理解,就是说如果进程没被回收的话,INIT进程会去处理。然后重用这个进程表。

循环累加的意思就是从1到100,头尾连起来

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
48 [报告]
发表于 2006-09-19 23:21 |只看该作者
在忽略情况下,一旦一个进程收到一个SIG_CHLD,这个进程就会干掉:

current进程所在的thread_group中, 所有进程的所有子进程里的,exit_signal == SIG_CHLD,并且处于僵尸状态的那部分子进程


以下摘自2.4.32

int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
{
        siginfo_t info;
        struct k_sigaction *ka;


        if ((regs->xcs & 3) != 3)
                return 1;

        if (!oldset)
                oldset = &current->blocked;

        for (; {
                unsigned long signr;

                spin_lock_irq(&current->sigmask_lock);
                signr = dequeue_signal(&current->blocked, &info);
                spin_unlock_irq(&current->sigmask_lock);

                if (!signr)
                        break;


                if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {

                                        //进程被跟踪,在这里处理,不考虑

                }

                ka = &current->sig->action[signr-1];


               

                              /*SIG_IGN 时的处理, 这里是关键*/


                if (ka->sa.sa_handler == SIG_IGN) {

                        /*SIGCHLD以外的信号忽略,但是SIGCHLD不忽略,执行这里*/
                        if (signr != SIGCHLD)
                                continue;

                        while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
                        ;
                        continue;
                }

                                
                                /*默认的信号处理函数*/
                if (ka->sa.sa_handler == SIG_DFL) {
                        int exit_code = signr;

                        if (current->pid == 1)
                                continue;

                                             /* 这里执行默认的信号处理函数*/
                }


                __asm__("movl %0,%%db7"        : : "r" (current->thread.debugreg[7]));

                /* Whee!  Actually deliver the signal.  */
                handle_signal(signr, ka, &info, oldset, regs);
                return 1;
        }

        /* Did we come from a system call? */
        if (regs->orig_eax >= 0) {
                /* Restart the system call - no handlers present */
                if (regs->eax == -ERESTARTNOHAND ||
                    regs->eax == -ERESTARTSYS ||
                    regs->eax == -ERESTARTNOINTR) {
                        regs->eax = regs->orig_eax;
                        regs->eip -= 2;
                }
        }
        return 0;
}




这个就是对SIGCHLD的处理

        while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
        ;

  反复执行sys_wait4(-1, NULL, WNOHANG, NULL) ,直到返回<=0







asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
{
        int flag, retval;
        DECLARE_WAITQUEUE(wait, current);
        struct task_struct *tsk;

        if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
                return -EINVAL;

        add_wait_queue(&current->wait_chldexit,&wait);
                /* 以上语句都不用考虑*/

repeat:
        flag = 0;
        current->state = TASK_INTERRUPTIBLE;
        read_lock(&tasklist_lock);
        tsk = current;

        do {
                struct task_struct *p;
                 for (p = tsk->p_cptr ; p ; p = p->p_osptr) {
                          
                                                /*  这里省略了一部分指令,以参数pid = -1, option = WNOHANG
                                                 *   来执行这里的语句时,效果就是
                                 *
                                                 *   过滤掉所有exit_signal != SIG_CHLD的,进程task的子进程
                                 *
                                                 *   进程task的所有exit_signal == SIG_CHLD的子进程进入下边的
                                 *  flag = 1;
                                                  * switch (p->state) {
                                                 *
                                                 */
                       
                                                flag = 1;

                        switch (p->state) {
                        case TASK_STOPPED:
                                                               
                                                                /* 对被跟踪进程的处理,我们不考虑*/
                                goto end_wait4;


                        case TASK_ZOMBIE:
                               
                                read_unlock(&tasklist_lock);

                                retval = p->pid;
  
                                                                /* 对exit_signal == SIG_CHLD的子进程的处理*/

                                if (p->p_opptr != p->p_pptr) {

                                                                     /*进程task的继子进程归还给继子进程的原始父进程,
                                                                       *并向原始父进程发送SIG_CHLD*/
                                } else
                                        release_task(p);
                                                                               /*回收僵尸进程的task_struct*/

                                goto end_wait4;
                        default:
                                continue;
                        }
                }
                              

                                /* 以下3句指令
                      *
                                 * 因为参数中没有设置__WNOTHREAD,所以会循环扫描整个thread_group中的
                      * 所有进程的所有子进程,当然,子进程必须exit_signal == SIG_CHLD
                                 */
                if (options & __WNOTHREAD)
                        break;
                tsk = next_thread(tsk);

        } while (tsk != current);


        read_unlock(&tasklist_lock);

               
                /* 一旦执行这个if语句,证明当前进程所在的thread_group中,所有进程的所有子进程
            *(子进程还要满足 exit_signal == SIG_CHLD)只有就绪,可中断,不可中断三种状态
            *
                  * 而没有僵尸,或者被跟踪而停止的子进程
                  *
                  * 这样会返回0
                  */
        if (flag) {
                retval = 0;
                if (options & WNOHANG)
                        goto end_wait4;
                    
                                /*以下省略一些指令,因为根本不会执行,参数中option == WNOHANG*/
        }

               
               /* thread_group中,所有进程都没有exit_signal == SIG_CHLD的子进程,才会执行
           * retval = -ECHILD,返回负值
                 */

        retval = -ECHILD;


  
               /* 三种情况会到达这里
           *
                * 1) 处理了一个僵尸进程,retval = 僵尸进程的pid
                *
                * 2) thread_group组中所有进程的子进程们,虽然有的exit_signal == SIG_CHLD,
                *     但是没有僵尸进程,retval = 0
                *
                * 3) thread_group组中进程的子进程们,没有任何一个exit_signal == SIG_CHLD,
                *     这时retval = -ECHILD,负值
                */
end_wait4:
        current->state = TASK_RUNNING;
        remove_wait_queue(&current->wait_chldexit,&wait);
        return retval;
}

[ 本帖最后由 塑料袋 于 2006-9-19 23:27 编辑 ]

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
49 [报告]
发表于 2006-09-19 23:34 |只看该作者
你的这段程序
void sig_chld(int signo)
{
       pid_t   pid;
       int     stat;
      
       while((pid = waitpid(-1, &stat, WNOHANG)) > 0){
               printf("child %d terminated\n", pid);
       }
        return;
}


跟Linux Kernel中对SIGCHLD的处理基本一模一样

waitpid(-1, &stat, WNOHANG)) 类似于sys_wait4

只要当前进程所在的线程组中,有任何一个线程还有子进程,并且这个子进程的exit_signal == SIGCHLD,还处于ZOMBIE状态,那么就会返回一个>0的ZOMBIE进程的pid

直到干掉了所有这样的子进程,才返回<=0 的值

象这么用的话,一个SIGCHLD就足够干掉一大片子进程了

[ 本帖最后由 思一克 于 2006-9-20 09:49 编辑 ]

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
50 [报告]
发表于 2006-09-20 09:21 |只看该作者
原帖由 flw 于 2006-9-20 09:17 发表
塑料袋兄弟,以您目前的水平,还不适合在 ChinaUnix C/C++ 版回答别人的问题。希望您在这一点上有足够的自知之明,否则只会毒害别人,并没有什么好处。



塑料袋兄弟,以您目前的水平,还不适合在 ChinaUnix C/C++ 版回答别人的问题。希望您在这一点上有足够的自知之明,否则只会根一帮弱智们对牛弹琴,并没有什么好处。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP