code: func (w *worker) taskLoop() {
  	var (
  		stopCh chan struct{}
  		prev   common.Hash
  	)
  
  	// interrupt aborts the in-flight sealing task.
  	interrupt := func() {
  		if stopCh != nil {
  			close(stopCh)
  			stopCh = nil
  		}
  	}
  	for {
  		select {
  		case task := <-w.taskCh:
  			if w.newTaskHook != nil {
  				w.newTaskHook(task)
  			}
  			// Reject duplicate sealing work due to resubmitting.
  			sealHash := w.engine.SealHash(task.block.Header())
  			if sealHash == prev {
  				continue
  			}
  			// Interrupt previous sealing operation
  			interrupt()
  			stopCh, prev = make(chan struct{}), sealHash
  
  			if w.skipSealHook != nil && w.skipSealHook(task) {
  				continue
  			}
  			w.pendingMu.Lock()
  			w.pendingTasks[w.engine.SealHash(task.block.Header())] = task
  			w.pendingMu.Unlock()
  
  			if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil {
  				log.Warn("Block sealing failed", "err", err)
  			}
  		case <-w.exitCh:
  			interrupt()
  			return
  		}
  	}
  }
docs: // taskLoop is a standalone goroutine to fetch sealing task from the generator and
  // push them to consensus engine.