code: func (t *TimeoutWheel) Schedule(
  	d time.Duration,
  	expireCb func(interface{}),
  	arg interface{},
  ) (Timeout, error) {
  	dTicks := (d + t.tickInterval - 1) / t.tickInterval
  	deadline := atomic.LoadUint64(&t.ticks) + uint64(dTicks)
  	timeout := t.getTimeoutLocked(deadline)
  
  	if t.state != running {
  		t.putTimeoutLocked(timeout)
  		timeout.mtx.Unlock()
  		return Timeout{}, ErrSystemStopped
  	}
  
  	bucket := &t.buckets[deadline&t.bucketMask]
  	timeout.expireCb = expireCb
  	timeout.expireArg = arg
  	timeout.deadline = deadline
  	timeout.state = timeoutActive
  	out := Timeout{timeout: timeout, generation: timeout.generation}
  
  	// execute the callback now, return a Timeout that is already Stopped (generation is bumped)
  	if bucket.lastTick >= deadline {
  		t.putTimeoutLocked(timeout)
  		timeout.mtx.Unlock()
  		expireCb(arg)
  		return out, nil
  	}
  
  	timeout.prependLocked(bucket)
  	timeout.mtx.Unlock()
  	return out, nil
  }
docs: // Schedule adds a new function to be called after some duration of time has
  // elapsed. The returned Timeout can be used to cancel calling the function. If the duration falls
  // between two ticks, the latter tick is used.