...

Source file src/github.com/thales-e-security/pool/timer.go

Documentation: github.com/thales-e-security/pool

     1  /*
     2  Copyright 2017 Google Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  
    16  Modified by Duncan Jones to remove the external dependency.
    17  */
    18  
    19  // Package timer provides various enhanced timer functions.
    20  package pool
    21  
    22  import (
    23  	"sync"
    24  	"time"
    25  )
    26  
    27  // Out-of-band messages
    28  type typeAction int
    29  
    30  const (
    31  	timerStop typeAction = iota
    32  	timerReset
    33  	timerTrigger
    34  )
    35  
    36  /*
    37  Timer provides timer functionality that can be controlled
    38  by the user. You start the timer by providing it a callback function,
    39  which it will call at the specified interval.
    40  
    41  	var t = timer.NewTimer(1e9)
    42  	t.Start(KeepHouse)
    43  
    44  	func KeepHouse() {
    45  		// do house keeping work
    46  	}
    47  
    48  You can stop the timer by calling t.Stop, which is guaranteed to
    49  wait if KeepHouse is being executed.
    50  
    51  You can create an untimely trigger by calling t.Trigger. You can also
    52  schedule an untimely trigger by calling t.TriggerAfter.
    53  
    54  The timer interval can be changed on the fly by calling t.SetInterval.
    55  A zero value interval will cause the timer to wait indefinitely, and it
    56  will react only to an explicit Trigger or Stop.
    57  */
    58  type Timer struct {
    59  	interval AtomicDuration
    60  
    61  	// state management
    62  	mu      sync.Mutex
    63  	running bool
    64  
    65  	// msg is used for out-of-band messages
    66  	msg chan typeAction
    67  }
    68  
    69  // NewTimer creates a new Timer object
    70  func NewTimer(interval time.Duration) *Timer {
    71  	tm := &Timer{
    72  		msg: make(chan typeAction),
    73  	}
    74  	tm.interval.Set(interval)
    75  	return tm
    76  }
    77  
    78  // Start starts the timer.
    79  func (tm *Timer) Start(keephouse func()) {
    80  	tm.mu.Lock()
    81  	defer tm.mu.Unlock()
    82  	if tm.running {
    83  		return
    84  	}
    85  	tm.running = true
    86  	go tm.run(keephouse)
    87  }
    88  
    89  func (tm *Timer) run(keephouse func()) {
    90  	var timer *time.Timer
    91  	for {
    92  		var ch <-chan time.Time
    93  		interval := tm.interval.Get()
    94  		if interval > 0 {
    95  			timer = time.NewTimer(interval)
    96  			ch = timer.C
    97  		}
    98  		select {
    99  		case action := <-tm.msg:
   100  			if timer != nil {
   101  				timer.Stop()
   102  				timer = nil
   103  			}
   104  			switch action {
   105  			case timerStop:
   106  				return
   107  			case timerReset:
   108  				continue
   109  			}
   110  		case <-ch:
   111  		}
   112  		keephouse()
   113  	}
   114  }
   115  
   116  // SetInterval changes the wait interval.
   117  // It will cause the timer to restart the wait.
   118  func (tm *Timer) SetInterval(ns time.Duration) {
   119  	tm.interval.Set(ns)
   120  	tm.mu.Lock()
   121  	defer tm.mu.Unlock()
   122  	if tm.running {
   123  		tm.msg <- timerReset
   124  	}
   125  }
   126  
   127  // Trigger will cause the timer to immediately execute the keephouse function.
   128  // It will then cause the timer to restart the wait.
   129  func (tm *Timer) Trigger() {
   130  	tm.mu.Lock()
   131  	defer tm.mu.Unlock()
   132  	if tm.running {
   133  		tm.msg <- timerTrigger
   134  	}
   135  }
   136  
   137  // TriggerAfter waits for the specified duration and triggers the next event.
   138  func (tm *Timer) TriggerAfter(duration time.Duration) {
   139  	go func() {
   140  		time.Sleep(duration)
   141  		tm.Trigger()
   142  	}()
   143  }
   144  
   145  // Stop will stop the timer. It guarantees that the timer will not execute
   146  // any more calls to keephouse once it has returned.
   147  func (tm *Timer) Stop() {
   148  	tm.mu.Lock()
   149  	defer tm.mu.Unlock()
   150  	if tm.running {
   151  		tm.msg <- timerStop
   152  		tm.running = false
   153  	}
   154  }
   155  
   156  // Interval returns the current interval.
   157  func (tm *Timer) Interval() time.Duration {
   158  	return tm.interval.Get()
   159  }
   160  

View as plain text