* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
		
			
				
	
	
		
			122 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2013, Google Inc. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package sync2
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| )
 | |
| 
 | |
| // These are the three predefined states of a service.
 | |
| const (
 | |
| 	SERVICE_STOPPED = iota
 | |
| 	SERVICE_RUNNING
 | |
| 	SERVICE_SHUTTING_DOWN
 | |
| )
 | |
| 
 | |
| var stateNames = []string{
 | |
| 	"Stopped",
 | |
| 	"Running",
 | |
| 	"ShuttingDown",
 | |
| }
 | |
| 
 | |
| // ServiceManager manages the state of a service through its lifecycle.
 | |
| type ServiceManager struct {
 | |
| 	mu    sync.Mutex
 | |
| 	wg    sync.WaitGroup
 | |
| 	err   error // err is the error returned from the service function.
 | |
| 	state AtomicInt64
 | |
| 	// shutdown is created when the service starts and is closed when the service
 | |
| 	// enters the SERVICE_SHUTTING_DOWN state.
 | |
| 	shutdown chan struct{}
 | |
| }
 | |
| 
 | |
| // Go tries to change the state from SERVICE_STOPPED to SERVICE_RUNNING.
 | |
| //
 | |
| // If the current state is not SERVICE_STOPPED (already running), it returns
 | |
| // false immediately.
 | |
| //
 | |
| // On successful transition, it launches the service as a goroutine and returns
 | |
| // true. The service function is responsible for returning on its own when
 | |
| // requested, either by regularly checking svc.IsRunning(), or by waiting for
 | |
| // the svc.ShuttingDown channel to be closed.
 | |
| //
 | |
| // When the service func returns, the state is reverted to SERVICE_STOPPED.
 | |
| func (svm *ServiceManager) Go(service func(svc *ServiceContext) error) bool {
 | |
| 	svm.mu.Lock()
 | |
| 	defer svm.mu.Unlock()
 | |
| 	if !svm.state.CompareAndSwap(SERVICE_STOPPED, SERVICE_RUNNING) {
 | |
| 		return false
 | |
| 	}
 | |
| 	svm.wg.Add(1)
 | |
| 	svm.err = nil
 | |
| 	svm.shutdown = make(chan struct{})
 | |
| 	go func() {
 | |
| 		svm.err = service(&ServiceContext{ShuttingDown: svm.shutdown})
 | |
| 		svm.state.Set(SERVICE_STOPPED)
 | |
| 		svm.wg.Done()
 | |
| 	}()
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Stop tries to change the state from SERVICE_RUNNING to SERVICE_SHUTTING_DOWN.
 | |
| // If the current state is not SERVICE_RUNNING, it returns false immediately.
 | |
| // On successul transition, it waits for the service to finish, and returns true.
 | |
| // You are allowed to Go() again after a Stop().
 | |
| func (svm *ServiceManager) Stop() bool {
 | |
| 	svm.mu.Lock()
 | |
| 	defer svm.mu.Unlock()
 | |
| 	if !svm.state.CompareAndSwap(SERVICE_RUNNING, SERVICE_SHUTTING_DOWN) {
 | |
| 		return false
 | |
| 	}
 | |
| 	// Signal the service that we've transitioned to SERVICE_SHUTTING_DOWN.
 | |
| 	close(svm.shutdown)
 | |
| 	svm.shutdown = nil
 | |
| 	svm.wg.Wait()
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Wait waits for the service to terminate if it's currently running.
 | |
| func (svm *ServiceManager) Wait() {
 | |
| 	svm.wg.Wait()
 | |
| }
 | |
| 
 | |
| // Join waits for the service to terminate and returns the value returned by the
 | |
| // service function.
 | |
| func (svm *ServiceManager) Join() error {
 | |
| 	svm.wg.Wait()
 | |
| 	return svm.err
 | |
| }
 | |
| 
 | |
| // State returns the current state of the service.
 | |
| // This should only be used to report the current state.
 | |
| func (svm *ServiceManager) State() int64 {
 | |
| 	return svm.state.Get()
 | |
| }
 | |
| 
 | |
| // StateName returns the name of the current state.
 | |
| func (svm *ServiceManager) StateName() string {
 | |
| 	return stateNames[svm.State()]
 | |
| }
 | |
| 
 | |
| // ServiceContext is passed into the service function to give it access to
 | |
| // information about the running service.
 | |
| type ServiceContext struct {
 | |
| 	// ShuttingDown is a channel that the service can select on to be notified
 | |
| 	// when it should shut down. The channel is closed when the state transitions
 | |
| 	// from SERVICE_RUNNING to SERVICE_SHUTTING_DOWN.
 | |
| 	ShuttingDown chan struct{}
 | |
| }
 | |
| 
 | |
| // IsRunning returns true if the ServiceContext.ShuttingDown channel has not
 | |
| // been closed yet.
 | |
| func (svc *ServiceContext) IsRunning() bool {
 | |
| 	select {
 | |
| 	case <-svc.ShuttingDown:
 | |
| 		return false
 | |
| 	default:
 | |
| 		return true
 | |
| 	}
 | |
| }
 |