zoukankan      html  css  js  c++  java
  • sleep 和 usleep的实现方法

    一、sleep 和 usleep
    1、不属于系统调用,是glibc 库函数实现的;
    2、glibc函数库中通过调用内核的nanosleep实现的;
    3、内核nanosleep通过调用 hrtimer_nanosleep 实现(/kernel/hrtime);
     
    二、源码
    2.1 usleep  (glibc2.11)
    int usleep (useconds_t useconds)
    {
      struct timespec ts = { .tv_sec = (long int) (useconds / 1000000),
    		.tv_nsec = (long int) (useconds % 1000000) * 1000ul };
      /* Note the usleep() is a cancellation point.  But since we call
         nanosleep() which itself is a cancellation point we do not have
         to do anything here.  */
      return __nanosleep (&ts, NULL);
    }
    2.2 sleep源码
    /* We are going to use the `nanosleep' syscall of the kernel.  But the
       kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
       behaviour for this syscall.  Therefore we have to emulate it here.  */
    unsigned int
    __sleep (unsigned int seconds)
    {
      const unsigned int max
        = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
      struct timespec ts;
      sigset_t set, oset;
      unsigned int result;
    
      /* This is not necessary but some buggy programs depend on this.  */
      if (__builtin_expect (seconds == 0, 0))
        {
    #ifdef CANCELLATION_P
          CANCELLATION_P (THREAD_SELF);
    #endif
          return 0;
        }
    
      ts.tv_sec = 0;
      ts.tv_nsec = 0;
     again:
      if (sizeof (ts.tv_sec) <= sizeof (seconds))
        {
          /* Since SECONDS is unsigned assigning the value to .tv_sec can
    	 overflow it.  In this case we have to wait in steps.  */
          ts.tv_sec += MIN (seconds, max);
          seconds -= (unsigned int) ts.tv_sec;
        }
      else
        {
          ts.tv_sec = (time_t) seconds;
          seconds = 0;
        }
    
      /* Linux will wake up the system call, nanosleep, when SIGCHLD
         arrives even if SIGCHLD is ignored.  We have to deal with it
         in libc.  We block SIGCHLD first.  */
      __sigemptyset (&set);
      __sigaddset (&set, SIGCHLD);
      if (__sigprocmask (SIG_BLOCK, &set, &oset))
        return -1;
    
      /* If SIGCHLD is already blocked, we don't have to do anything.  */
      if (!__sigismember (&oset, SIGCHLD))
        {
          int saved_errno;
          struct sigaction oact;
    
          __sigemptyset (&set);
          __sigaddset (&set, SIGCHLD);
    
          /* We get the signal handler for SIGCHLD.  */
          if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
    	{
    	  saved_errno = errno;
    	  /* Restore the original signal mask.  */
    	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
    	  __set_errno (saved_errno);
    	  return -1;
    	}
    
          /* Note the sleep() is a cancellation point.  But since we call
    	 nanosleep() which itself is a cancellation point we do not
    	 have to do anything here.  */
          if (oact.sa_handler == SIG_IGN)
    	{
    	  //__libc_cleanup_push (cl, &oset);
    
    	  /* We should leave SIGCHLD blocked.  */
    	  while (1)
    	    {
    	      result = __nanosleep (&ts, &ts);
    
    	      if (result != 0 || seconds == 0)
    		break;
    
    	      if (sizeof (ts.tv_sec) <= sizeof (seconds))
    		{
    		  ts.tv_sec = MIN (seconds, max);
    		  seconds -= (unsigned int) ts.tv_nsec;
    		}
    	    }
    
    	  //__libc_cleanup_pop (0);
    
    	  saved_errno = errno;
    	  /* Restore the original signal mask.  */
    	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
    	  __set_errno (saved_errno);
    
    	  goto out;
    	}
    
          /* We should unblock SIGCHLD.  Restore the original signal mask.  */
          (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
        }
    
      result = __nanosleep (&ts, &ts);
      if (result == 0 && seconds != 0)
        goto again;
    
     out:
      if (result != 0)
        /* Round remaining time.  */
        result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
    
      return result;
    }
    2.3 内核nanosleep源码
    long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,const enum hrtimer_mode mode, const clockid_t clockid)
    {
    	struct restart_block *restart;
    	struct hrtimer_sleeper t;
    	int ret = 0;
    	unsigned long slack;
    	slack = current->timer_slack_ns;
    	if (rt_task(current))
    		slack = 0;
    	hrtimer_init_on_stack(&t.timer, clockid, mode);
    	hrtimer_set_expires_range_ns(&t.timer, timespec_to_ktime(*rqtp), slack);
    	if (do_nanosleep(&t, mode))
    		goto out;
    	/* Absolute timers do not update the rmtp value and restart: */
    	if (mode == HRTIMER_MODE_ABS) {
    		ret = -ERESTARTNOHAND;
    		goto out;
    	}
    	if (rmtp) {
    		ret = update_rmtp(&t.timer, rmtp);
    		if (ret <= 0)
    			goto out;
    	}
    	restart = &current_thread_info()->restart_block;
    	restart->fn = hrtimer_nanosleep_restart;
    	restart->nanosleep.clockid = t.timer.base->clockid;
    	restart->nanosleep.rmtp = rmtp;
    	restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
    	ret = -ERESTART_RESTARTBLOCK;
    out:
    	destroy_hrtimer_on_stack(&t.timer);
    	return ret;
    }
    SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
    		struct timespec __user *, rmtp)
    {
    	struct timespec tu;
    	if (copy_from_user(&tu, rqtp, sizeof(tu)))
    		return -EFAULT;
    	if (!timespec_valid(&tu))
    		return -EINVAL;
    
    	return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
  • 相关阅读:
    107. Binary Tree Level Order Traversal II
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    690. Employee Importance
    1723. Find Minimum Time to Finish All Jobs
    LeetCode 329 矩阵中最长增长路径
    7.2 物理内存管理
    LeetCode 面试题 特定深度节点链表
    LeetCode 100 相同的树
    npm安装包命令详解,dependencies与devDependencies实际区别
  • 原文地址:https://www.cnblogs.com/FarmPick/p/6096650.html
Copyright © 2011-2022 走看看