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