github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/common/mclock/simclock.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:34</date>
    10  //</624450074071535616>
    11  
    12  
    13  package mclock
    14  
    15  import (
    16  	"sync"
    17  	"time"
    18  )
    19  
    20  //模拟实现了一个可重复的时间敏感测试的虚拟时钟。它
    21  //在实际处理占用零时间的虚拟时间刻度上模拟调度程序。
    22  //
    23  //虚拟时钟本身不前进,调用run前进并执行计时器。
    24  //由于无法影响Go调度程序,因此测试涉及的超时行为
    25  //戈罗蒂内斯需要特别照顾。测试这种超时的一个好方法是:首先
    26  //执行应该超时的操作。确保要测试的计时器
    27  //创建。然后运行时钟直到超时之后。最后观察
    28  //使用通道或信号量的超时。
    29  type Simulated struct {
    30  	now       AbsTime
    31  	scheduled []event
    32  	mu        sync.RWMutex
    33  	cond      *sync.Cond
    34  }
    35  
    36  type event struct {
    37  	do func()
    38  	at AbsTime
    39  }
    40  
    41  //RUN按给定的持续时间移动时钟,在该持续时间之前执行所有计时器。
    42  func (s *Simulated) Run(d time.Duration) {
    43  	s.mu.Lock()
    44  	defer s.mu.Unlock()
    45  	s.init()
    46  
    47  	end := s.now + AbsTime(d)
    48  	for len(s.scheduled) > 0 {
    49  		ev := s.scheduled[0]
    50  		if ev.at > end {
    51  			break
    52  		}
    53  		s.now = ev.at
    54  		ev.do()
    55  		s.scheduled = s.scheduled[1:]
    56  	}
    57  	s.now = end
    58  }
    59  
    60  func (s *Simulated) ActiveTimers() int {
    61  	s.mu.RLock()
    62  	defer s.mu.RUnlock()
    63  
    64  	return len(s.scheduled)
    65  }
    66  
    67  func (s *Simulated) WaitForTimers(n int) {
    68  	s.mu.Lock()
    69  	defer s.mu.Unlock()
    70  	s.init()
    71  
    72  	for len(s.scheduled) < n {
    73  		s.cond.Wait()
    74  	}
    75  }
    76  
    77  //现在实现时钟。
    78  func (s *Simulated) Now() AbsTime {
    79  	s.mu.RLock()
    80  	defer s.mu.RUnlock()
    81  
    82  	return s.now
    83  }
    84  
    85  //睡眠实现时钟。
    86  func (s *Simulated) Sleep(d time.Duration) {
    87  	<-s.After(d)
    88  }
    89  
    90  //在执行时钟之后。
    91  func (s *Simulated) After(d time.Duration) <-chan time.Time {
    92  	after := make(chan time.Time, 1)
    93  	s.insert(d, func() {
    94  		after <- (time.Time{}).Add(time.Duration(s.now))
    95  	})
    96  	return after
    97  }
    98  
    99  func (s *Simulated) insert(d time.Duration, do func()) {
   100  	s.mu.Lock()
   101  	defer s.mu.Unlock()
   102  	s.init()
   103  
   104  	at := s.now + AbsTime(d)
   105  	l, h := 0, len(s.scheduled)
   106  	ll := h
   107  	for l != h {
   108  		m := (l + h) / 2
   109  		if at < s.scheduled[m].at {
   110  			h = m
   111  		} else {
   112  			l = m + 1
   113  		}
   114  	}
   115  	s.scheduled = append(s.scheduled, event{})
   116  	copy(s.scheduled[l+1:], s.scheduled[l:ll])
   117  	s.scheduled[l] = event{do: do, at: at}
   118  	s.cond.Broadcast()
   119  }
   120  
   121  func (s *Simulated) init() {
   122  	if s.cond == nil {
   123  		s.cond = sync.NewCond(&s.mu)
   124  	}
   125  }
   126