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);
  • 相关阅读:
    C语言中const关键字的用法
    LDO和DC-DC的概念,区别及优缺点
    Ubuntu下几个命令行方式使用的图片浏览工具
    I2C和I2S的区别和使用方法
    scikit-image 图像处理库介绍
    USB协议介绍
    Ubuntu 16.04 python和OpenCV安装
    一种基于python的人脸识别开源系统
    numpy 介绍
    python enumerate用法总结
  • 原文地址:https://www.cnblogs.com/FarmPick/p/6096650.html
Copyright © 2011-2022 走看看