github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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  enum {
    17  	debug = 0,
    18  };
    19  
    20  static Timers timers;
    21  static void addtimer(Timer*);
    22  static void dumptimers(int8*);
    23  
    24  // Package time APIs.
    25  // Godoc uses the comments in package time, not these.
    26  
    27  // time.now is implemented in assembly.
    28  
    29  // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
    30  func Sleep(ns int64) {
    31  	runtime·tsleep(ns, "sleep");
    32  }
    33  
    34  // startTimer adds t to the timer heap.
    35  func startTimer(t *Timer) {
    36  	if(raceenabled)
    37  		runtime·racerelease(t);
    38  	runtime·addtimer(t);
    39  }
    40  
    41  // stopTimer removes t from the timer heap if it is there.
    42  // It returns true if t was removed, false if t wasn't even there.
    43  func stopTimer(t *Timer) (stopped bool) {
    44  	stopped = runtime·deltimer(t);
    45  }
    46  
    47  // C runtime.
    48  
    49  static void timerproc(void);
    50  static void siftup(int32);
    51  static void siftdown(int32);
    52  
    53  // Ready the goroutine e.data.
    54  static void
    55  ready(int64 now, Eface e)
    56  {
    57  	USED(now);
    58  
    59  	runtime·ready(e.data);
    60  }
    61  
    62  static FuncVal readyv = {(void(*)(void))ready};
    63  
    64  // Put the current goroutine to sleep for ns nanoseconds.
    65  void
    66  runtime·tsleep(int64 ns, int8 *reason)
    67  {
    68  	Timer t;
    69  
    70  	if(ns <= 0)
    71  		return;
    72  
    73  	t.when = runtime·nanotime() + ns;
    74  	t.period = 0;
    75  	t.fv = &readyv;
    76  	t.arg.data = g;
    77  	runtime·lock(&timers);
    78  	addtimer(&t);
    79  	runtime·park(runtime·unlock, &timers, reason);
    80  }
    81  
    82  static FuncVal timerprocv = {timerproc};
    83  
    84  void
    85  runtime·addtimer(Timer *t)
    86  {
    87  	runtime·lock(&timers);
    88  	addtimer(t);
    89  	runtime·unlock(&timers);
    90  }
    91  
    92  // Add a timer to the heap and start or kick the timer proc
    93  // if the new timer is earlier than any of the others.
    94  static void
    95  addtimer(Timer *t)
    96  {
    97  	int32 n;
    98  	Timer **nt;
    99  
   100  	// when must never be negative; otherwise timerproc will overflow
   101  	// during its delta calculation and never expire other timers.
   102  	if(t->when < 0)
   103  		t->when = (1LL<<63)-1;
   104  
   105  	if(timers.len >= timers.cap) {
   106  		// Grow slice.
   107  		n = 16;
   108  		if(n <= timers.cap)
   109  			n = timers.cap*3 / 2;
   110  		nt = runtime·malloc(n*sizeof nt[0]);
   111  		runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]);
   112  		runtime·free(timers.t);
   113  		timers.t = nt;
   114  		timers.cap = n;
   115  	}
   116  	t->i = timers.len++;
   117  	timers.t[t->i] = t;
   118  	siftup(t->i);
   119  	if(t->i == 0) {
   120  		// siftup moved to top: new earliest deadline.
   121  		if(timers.sleeping) {
   122  			timers.sleeping = false;
   123  			runtime·notewakeup(&timers.waitnote);
   124  		}
   125  		if(timers.rescheduling) {
   126  			timers.rescheduling = false;
   127  			runtime·ready(timers.timerproc);
   128  		}
   129  	}
   130  	if(timers.timerproc == nil) {
   131  		timers.timerproc = runtime·newproc1(&timerprocv, nil, 0, 0, addtimer);
   132  		timers.timerproc->issystem = true;
   133  	}
   134  	if(debug)
   135  		dumptimers("addtimer");
   136  }
   137  
   138  // Delete timer t from the heap.
   139  // Do not need to update the timerproc:
   140  // if it wakes up early, no big deal.
   141  bool
   142  runtime·deltimer(Timer *t)
   143  {
   144  	int32 i;
   145  
   146  	// Dereference t so that any panic happens before the lock is held.
   147  	// Discard result, because t might be moving in the heap.
   148  	i = t->i;
   149  	USED(i);
   150  
   151  	runtime·lock(&timers);
   152  
   153  	// t may not be registered anymore and may have
   154  	// a bogus i (typically 0, if generated by Go).
   155  	// Verify it before proceeding.
   156  	i = t->i;
   157  	if(i < 0 || i >= timers.len || timers.t[i] != t) {
   158  		runtime·unlock(&timers);
   159  		return false;
   160  	}
   161  
   162  	timers.len--;
   163  	if(i == timers.len) {
   164  		timers.t[i] = nil;
   165  	} else {
   166  		timers.t[i] = timers.t[timers.len];
   167  		timers.t[timers.len] = nil;
   168  		timers.t[i]->i = i;
   169  		siftup(i);
   170  		siftdown(i);
   171  	}
   172  	if(debug)
   173  		dumptimers("deltimer");
   174  	runtime·unlock(&timers);
   175  	return true;
   176  }
   177  
   178  // Timerproc runs the time-driven events.
   179  // It sleeps until the next event in the timers heap.
   180  // If addtimer inserts a new earlier event, addtimer
   181  // wakes timerproc early.
   182  static void
   183  timerproc(void)
   184  {
   185  	int64 delta, now;
   186  	Timer *t;
   187  	void (*f)(int64, Eface);
   188  	Eface arg;
   189  
   190  	for(;;) {
   191  		runtime·lock(&timers);
   192  		timers.sleeping = false;
   193  		now = runtime·nanotime();
   194  		for(;;) {
   195  			if(timers.len == 0) {
   196  				delta = -1;
   197  				break;
   198  			}
   199  			t = timers.t[0];
   200  			delta = t->when - now;
   201  			if(delta > 0)
   202  				break;
   203  			if(t->period > 0) {
   204  				// leave in heap but adjust next time to fire
   205  				t->when += t->period * (1 + -delta/t->period);
   206  				siftdown(0);
   207  			} else {
   208  				// remove from heap
   209  				timers.t[0] = timers.t[--timers.len];
   210  				timers.t[0]->i = 0;
   211  				siftdown(0);
   212  				t->i = -1;  // mark as removed
   213  			}
   214  			f = (void*)t->fv->fn;
   215  			arg = t->arg;
   216  			runtime·unlock(&timers);
   217  			if(raceenabled)
   218  				runtime·raceacquire(t);
   219  			f(now, arg);
   220  			runtime·lock(&timers);
   221  		}
   222  		if(delta < 0) {
   223  			// No timers left - put goroutine to sleep.
   224  			timers.rescheduling = true;
   225  			runtime·park(runtime·unlock, &timers, "timer goroutine (idle)");
   226  			continue;
   227  		}
   228  		// At least one timer pending.  Sleep until then.
   229  		timers.sleeping = true;
   230  		runtime·noteclear(&timers.waitnote);
   231  		runtime·unlock(&timers);
   232  		runtime·notetsleepg(&timers.waitnote, delta);
   233  	}
   234  }
   235  
   236  // heap maintenance algorithms.
   237  
   238  static void
   239  siftup(int32 i)
   240  {
   241  	int32 p;
   242  	int64 when;
   243  	Timer **t, *tmp;
   244  
   245  	t = timers.t;
   246  	when = t[i]->when;
   247  	tmp = t[i];
   248  	while(i > 0) {
   249  		p = (i-1)/4;  // parent
   250  		if(when >= t[p]->when)
   251  			break;
   252  		t[i] = t[p];
   253  		t[i]->i = i;
   254  		t[p] = tmp;
   255  		tmp->i = p;
   256  		i = p;
   257  	}
   258  }
   259  
   260  static void
   261  siftdown(int32 i)
   262  {
   263  	int32 c, c3, len;
   264  	int64 when, w, w3;
   265  	Timer **t, *tmp;
   266  
   267  	t = timers.t;
   268  	len = timers.len;
   269  	when = t[i]->when;
   270  	tmp = t[i];
   271  	for(;;) {
   272  		c = i*4 + 1;  // left child
   273  		c3 = c + 2;  // mid child
   274  		if(c >= len) {
   275  			break;
   276  		}
   277  		w = t[c]->when;
   278  		if(c+1 < len && t[c+1]->when < w) {
   279  			w = t[c+1]->when;
   280  			c++;
   281  		}
   282  		if(c3 < len) {
   283  			w3 = t[c3]->when;
   284  			if(c3+1 < len && t[c3+1]->when < w3) {
   285  				w3 = t[c3+1]->when;
   286  				c3++;
   287  			}
   288  			if(w3 < w) {
   289  				w = w3;
   290  				c = c3;
   291  			}
   292  		}
   293  		if(w >= when)
   294  			break;
   295  		t[i] = t[c];
   296  		t[i]->i = i;
   297  		t[c] = tmp;
   298  		tmp->i = c;
   299  		i = c;
   300  	}
   301  }
   302  
   303  static void
   304  dumptimers(int8 *msg)
   305  {
   306  	Timer *t;
   307  	int32 i;
   308  
   309  	runtime·printf("timers: %s\n", msg);
   310  	for(i = 0; i < timers.len; i++) {
   311  		t = timers.t[i];
   312  		runtime·printf("\t%d\t%p:\ti %d when %D period %D fn %p\n",
   313  				i, t, t->i, t->when, t->period, t->fv->fn);
   314  	}
   315  	runtime·printf("\n");
   316  }