github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/time.goc (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 time
     8  
     9  #include "runtime.h"
    10  #include "defs_GOOS_GOARCH.h"
    11  #include "os_GOOS.h"
    12  #include "arch_GOARCH.h"
    13  #include "malloc.h"
    14  #include "race.h"
    15  
    16  static Timers timers;
    17  static void addtimer(Timer*);
    18  
    19  // Package time APIs.
    20  // Godoc uses the comments in package time, not these.
    21  
    22  // time.now is implemented in assembly.
    23  
    24  // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
    25  func Sleep(ns int64) {
    26  	runtime·tsleep(ns, "sleep");
    27  }
    28  
    29  // startTimer adds t to the timer heap.
    30  func startTimer(t *Timer) {
    31  	if(raceenabled)
    32  		runtime·racerelease(t);
    33  	runtime·addtimer(t);
    34  }
    35  
    36  // stopTimer removes t from the timer heap if it is there.
    37  // It returns true if t was removed, false if t wasn't even there.
    38  func stopTimer(t *Timer) (stopped bool) {
    39  	stopped = runtime·deltimer(t);
    40  }
    41  
    42  // C runtime.
    43  
    44  static void timerproc(void);
    45  static void siftup(int32);
    46  static void siftdown(int32);
    47  
    48  // Ready the goroutine e.data.
    49  static void
    50  ready(int64 now, Eface e)
    51  {
    52  	USED(now);
    53  
    54  	runtime·ready(e.data);
    55  }
    56  
    57  static FuncVal readyv = {(void(*)(void))ready};
    58  
    59  // Put the current goroutine to sleep for ns nanoseconds.
    60  void
    61  runtime·tsleep(int64 ns, int8 *reason)
    62  {
    63  	Timer t;
    64  
    65  	if(ns <= 0)
    66  		return;
    67  
    68  	t.when = runtime·nanotime() + ns;
    69  	t.period = 0;
    70  	t.fv = &readyv;
    71  	t.arg.data = g;
    72  	runtime·lock(&timers);
    73  	addtimer(&t);
    74  	runtime·park(runtime·unlock, &timers, reason);
    75  }
    76  
    77  static FuncVal timerprocv = {timerproc};
    78  
    79  void
    80  runtime·addtimer(Timer *t)
    81  {
    82  	runtime·lock(&timers);
    83  	addtimer(t);
    84  	runtime·unlock(&timers);
    85  }
    86  
    87  // Add a timer to the heap and start or kick the timer proc
    88  // if the new timer is earlier than any of the others.
    89  static void
    90  addtimer(Timer *t)
    91  {
    92  	int32 n;
    93  	Timer **nt;
    94  
    95  	if(timers.len >= timers.cap) {
    96  		// Grow slice.
    97  		n = 16;
    98  		if(n <= timers.cap)
    99  			n = timers.cap*3 / 2;
   100  		nt = runtime·malloc(n*sizeof nt[0]);
   101  		runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]);
   102  		runtime·free(timers.t);
   103  		timers.t = nt;
   104  		timers.cap = n;
   105  	}
   106  	t->i = timers.len++;
   107  	timers.t[t->i] = t;
   108  	siftup(t->i);
   109  	if(t->i == 0) {
   110  		// siftup moved to top: new earliest deadline.
   111  		if(timers.sleeping) {
   112  			timers.sleeping = false;
   113  			runtime·notewakeup(&timers.waitnote);
   114  		}
   115  		if(timers.rescheduling) {
   116  			timers.rescheduling = false;
   117  			runtime·ready(timers.timerproc);
   118  		}
   119  	}
   120  	if(timers.timerproc == nil) {
   121  		timers.timerproc = runtime·newproc1(&timerprocv, nil, 0, 0, addtimer);
   122  		timers.timerproc->issystem = true;
   123  	}
   124  }
   125  
   126  // Delete timer t from the heap.
   127  // Do not need to update the timerproc:
   128  // if it wakes up early, no big deal.
   129  bool
   130  runtime·deltimer(Timer *t)
   131  {
   132  	int32 i;
   133  
   134  	runtime·lock(&timers);
   135  
   136  	// t may not be registered anymore and may have
   137  	// a bogus i (typically 0, if generated by Go).
   138  	// Verify it before proceeding.
   139  	i = t->i;
   140  	if(i < 0 || i >= timers.len || timers.t[i] != t) {
   141  		runtime·unlock(&timers);
   142  		return false;
   143  	}
   144  
   145  	timers.len--;
   146  	if(i == timers.len) {
   147  		timers.t[i] = nil;
   148  	} else {
   149  		timers.t[i] = timers.t[timers.len];
   150  		timers.t[timers.len] = nil;
   151  		timers.t[i]->i = i;
   152  		siftup(i);
   153  		siftdown(i);
   154  	}
   155  	runtime·unlock(&timers);
   156  	return true;
   157  }
   158  
   159  // Timerproc runs the time-driven events.
   160  // It sleeps until the next event in the timers heap.
   161  // If addtimer inserts a new earlier event, addtimer
   162  // wakes timerproc early.
   163  static void
   164  timerproc(void)
   165  {
   166  	int64 delta, now;
   167  	Timer *t;
   168  	void (*f)(int64, Eface);
   169  	Eface arg;
   170  
   171  	for(;;) {
   172  		runtime·lock(&timers);
   173  		now = runtime·nanotime();
   174  		for(;;) {
   175  			if(timers.len == 0) {
   176  				delta = -1;
   177  				break;
   178  			}
   179  			t = timers.t[0];
   180  			delta = t->when - now;
   181  			if(delta > 0)
   182  				break;
   183  			if(t->period > 0) {
   184  				// leave in heap but adjust next time to fire
   185  				t->when += t->period * (1 + -delta/t->period);
   186  				siftdown(0);
   187  			} else {
   188  				// remove from heap
   189  				timers.t[0] = timers.t[--timers.len];
   190  				timers.t[0]->i = 0;
   191  				siftdown(0);
   192  				t->i = -1;  // mark as removed
   193  			}
   194  			f = (void*)t->fv->fn;
   195  			arg = t->arg;
   196  			runtime·unlock(&timers);
   197  			if(raceenabled)
   198  				runtime·raceacquire(t);
   199  			f(now, arg);
   200  			runtime·lock(&timers);
   201  		}
   202  		if(delta < 0) {
   203  			// No timers left - put goroutine to sleep.
   204  			timers.rescheduling = true;
   205  			runtime·park(runtime·unlock, &timers, "timer goroutine (idle)");
   206  			continue;
   207  		}
   208  		// At least one timer pending.  Sleep until then.
   209  		timers.sleeping = true;
   210  		runtime·noteclear(&timers.waitnote);
   211  		runtime·unlock(&timers);
   212  		runtime·entersyscallblock();
   213  		runtime·notetsleep(&timers.waitnote, delta);
   214  		runtime·exitsyscall();
   215  	}
   216  }
   217  
   218  // heap maintenance algorithms.
   219  
   220  static void
   221  siftup(int32 i)
   222  {
   223  	int32 p;
   224  	Timer **t, *tmp;
   225  
   226  	t = timers.t;
   227  	while(i > 0) {
   228  		p = (i-1)/2;  // parent
   229  		if(t[i]->when >= t[p]->when)
   230  			break;
   231  		tmp = t[i];
   232  		t[i] = t[p];
   233  		t[p] = tmp;
   234  		t[i]->i = i;
   235  		t[p]->i = p;
   236  		i = p;
   237  	}
   238  }
   239  
   240  static void
   241  siftdown(int32 i)
   242  {
   243  	int32 c, len;
   244  	Timer **t, *tmp;
   245  
   246  	t = timers.t;
   247  	len = timers.len;
   248  	for(;;) {
   249  		c = i*2 + 1;  // left child
   250  		if(c >= len) {
   251  			break;
   252  		}
   253  		if(c+1 < len && t[c+1]->when < t[c]->when)
   254  			c++;
   255  		if(t[c]->when >= t[i]->when)
   256  			break;
   257  		tmp = t[i];
   258  		t[i] = t[c];
   259  		t[c] = tmp;
   260  		t[i]->i = i;
   261  		t[c]->i = c;
   262  		i = c;
   263  	}
   264  }