From 844e911129dbebd80ff57ec68336a845b52c5eff Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 May 2016 10:24:16 +0200 Subject: [PATCH 01/10] internal/debug: rename debug_trace to debug_goTrace Reduces confusion with EVM execution tracing methods. --- internal/debug/api.go | 4 ++-- internal/web3ext/web3ext.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/debug/api.go b/internal/debug/api.go index 2cb264040d..a0bff27680 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -131,9 +131,9 @@ func (h *HandlerT) StopCPUProfile() error { return nil } -// Trace turns on tracing for nsec seconds and writes +// GoTrace turns on tracing for nsec seconds and writes // trace data to file. -func (h *HandlerT) Trace(file string, nsec uint) error { +func (h *HandlerT) GoTrace(file string, nsec uint) error { if err := h.StartTrace(file); err != nil { return err } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 14700b05c6..2a4698ee7f 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -366,8 +366,8 @@ web3._extend({ params: 0 }), new web3._extend.Method({ - name: 'trace', - call: 'debug_trace', + name: 'goTrace', + call: 'debug_goTrace', params: 2 }), new web3._extend.Method({ From ae9ed5c420dc7babc5754fbb88c7bfe893d5dcf0 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 May 2016 11:15:05 +0200 Subject: [PATCH 02/10] internal/debug: also rename debug_startTrace to debug_startGoTrace This was missing from the previous change. --- internal/debug/api.go | 6 +++--- internal/debug/flags.go | 4 ++-- internal/debug/trace.go | 6 +++--- internal/debug/trace_fallback.go | 4 ++-- internal/web3ext/web3ext.go | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/debug/api.go b/internal/debug/api.go index a0bff27680..96091541b5 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -51,7 +51,7 @@ type HandlerT struct { traceFile string } -// Verbosity sets the glog verbosity floor. +// Verbosity sets the glog verbosity ceiling. // The verbosity of individual packages and source files // can be raised using Vmodule. func (*HandlerT) Verbosity(level int) { @@ -134,11 +134,11 @@ func (h *HandlerT) StopCPUProfile() error { // GoTrace turns on tracing for nsec seconds and writes // trace data to file. func (h *HandlerT) GoTrace(file string, nsec uint) error { - if err := h.StartTrace(file); err != nil { + if err := h.StartGoTrace(file); err != nil { return err } time.Sleep(time.Duration(nsec) * time.Second) - h.StopTrace() + h.StopGoTrace() return nil } diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 76f32561ad..5b1a9b23c4 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -89,7 +89,7 @@ func Setup(ctx *cli.Context) error { runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) Handler.SetBlockProfileRate(ctx.GlobalInt(blockprofilerateFlag.Name)) if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { - if err := Handler.StartTrace(traceFile); err != nil { + if err := Handler.StartGoTrace(traceFile); err != nil { return err } } @@ -114,5 +114,5 @@ func Setup(ctx *cli.Context) error { // respective file. func Exit() { Handler.StopCPUProfile() - Handler.StopTrace() + Handler.StopGoTrace() } diff --git a/internal/debug/trace.go b/internal/debug/trace.go index 45637977a8..c0cf921ff0 100644 --- a/internal/debug/trace.go +++ b/internal/debug/trace.go @@ -27,8 +27,8 @@ import ( "github.com/ethereum/go-ethereum/logger/glog" ) -// StartTrace turns on tracing, writing to the given file. -func (h *HandlerT) StartTrace(file string) error { +// StartGoTrace turns on tracing, writing to the given file. +func (h *HandlerT) StartGoTrace(file string) error { h.mu.Lock() defer h.mu.Unlock() if h.traceW != nil { @@ -49,7 +49,7 @@ func (h *HandlerT) StartTrace(file string) error { } // StopTrace stops an ongoing trace. -func (h *HandlerT) StopTrace() error { +func (h *HandlerT) StopGoTrace() error { h.mu.Lock() defer h.mu.Unlock() trace.Stop() diff --git a/internal/debug/trace_fallback.go b/internal/debug/trace_fallback.go index 3199459259..4118ff4087 100644 --- a/internal/debug/trace_fallback.go +++ b/internal/debug/trace_fallback.go @@ -22,10 +22,10 @@ package debug import "errors" -func (*HandlerT) StartTrace(string) error { +func (*HandlerT) StartGoTrace(string) error { return errors.New("tracing is not supported on Go < 1.5") } -func (*HandlerT) StopTrace() error { +func (*HandlerT) StopGoTrace() error { return errors.New("tracing is not supported on Go < 1.5") } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 2a4698ee7f..64c1b5044b 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -371,13 +371,13 @@ web3._extend({ params: 2 }), new web3._extend.Method({ - name: 'startTrace', - call: 'debug_startTrace', + name: 'startGoTrace', + call: 'debug_startGoTrace', params: 1 }), new web3._extend.Method({ - name: 'stopTrace', - call: 'debug_stopTrace', + name: 'stopGoTrace', + call: 'debug_stopGoTrace', params: 0 }), new web3._extend.Method({ From 130bccc7630a6f6ec7990900bc9dc9bce410a6ad Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 May 2016 11:04:52 +0200 Subject: [PATCH 03/10] cmd/utils: flush trace and CPU profile data when force-qutting Also reduce log messages a little bit. --- cmd/utils/cmd.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index d331f762f6..9e2b14f567 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -73,15 +73,13 @@ func StartNode(stack *node.Node) { <-sigc glog.V(logger.Info).Infoln("Got interrupt, shutting down...") go stack.Stop() - logger.Flush() for i := 10; i > 0; i-- { <-sigc if i > 1 { - glog.V(logger.Info).Infoln("Already shutting down, please be patient.") - glog.V(logger.Info).Infoln("Interrupt", i-1, "more times to induce panic.") + glog.V(logger.Info).Infof("Already shutting down, interrupt %d more times for panic.", i-1) } } - glog.V(logger.Error).Infof("Force quitting: this might not end so well.") + debug.Exit() // ensure trace and CPU profile data is flushed. debug.LoudPanic("boom") }() } From d79f2f26569842121e6fafa9b3dbf48c2e589724 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Wed, 4 May 2016 13:40:07 +0200 Subject: [PATCH 04/10] node: start RPC/WS interface on localhost by default --- node/api.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/node/api.go b/node/api.go index f199a8d3d3..9b2be9c2e4 100644 --- a/node/api.go +++ b/node/api.go @@ -68,7 +68,11 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st } if host == nil { - host = &api.node.httpHost + h := common.DefaultHTTPHost + if api.node.httpHost != "" { + h = api.node.httpHost + } + host = &h } if port == nil { port = rpc.NewHexNumber(api.node.httpPort) @@ -113,7 +117,11 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr } if host == nil { - host = &api.node.wsHost + h := common.DefaultWSHost + if api.node.wsHost != "" { + h = api.node.wsHost + } + host = &h } if port == nil { port = rpc.NewHexNumber(api.node.wsPort) From 6a00a3ade157a08b36af304ae11849fa7f9fe6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 6 May 2016 16:56:22 +0300 Subject: [PATCH 05/10] Makefile: go build instead of install (solves cross compile issues) --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2b553299f6..c2fb9bb354 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ GOBIN = build/bin GO ?= latest geth: - build/env.sh go install -v $(shell build/flags.sh) ./cmd/geth + build/env.sh go build -i -v $(shell build/flags.sh) -o $(GOBIN)/geth ./cmd/geth @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." @@ -103,7 +103,9 @@ evm: @echo "Run \"$(GOBIN)/evm to start the evm." all: - build/env.sh go install -v $(shell build/flags.sh) ./... + for cmd in `ls ./cmd/`; do \ + build/env.sh go build -i -v $(shell build/flags.sh) -o $(GOBIN)/$$cmd ./cmd/$$cmd; \ + done test: all build/env.sh go test ./... From c89f4352d06b0cf7ea344782b3243e4b57565fe3 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 8 May 2016 01:23:07 +0200 Subject: [PATCH 06/10] build: add CI scripts for windows --- build/win-ci-compile.bat | 26 ++++++++++++++++++++++++++ build/win-ci-test.bat | 15 +++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 build/win-ci-compile.bat create mode 100644 build/win-ci-test.bat diff --git a/build/win-ci-compile.bat b/build/win-ci-compile.bat new file mode 100644 index 0000000000..5750990bf0 --- /dev/null +++ b/build/win-ci-compile.bat @@ -0,0 +1,26 @@ +@echo off +if not exist .\build\win-ci-compile.bat ( + echo This script must be run from the root of the repository. + exit /b +) +if not defined GOPATH ( + echo GOPATH is not set. + exit /b +) + +set GOPATH=%GOPATH%;%cd%\Godeps\_workspace +set GOBIN=%cd%\build\bin + +rem set gitCommit when running from a Git checkout. +set goLinkFlags="" +if exist ".git\HEAD" ( + where /q git + if not errorlevel 1 ( + for /f %%h in ('git rev-parse HEAD') do ( + set goLinkFlags="-X main.gitCommit=%%h" + ) + ) +) + +@echo on +go install -v -ldflags %goLinkFlags% ./... diff --git a/build/win-ci-test.bat b/build/win-ci-test.bat new file mode 100644 index 0000000000..5945426db0 --- /dev/null +++ b/build/win-ci-test.bat @@ -0,0 +1,15 @@ +@echo off +if not exist .\build\win-ci-test.bat ( + echo This script must be run from the root of the repository. + exit /b +) +if not defined GOPATH ( + echo GOPATH is not set. + exit /b +) + +set GOPATH=%GOPATH%;%cd%\Godeps\_workspace +set GOBIN=%cd%\build\bin + +@echo on +go test ./... From 7d59c5c58d93f97b8ee77f61811f2ad72f25388a Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Mon, 9 May 2016 09:59:27 +0200 Subject: [PATCH 07/10] eth: fixed tracing functions using the current header instead of parent Fixes #2525 --- eth/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/api.go b/eth/api.go index bd81799626..1d66f53fe5 100644 --- a/eth/api.go +++ b/eth/api.go @@ -1841,7 +1841,7 @@ func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogCon } // Mutate the state if we haven't reached the tracing transaction yet if uint64(idx) < txIndex { - vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{}) + vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, block.Header(), vm.Config{}) _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return nil, fmt.Errorf("mutation failed: %v", err) @@ -1849,7 +1849,7 @@ func (s *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogCon continue } // Otherwise trace the transaction and return - vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, parent.Header(), vm.Config{Debug: true, Logger: *logger}) + vmenv := core.NewEnv(stateDb, s.config, s.eth.BlockChain(), msg, block.Header(), vm.Config{Debug: true, Logger: *logger}) ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return nil, fmt.Errorf("tracing failed: %v", err) From 1d42061e2c8c1f657d56b606057df537e11abf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 9 May 2016 11:59:43 +0300 Subject: [PATCH 08/10] jsre: hotfix web3 for the console eth.syncing formatting --- jsre/ethereum_js.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jsre/ethereum_js.go b/jsre/ethereum_js.go index dfdedeb110..79ce1d2e2f 100644 --- a/jsre/ethereum_js.go +++ b/jsre/ethereum_js.go @@ -3911,7 +3911,12 @@ var outputSyncingFormatter = function(result) { result.startingBlock = utils.toDecimal(result.startingBlock); result.currentBlock = utils.toDecimal(result.currentBlock); result.highestBlock = utils.toDecimal(result.highestBlock); - + if (result.knownStates !== undefined) { + result.knownStates = utils.toDecimal(result.knownStates); + } + if (result.pulledStates !== undefined) { + result.pulledStates = utils.toDecimal(result.pulledStates); + } return result; }; From 56ed6152a11592d20220daf6322e94a009e6236d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 29 Mar 2016 03:08:16 +0200 Subject: [PATCH 09/10] core, eth, miner: improve shutdown synchronisation Shutting down geth prints hundreds of annoying error messages in some cases. The errors appear because the Stop method of eth.ProtocolManager, miner.Miner and core.TxPool is asynchronous. Left over peer sessions generate events which are processed after Stop even though the database has already been closed. The fix is to make Stop synchronous using sync.WaitGroup. For eth.ProtocolManager, in order to make use of WaitGroup safe, we need a way to stop new peer sessions from being added while waiting on the WaitGroup. The eth protocol Run function now selects on a signaling channel and adds to the WaitGroup only if ProtocolManager is not shutting down. For miner.worker and core.TxPool the number of goroutines is static, WaitGroup can be used in the usual way without additional synchronisation. --- core/tx_pool.go | 11 +++++--- eth/backend.go | 1 + eth/handler.go | 60 ++++++++++++++++++++++++++++---------------- eth/helper_test.go | 14 +++++------ eth/peer.go | 21 ++++++++++++++-- eth/sync.go | 2 +- miner/worker.go | 62 +++++++++++++++++++++------------------------- 7 files changed, 101 insertions(+), 70 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index e997e8cd01..f2eb2bbdd3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -60,8 +60,7 @@ type stateFn func() (*state.StateDB, error) // two states over time as they are received and processed. type TxPool struct { config *ChainConfig - quit chan bool // Quitting channel - currentState stateFn // The state function which will allow us to do some pre checks + currentState stateFn // The state function which will allow us to do some pre checks pendingState *state.ManagedState gasLimit func() *big.Int // The current gas limit function callback minGasPrice *big.Int @@ -72,6 +71,8 @@ type TxPool struct { pending map[common.Hash]*types.Transaction // processable transactions queue map[common.Address]map[common.Hash]*types.Transaction + wg sync.WaitGroup // for shutdown sync + homestead bool } @@ -80,7 +81,6 @@ func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stat config: config, pending: make(map[common.Hash]*types.Transaction), queue: make(map[common.Address]map[common.Hash]*types.Transaction), - quit: make(chan bool), eventMux: eventMux, currentState: currentStateFn, gasLimit: gasLimitFn, @@ -90,12 +90,15 @@ func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stat events: eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}), } + pool.wg.Add(1) go pool.eventLoop() return pool } func (pool *TxPool) eventLoop() { + defer pool.wg.Done() + // Track chain events. When a chain events occurs (new chain canon block) // we need to know the new state. The new state will help us determine // the nonces in the managed state @@ -155,8 +158,8 @@ func (pool *TxPool) resetState() { } func (pool *TxPool) Stop() { - close(pool.quit) pool.events.Unsubscribe() + pool.wg.Wait() glog.V(logger.Info).Infoln("Transaction pool stopped") } diff --git a/eth/backend.go b/eth/backend.go index 9722e96257..f43dea7775 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -416,6 +416,7 @@ func (s *Ethereum) Stop() error { s.blockchain.Stop() s.protocolManager.Stop() s.txPool.Stop() + s.miner.Stop() s.eventMux.Stop() s.StopAutoDAG() diff --git a/eth/handler.go b/eth/handler.go index d6b474a918..3980a625e6 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -74,14 +74,14 @@ type ProtocolManager struct { minedBlockSub event.Subscription // channels for fetcher, syncer, txsyncLoop - newPeerCh chan *peer - txsyncCh chan *txsync - quitSync chan struct{} + newPeerCh chan *peer + txsyncCh chan *txsync + quitSync chan struct{} + noMorePeers chan struct{} // wait group is used for graceful shutdowns during downloading // and processing - wg sync.WaitGroup - quit bool + wg sync.WaitGroup } // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable @@ -94,16 +94,17 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int, } // Create the protocol manager with the base fields manager := &ProtocolManager{ - networkId: networkId, - fastSync: fastSync, - eventMux: mux, - txpool: txpool, - blockchain: blockchain, - chaindb: chaindb, - peers: newPeerSet(), - newPeerCh: make(chan *peer, 1), - txsyncCh: make(chan *txsync), - quitSync: make(chan struct{}), + networkId: networkId, + fastSync: fastSync, + eventMux: mux, + txpool: txpool, + blockchain: blockchain, + chaindb: chaindb, + peers: newPeerSet(), + newPeerCh: make(chan *peer), + noMorePeers: make(chan struct{}), + txsyncCh: make(chan *txsync), + quitSync: make(chan struct{}), } // Initiate a sub-protocol for every implemented version we can handle manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions)) @@ -120,8 +121,14 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int, Length: ProtocolLengths[i], Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { peer := manager.newPeer(int(version), p, rw) - manager.newPeerCh <- peer - return manager.handle(peer) + select { + case manager.newPeerCh <- peer: + manager.wg.Add(1) + defer manager.wg.Done() + return manager.handle(peer) + case <-manager.quitSync: + return p2p.DiscQuitting + } }, NodeInfo: func() interface{} { return manager.NodeInfo() @@ -187,16 +194,25 @@ func (pm *ProtocolManager) Start() { } func (pm *ProtocolManager) Stop() { - // Showing a log message. During download / process this could actually - // take between 5 to 10 seconds and therefor feedback is required. glog.V(logger.Info).Infoln("Stopping ethereum protocol handler...") - pm.quit = true pm.txSub.Unsubscribe() // quits txBroadcastLoop pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop - close(pm.quitSync) // quits syncer, fetcher, txsyncLoop - // Wait for any process action + // Quit the sync loop. + // After this send has completed, no new peers will be accepted. + pm.noMorePeers <- struct{}{} + + // Quit fetcher, txsyncLoop. + close(pm.quitSync) + + // Disconnect existing sessions. + // This also closes the gate for any new registrations on the peer set. + // sessions which are already established but not added to pm.peers yet + // will exit when they try to register. + pm.peers.Close() + + // Wait for all peer handler goroutines and the loops to come down. pm.wg.Wait() glog.V(logger.Info).Infoln("Ethereum protocol handler stopped") diff --git a/eth/helper_test.go b/eth/helper_test.go index 5703d44cc2..dacb1593f5 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -140,14 +140,14 @@ func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*te // Start the peer on a new thread errc := make(chan error, 1) go func() { - pm.newPeerCh <- peer - errc <- pm.handle(peer) + select { + case pm.newPeerCh <- peer: + errc <- pm.handle(peer) + case <-pm.quitSync: + errc <- p2p.DiscQuitting + } }() - tp := &testPeer{ - app: app, - net: net, - peer: peer, - } + tp := &testPeer{app: app, net: net, peer: peer} // Execute any implicitly requested handshakes and return if shake { td, head, genesis := pm.blockchain.Status() diff --git a/eth/peer.go b/eth/peer.go index 15ba22ff53..8eb41b0f99 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -34,6 +34,7 @@ import ( ) var ( + errClosed = errors.New("peer set is closed") errAlreadyRegistered = errors.New("peer is already registered") errNotRegistered = errors.New("peer is not registered") ) @@ -351,8 +352,9 @@ func (p *peer) String() string { // peerSet represents the collection of active peers currently participating in // the Ethereum sub-protocol. type peerSet struct { - peers map[string]*peer - lock sync.RWMutex + peers map[string]*peer + lock sync.RWMutex + closed bool } // newPeerSet creates a new peer set to track the active participants. @@ -368,6 +370,9 @@ func (ps *peerSet) Register(p *peer) error { ps.lock.Lock() defer ps.lock.Unlock() + if ps.closed { + return errClosed + } if _, ok := ps.peers[p.id]; ok { return errAlreadyRegistered } @@ -450,3 +455,15 @@ func (ps *peerSet) BestPeer() *peer { } return bestPeer } + +// Close disconnects all peers. +// No new peers can be registered after Close has returned. +func (ps *peerSet) Close() { + ps.lock.Lock() + defer ps.lock.Unlock() + + for _, p := range ps.peers { + p.Disconnect(p2p.DiscQuitting) + } + ps.closed = true +} diff --git a/eth/sync.go b/eth/sync.go index dd8aef8e43..69881530d7 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -148,7 +148,7 @@ func (pm *ProtocolManager) syncer() { // Force a sync even if not enough peers are present go pm.synchronise(pm.peers.BestPeer()) - case <-pm.quitSync: + case <-pm.noMorePeers: return } } diff --git a/miner/worker.go b/miner/worker.go index 21588e3103..3d1928bf63 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -94,10 +94,13 @@ type worker struct { mu sync.Mutex + // update loop + mux *event.TypeMux + events event.Subscription + wg sync.WaitGroup + agents map[Agent]struct{} recv chan *Result - mux *event.TypeMux - quit chan struct{} pow pow.PoW eth core.Backend @@ -138,13 +141,14 @@ func newWorker(config *core.ChainConfig, coinbase common.Address, eth core.Backe possibleUncles: make(map[common.Hash]*types.Block), coinbase: coinbase, txQueue: make(map[common.Hash]*types.Transaction), - quit: make(chan struct{}), agents: make(map[Agent]struct{}), fullValidation: false, } + worker.events = worker.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{}) + worker.wg.Add(1) go worker.update() - go worker.wait() + go worker.wait() worker.commitNewWork() return worker @@ -184,9 +188,12 @@ func (self *worker) start() { } func (self *worker) stop() { + // Quit update. + self.events.Unsubscribe() + self.wg.Wait() + self.mu.Lock() defer self.mu.Unlock() - if atomic.LoadInt32(&self.mining) == 1 { // Stop all agents. for agent := range self.agents { @@ -217,36 +224,23 @@ func (self *worker) unregister(agent Agent) { } func (self *worker) update() { - eventSub := self.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{}) - defer eventSub.Unsubscribe() - - eventCh := eventSub.Chan() - for { - select { - case event, ok := <-eventCh: - if !ok { - // Event subscription closed, set the channel to nil to stop spinning - eventCh = nil - continue + defer self.wg.Done() + for event := range self.events.Chan() { + // A real event arrived, process interesting content + switch ev := event.Data.(type) { + case core.ChainHeadEvent: + self.commitNewWork() + case core.ChainSideEvent: + self.uncleMu.Lock() + self.possibleUncles[ev.Block.Hash()] = ev.Block + self.uncleMu.Unlock() + case core.TxPreEvent: + // Apply transaction to the pending state if we're not mining + if atomic.LoadInt32(&self.mining) == 0 { + self.currentMu.Lock() + self.current.commitTransactions(self.mux, types.Transactions{ev.Tx}, self.gasPrice, self.chain) + self.currentMu.Unlock() } - // A real event arrived, process interesting content - switch ev := event.Data.(type) { - case core.ChainHeadEvent: - self.commitNewWork() - case core.ChainSideEvent: - self.uncleMu.Lock() - self.possibleUncles[ev.Block.Hash()] = ev.Block - self.uncleMu.Unlock() - case core.TxPreEvent: - // Apply transaction to the pending state if we're not mining - if atomic.LoadInt32(&self.mining) == 0 { - self.currentMu.Lock() - self.current.commitTransactions(self.mux, types.Transactions{ev.Tx}, self.gasPrice, self.chain) - self.currentMu.Unlock() - } - } - case <-self.quit: - return } } } From f61e203c10124d62b0d1206812caaa568c79de93 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 9 May 2016 13:13:44 +0200 Subject: [PATCH 10/10] cmd/utils: fix build on *BSD --- cmd/utils/fdlimit_freebsd.go | 54 ++++++++++++++++++++++++++++++++++++ cmd/utils/fdlimit_unix.go | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 cmd/utils/fdlimit_freebsd.go diff --git a/cmd/utils/fdlimit_freebsd.go b/cmd/utils/fdlimit_freebsd.go new file mode 100644 index 0000000000..4cb5013c84 --- /dev/null +++ b/cmd/utils/fdlimit_freebsd.go @@ -0,0 +1,54 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +// +build freebsd + +package utils + +import "syscall" + +// This file is largely identical to fdlimit_unix.go, +// but Rlimit fields have type int64 on FreeBSD so it needs +// an extra conversion. + +// raiseFdLimit tries to maximize the file descriptor allowance of this process +// to the maximum hard-limit allowed by the OS. +func raiseFdLimit(max uint64) error { + // Get the current limit + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return err + } + // Try to update the limit to the max allowance + limit.Cur = limit.Max + if limit.Cur > int64(max) { + limit.Cur = int64(max) + } + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return err + } + return nil +} + +// getFdLimit retrieves the number of file descriptors allowed to be opened by this +// process. +func getFdLimit() (int, error) { + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return 0, err + } + return int(limit.Cur), nil +} diff --git a/cmd/utils/fdlimit_unix.go b/cmd/utils/fdlimit_unix.go index 2a6dffc8f3..08e153bbd4 100644 --- a/cmd/utils/fdlimit_unix.go +++ b/cmd/utils/fdlimit_unix.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . -// +build linux darwin +// +build linux darwin netbsd openbsd solaris package utils