github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/runtime/time.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Time-related runtime and pieces of package time.
     6  
     7  package runtime
     8  
     9  import "unsafe"
    10  
    11  // Package time knows the layout of this structure.
    12  // If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
    13  // For GOOS=nacl, package syscall knows the layout of this structure.
    14  // If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
    15  type timer struct {
    16  	i int // heap index
    17  
    18  	// Timer wakes up at when, and then at when+period, ... (period > 0 only)
    19  	// each time calling f(arg, now) in the timer goroutine, so f must be
    20  	// a well-behaved function and not block.
    21  	when   int64
    22  	period int64
    23  	f      func(interface{}, uintptr)
    24  	arg    interface{}
    25  	seq    uintptr
    26  }
    27  
    28  var timers struct {
    29  	lock         mutex
    30  	gp           *g
    31  	created      bool
    32  	sleeping     bool
    33  	rescheduling bool
    34  	sleepUntil   int64
    35  	waitnote     note
    36  	t            []*timer
    37  }
    38  
    39  // nacl fake time support - time in nanoseconds since 1970
    40  var faketime int64
    41  
    42  // Package time APIs.
    43  // Godoc uses the comments in package time, not these.
    44  
    45  // time.now is implemented in assembly.
    46  
    47  // timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
    48  //go:linkname timeSleep time.Sleep
    49  func timeSleep(ns int64) {
    50  	if ns <= 0 {
    51  		return
    52  	}
    53  
    54  	t := getg().timer
    55  	if t == nil {
    56  		t = new(timer)
    57  		getg().timer = t
    58  	}
    59  	*t = timer{}
    60  	t.when = nanotime() + ns
    61  	t.f = goroutineReady
    62  	t.arg = getg()
    63  	lock(&timers.lock)
    64  	addtimerLocked(t)
    65  	goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
    66  }
    67  
    68  // startTimer adds t to the timer heap.
    69  //go:linkname startTimer time.startTimer
    70  func startTimer(t *timer) {
    71  	if raceenabled {
    72  		racerelease(unsafe.Pointer(t))
    73  	}
    74  	addtimer(t)
    75  }
    76  
    77  // stopTimer removes t from the timer heap if it is there.
    78  // It returns true if t was removed, false if t wasn't even there.
    79  //go:linkname stopTimer time.stopTimer
    80  func stopTimer(t *timer) bool {
    81  	return deltimer(t)
    82  }
    83  
    84  // Go runtime.
    85  
    86  // Ready the goroutine arg.
    87  func goroutineReady(arg interface{}, seq uintptr) {
    88  	goready(arg.(*g), 0)
    89  }
    90  
    91  func addtimer(t *timer) {
    92  	lock(&timers.lock)
    93  	addtimerLocked(t)
    94  	unlock(&timers.lock)
    95  }
    96  
    97  // Add a timer to the heap and start or kick timerproc if the new timer is
    98  // earlier than any of the others.
    99  // Timers are locked.
   100  func addtimerLocked(t *timer) {
   101  	// when must never be negative; otherwise timerproc will overflow
   102  	// during its delta calculation and never expire other runtime timers.
   103  	if t.when < 0 {
   104  		t.when = 1<<63 - 1
   105  	}
   106  	t.i = len(timers.t)
   107  	timers.t = append(timers.t, t)
   108  	siftupTimer(t.i)
   109  	if t.i == 0 {
   110  		// siftup moved to top: new earliest deadline.
   111  		if timers.sleeping {
   112  			timers.sleeping = false
   113  			notewakeup(&timers.waitnote)
   114  		}
   115  		if timers.rescheduling {
   116  			timers.rescheduling = false
   117  			goready(timers.gp, 0)
   118  		}
   119  	}
   120  	if !timers.created {
   121  		timers.created = true
   122  		go timerproc()
   123  	}
   124  }
   125  
   126  // Delete timer t from the heap.
   127  // Do not need to update the timerproc: if it wakes up early, no big deal.
   128  func deltimer(t *timer) bool {
   129  	// Dereference t so that any panic happens before the lock is held.
   130  	// Discard result, because t might be moving in the heap.
   131  	_ = t.i
   132  
   133  	lock(&timers.lock)
   134  	// t may not be registered anymore and may have
   135  	// a bogus i (typically 0, if generated by Go).
   136  	// Verify it before proceeding.
   137  	i := t.i
   138  	last := len(timers.t) - 1
   139  	if i < 0 || i > last || timers.t[i] != t {
   140  		unlock(&timers.lock)
   141  		return false
   142  	}
   143  	if i != last {
   144  		timers.t[i] = timers.t[last]
   145  		timers.t[i].i = i
   146  	}
   147  	timers.t[last] = nil
   148  	timers.t = timers.t[:last]
   149  	if i != last {
   150  		siftupTimer(i)
   151  		siftdownTimer(i)
   152  	}
   153  	unlock(&timers.lock)
   154  	return true
   155  }
   156  
   157  // Timerproc runs the time-driven events.
   158  // It sleeps until the next event in the timers heap.
   159  // If addtimer inserts a new earlier event, it wakes timerproc early.
   160  func timerproc() {
   161  	timers.gp = getg()
   162  	for {
   163  		lock(&timers.lock)
   164  		timers.sleeping = false
   165  		now := nanotime()
   166  		delta := int64(-1)
   167  		for {
   168  			if len(timers.t) == 0 {
   169  				delta = -1
   170  				break
   171  			}
   172  			t := timers.t[0]
   173  			delta = t.when - now
   174  			if delta > 0 {
   175  				break
   176  			}
   177  			if t.period > 0 {
   178  				// leave in heap but adjust next time to fire
   179  				t.when += t.period * (1 + -delta/t.period)
   180  				siftdownTimer(0)
   181  			} else {
   182  				// remove from heap
   183  				last := len(timers.t) - 1
   184  				if last > 0 {
   185  					timers.t[0] = timers.t[last]
   186  					timers.t[0].i = 0
   187  				}
   188  				timers.t[last] = nil
   189  				timers.t = timers.t[:last]
   190  				if last > 0 {
   191  					siftdownTimer(0)
   192  				}
   193  				t.i = -1 // mark as removed
   194  			}
   195  			f := t.f
   196  			arg := t.arg
   197  			seq := t.seq
   198  			unlock(&timers.lock)
   199  			if raceenabled {
   200  				raceacquire(unsafe.Pointer(t))
   201  			}
   202  			f(arg, seq)
   203  			lock(&timers.lock)
   204  		}
   205  		if delta < 0 || faketime > 0 {
   206  			// No timers left - put goroutine to sleep.
   207  			timers.rescheduling = true
   208  			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
   209  			continue
   210  		}
   211  		// At least one timer pending. Sleep until then.
   212  		timers.sleeping = true
   213  		timers.sleepUntil = now + delta
   214  		noteclear(&timers.waitnote)
   215  		unlock(&timers.lock)
   216  		notetsleepg(&timers.waitnote, delta)
   217  	}
   218  }
   219  
   220  func timejump() *g {
   221  	if faketime == 0 {
   222  		return nil
   223  	}
   224  
   225  	lock(&timers.lock)
   226  	if !timers.created || len(timers.t) == 0 {
   227  		unlock(&timers.lock)
   228  		return nil
   229  	}
   230  
   231  	var gp *g
   232  	if faketime < timers.t[0].when {
   233  		faketime = timers.t[0].when
   234  		if timers.rescheduling {
   235  			timers.rescheduling = false
   236  			gp = timers.gp
   237  		}
   238  	}
   239  	unlock(&timers.lock)
   240  	return gp
   241  }
   242  
   243  // Heap maintenance algorithms.
   244  
   245  func siftupTimer(i int) {
   246  	t := timers.t
   247  	when := t[i].when
   248  	tmp := t[i]
   249  	for i > 0 {
   250  		p := (i - 1) / 4 // parent
   251  		if when >= t[p].when {
   252  			break
   253  		}
   254  		t[i] = t[p]
   255  		t[i].i = i
   256  		t[p] = tmp
   257  		t[p].i = p
   258  		i = p
   259  	}
   260  }
   261  
   262  func siftdownTimer(i int) {
   263  	t := timers.t
   264  	n := len(t)
   265  	when := t[i].when
   266  	tmp := t[i]
   267  	for {
   268  		c := i*4 + 1 // left child
   269  		c3 := c + 2  // mid child
   270  		if c >= n {
   271  			break
   272  		}
   273  		w := t[c].when
   274  		if c+1 < n && t[c+1].when < w {
   275  			w = t[c+1].when
   276  			c++
   277  		}
   278  		if c3 < n {
   279  			w3 := t[c3].when
   280  			if c3+1 < n && t[c3+1].when < w3 {
   281  				w3 = t[c3+1].when
   282  				c3++
   283  			}
   284  			if w3 < w {
   285  				w = w3
   286  				c = c3
   287  			}
   288  		}
   289  		if w >= when {
   290  			break
   291  		}
   292  		t[i] = t[c]
   293  		t[i].i = i
   294  		t[c] = tmp
   295  		t[c].i = c
   296  		i = c
   297  	}
   298  }
   299  
   300  // Entry points for net, time to call nanotime.
   301  
   302  //go:linkname poll_runtimeNano internal/poll.runtimeNano
   303  func poll_runtimeNano() int64 {
   304  	return nanotime()
   305  }
   306  
   307  //go:linkname time_runtimeNano time.runtimeNano
   308  func time_runtimeNano() int64 {
   309  	return nanotime()
   310  }
   311  
   312  var startNano int64 = nanotime()