linux進程管理之wait系統調用

來源:互聯網
上載者:User

六: wait4 ()系統調用

在父進程中,用wait4()可以獲得子進程的退出狀態,並且防止在父進程退出前,子進程退出造成僵死 狀態。這是我們這節分析的最後一個小節了。

關於wait4()在使用者空間的調用方式可以自行參考相關資料,在這裡只是討論核心對這個系統調用的實 現過程。

Wait4()的系統調用入口為sys_wait4().代碼如下所示:

asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,        int options, struct rusage __user *ru){   long ret;   //options的標誌為須為WNOHANG…__WALL的組合,否則會出錯   //相關標誌的作用在do_wait()中再進行分析   if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|       __WNOTHREAD|__WCLONE|__WALL))     return -EINVAL;   ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru);   /* avoid REGPARM breakage on x86: */   prevent_tail_call(ret);   return ret;}

do_wait()是其中的核心處理函數。代碼如下:

static long do_wait(pid_t pid, int options, struct siginfo __user *infop,       int __user *stat_addr, struct rusage __user *ru){   //初始化一個等待隊列   DECLARE_WAITQUEUE(wait, current);   struct task_struct *tsk;   int flag, retval;   int allowed, denied;   //將當前進程加入等待隊列,子進程退出給父進程發送訊號會wake up些等待隊列   add_wait_queue(&current->signal->wait_chldexit,&wait);repeat:   flag = 0;   allowed = denied = 0;   //設定進程狀態為TASK_INTERRUPTIBLE.下次調度必須要等到子進程喚醒才可以了   current->state = TASK_INTERRUPTIBLE;   read_lock(&tasklist_lock);   tsk = current;   do {     struct task_struct *p;     struct list_head *_p;     int ret;     //遍曆進程下的子進程     list_for_each(_p,&tsk->children) {       p = list_entry(_p, struct task_struct, sibling);       //判斷是否是我們要wait 的子進程       ret = eligible_child(pid, options, p);       if (!ret)          continue;       if (unlikely(ret < 0)) {          denied = ret;          continue;       }       allowed = 1;       switch (p->state) {       //子進程為TASK_TRACED.即處於跟蹤狀態。則取子進程的相關資訊       case TASK_TRACED:          flag = 1;          //判斷是否是被父進程跟蹤的子進程          //如果是則返回1..不是返回0          if (!my_ptrace_child(p))            continue;          /*FALLTHROUGH*/       case TASK_STOPPED:          flag = 1;          //WUNTRACED:子進程是停止的,也馬上返回          //沒有定義WUNTRACED 參數.繼續遍曆子進程          /*從此看出.生父進程是不會處理STOP狀態的子進程的.只有            發起跟蹤的進程才會           */                     if (!(options & WUNTRACED) &&            !my_ptrace_child(p))            continue;          //WNOWAIT:不會將zombie子進程的退出狀態撤銷          //下次調用wait系列函數的時候還可以繼續獲得這個退出狀態          retval = wait_task_stopped(p, ret == 2,                   (options & WNOWAIT),                   infop,                   stat_addr, ru);          if (retval == -EAGAIN)            goto repeat;          if (retval != 0) /* He released the lock. */            goto end;          break;       default:       // case EXIT_DEAD:          //不需要處理DEAD狀態          if (p->exit_state == EXIT_DEAD)            continue;       // case EXIT_ZOMBIE:          //子進程為殭屍狀態          if (p->exit_state == EXIT_ZOMBIE) {            if (ret == 2)              goto check_continued;            if (!likely(options & WEXITED))continue;            retval = wait_task_zombie(              p, (options & WNOWAIT),              infop, stat_addr, ru);            /* He released the lock. */            if (retval != 0)              goto end;            break;          }check_continued:          /*          * It's running now, so it might later          * exit, stop, or stop and then continue.          */          flag = 1;       //WCONTINUED:報告任何繼續啟動並執行指定進程號的子進程的狀態          if (!unlikely(options & WCONTINUED))            continue;        //取進程的相關狀態        retval = wait_task_continued(            p, (options & WNOWAIT),            infop, stat_addr, ru);          if (retval != 0) /* He released the lock. */            goto end;          break;       }     }     //遍曆被跟蹤出去的子進程     //從這裡可以看出.如果一個子進程被跟蹤出去了.那麼子進程的退出     //操作並不是由生父進程進行了     if (!flag) {       list_for_each(_p, &tsk->ptrace_children) {          p = list_entry(_p, struct task_struct,              ptrace_list);          if (!eligible_child(pid, options, p))            continue;          flag = 1;          break;       }     }     if (options & __WNOTHREAD)       break;     //也有可能是進程中的線程在wait其fork出來的子進程     tsk = next_thread(tsk);     BUG_ON(tsk->signal != current->signal);   } while (tsk != current);   //   read_unlock(&tasklist_lock);   if (flag) {     retval = 0;     //如果定義了WHNOHANG:馬上退出     if (options & WNOHANG)       goto end;     retval = -ERESTARTSYS;     if (signal_pending(current))       goto end;     schedule();     goto repeat;   }   retval = -ECHILD;   if (unlikely(denied) && !allowed)     retval = denied;end:   //將進程設為運行狀態,從等待隊列中移除   current->state = TASK_RUNNING;   remove_wait_queue(&current->signal->wait_chldexit,&wait);   if (infop) {     if (retval > 0)     retval = 0;     else {       /*       * For a WNOHANG return, clear out all the fields       * we would set so the user can easily tell the       * difference.       */       if (!retval)          retval = put_user(0, &infop->si_signo);       if (!retval)          retval = put_user(0, &infop->si_errno);       if (!retval)          retval = put_user(0, &infop->si_code);       if (!retval)          retval = put_user(0, &infop->si_pid);       if (!retval)          retval = put_user(0, &infop->si_uid);       if (!retval)          retval = put_user(0, &infop->si_status);     }   }   return retval;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.