Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2279816
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-06-17 15:10:30

还是关于signal的高级用法:
 


sigset_t wait_set;
sigset_t zero_set;
int sig_no;
struct sigaction act;
const struct timespec tv = {5,0}; //timeout

siginfo_t sig_info ;//传递的信息结构



void sig_pipe(int signo) 
{
    printf("in sig_pipe () , signo=%d\n",signo);
    printf("errno=%d\n",errno);
    printf("access_mode = %d\n",access_mode);
    
    //if(errno == EPIPE && access_mode == ACCESS_WRITE ) { //仅对write archive的时候有效

    if(access_mode == ACCESS_WRITE ) 
    {    //当no space left的时候,为什么errno=0 ??? 

        printf("in catch function , ENOSPC \n");
        RetCode = -TAR_NO_SPACE_LEFT;
    }
    
}



void sighandler_sigchld(int signo)
{
      int child_count;
      pid_t pid;
      int status;
            
      printf("recieved signo = %d\n",signo);
    if(signo == SIGCHLD) {
        
            /* Reap defunct children until there aren't any more. */
           for(;;)
           {
                    pid = waitpid((pid_t) - 1, &status, WNOHANG); //WNOHANG 防止阻塞

                    jprintf("\n\n++++++ waitpid retunr pid (%d) , status (%d) \n",pid,status);
                    if ((int) pid == 0)    /* none left */
                     break;
                     
                    if ((int) pid < 0) 
                    {
                         if (errno == EINTR)    /* because of ptrace */
                            continue;
                     
                     /* ECHILD shouldn't happen with the WNOHANG option, but with
                     ** some kernels it does anyway. Ignore it.
                     */

                     
                     //其他的情况,就说明没有子进程需要回收了, 可以跳出循环

                         break;
                    }
            }
       
       }
}


void wait_Zombie(void)
{
      int child_count;
      pid_t pid;
      int status;
        
        /* Reap defunct children until there aren't any more. */
       for(;;)
       {
                pid = waitpid((pid_t) - 1, &status, WNOHANG); //WNOHANG 防止阻塞

                jprintf("========= in uncompress parent process free Zombie \n"
                     "waitpid retunr pid (%d) , status (%d) \n",pid,status);
                if ((int) pid == 0)    /* none left */
                 break;
                 
                if ((int) pid < 0) 
                {
                     if (errno == EINTR)    /* because of ptrace */
                        continue;
                 
                 /* ECHILD shouldn't happen with the WNOHANG option, but with
                 ** some kernels it does anyway. Ignore it.
                 */

                 
                 //其他的情况,就说明没有子进程需要回收了, 可以跳出循环

                     break;
                }
        }
       
       
}


/*===================================================
  创建.tar.gz 文件
 这个compress 比 uncompress可简单多了。
 this function will return pipe[write] id , then write block into this archive 
 =================================================== */

int sys_child_open_for_compress_xx (const char *archive_file_path)
{

    int parent_pipe[2];
    int child_pipe[2];
    pid_t grandchild_pid;
    pid_t child_pid;
    int wait_status;

    //siginfo_t sig_info ;//传递的信息结构


    sigemptyset(&zero_set);
    sigemptyset(&wait_set);
    sigaddset(&wait_set,SIGUSR1);

    sigprocmask(SIG_SETMASK,&zero_set,NULL);

    act.sa_handler = sighandler_usr1;
    //act.sa_handler = SIG_DFL;

    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO; //这个很关键,否则无法用sigqueue() 发送信号


    sigaction(SIGUSR1,&act,NULL);


    xpipe (parent_pipe);
    child_pid = xfork ();

    // -------------------------------- parent progress ---------------------------------


    if (child_pid > 0)
    {
        /* The parent tar is still here! Just clean up. */
        printf("\n\n--------- in compress : child_pid= %d\n",child_pid);
        archive = parent_pipe[PWRITE];
        xclose (parent_pipe[PREAD]);

        //在这里等待子进程的返回值,来确定是否有必要继续运行下去


again:
        sigprocmask(SIG_BLOCK,&wait_set,NULL);
        sig_no = sigtimedwait(&wait_set,&sig_info,&tv); //父进程会一直阻塞tv时间,然后就返回

        printf("sig_no=%d\n",sig_no);
        if(sig_no == -1) { //可能超时,也可能是被别的信号中断,在下面判

            printf("sigtimedwait return exception , sig_no = -1\n");
            if(errno == EINTR)//interrupted by others signals

            {
                jprintf("parent process has been interrupted by others signal \n");
                jprintf("it will continue to be blocked \n");
                goto again;
            }
            else if(errno == EAGAIN)//resource unavilable , timeout

            ;    //jump out; do nothing


            return -TAR_CANNOT_CREATE_ARCHIVE_FILE;
        }
        else {
            printf("child process return value = %d\n",sig_info.si_int);
            if(sig_info.si_int > 0) { //信号传递的信息:传递的子进程create的archive的fd

                printf("ok\n");
                printf("child process create fd=%d\n",sig_info.si_int);

                return archive;
            }
            else
            { // fd <=0

                printf("can't create archive file ,please check directory\n");
                return -TAR_CANNOT_CREATE_ARCHIVE_FILE;

                //FIXME: 我的意思是子进程无法创建archive , 的时候, 返回负数, 但是archive本身永远是对的

                //不过不是大问题,最多没有close(archive)而已。

            }

        }


        //-------------------------------------------------------------------


        //return archive; 原来是直接返回,这是不对的,必须经过上面的判断才可


    }
    else if (child_pid == 0) {

        /* The new born child tar is here! */
        union sigval rc_val;
        //program_name = _("tar (child)");


        xdup2 (parent_pipe[PREAD], STDIN_FILENO);//dup2 to stdin

        xclose (parent_pipe[PWRITE]);


        // if (!_remdev (archive_name_array[0])

        // && is_regular_file (archive_name_array[0]))

        {

            int _tar_gz_fd = 0;
            pid_t p_pid = 0;
            /* We don't need a grandchild tar. Open the archive and launch the
            compressor. */

            if (strcmp (archive_file_path, "-")) //最一般的情况,比如 tar zcvf bob.tar.gz system.c update.c

            {

                _tar_gz_fd = creat (archive_file_path, MODE_RW);
                jprintf("in child progress (gzip) ,fd = %d\n",_tar_gz_fd);

                rc_val.sival_int = _tar_gz_fd; //传递整型值

                //这里要通知父进程

                p_pid = getppid();
                if(p_pid !=1) { //如果父进程是1(init) , 就不要发信号(事实上没有这种可能,因为父进程已经阻塞了)

                    jprintf("has send SIGUSR1 signal \n");
                    sleep(1); //in Marvell 的扳子上,子进程run的太快了,以至于父进程还没有执行到sigtimedwait()函数

                    //因此必须sleep一下, 确保父进程已经blocked

                    sigqueue(p_pid,SIGUSR1,rc_val); //kill的更强的用法,除了kill的功能外,还可以传递整形值和指针

                    //exit(0); //

                }


                if (_tar_gz_fd < 0)
                {
                    int saved_errno = errno;

                    errno = saved_errno;
                    // open_fatal (archive_file_path);

                    exit(0);
                }

                xdup2 (_tar_gz_fd, STDOUT_FILENO); //父进程会把tar的结果输出到 archive中去, gzip到这里取结果!

            }

            execlp (use_compress_program_option, use_compress_program_option, NULL);
            //如果gzip执行正常,就不会执行到下面的代码

            jprintf("gzip run status = %d\n",errno);
            //exec_fatal (use_compress_program_option);

        }

    }

}


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