func (s *session) SetWaitTime(waitTime time.Duration) {
	if waitTime < 1 {
		panic("@wait < 1")
	}
	s.lock.Lock()
	defer s.lock.Unlock()
	s.wait = waitTime
}
set maximum wait time when session got error or got exit signal
package getty
import (
	"bytes"
	"fmt"
	"io"
	"net"
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)
import (
	gxbytes "github.com/dubbogo/gost/bytes"
	gxcontext "github.com/dubbogo/gost/context"
	gxsync "github.com/dubbogo/gost/sync"
	gxtime "github.com/dubbogo/gost/time"
	"github.com/gorilla/websocket"
	perrors "github.com/pkg/errors"
)
const (
	maxReadBufLen    = 4 * 1024
	netIOTimeout     = 1e9       
	period           = 60 * 1e9  
	pendingDuration  = 3e9
	defaultQLen      = 1024
	maxIovecNum      = 10
	MaxWheelTimeSpan = 900e9  
	defaultSessionName    = "session"
	defaultTCPSessionName = "tcp-session"
	defaultUDPSessionName = "udp-session"
	defaultWSSessionName  = "ws-session"
	defaultWSSSessionName = "wss-session"
	outputFormat          = "session %s, Read Bytes: %d, Write Bytes: %d, Read Pkgs: %d, Write Pkgs: %d"
)
var (
	wheel *gxtime.Wheel
)
func init() {
	span := 100e6  
	buckets := MaxWheelTimeSpan / span
	wheel = gxtime.NewWheel(time.Duration(span), int(buckets))  
}
func GetTimeWheel() *gxtime.Wheel {
	return wheel
}
type session struct {
	name     string
	endPoint EndPoint
	Connection
	listener EventListener
	reader Reader  
	writer Writer
	wQ chan interface{}
	maxMsgLen int32
	tPool *gxsync.TaskPool
	period time.Duration
	wait time.Duration
	once *sync.Once
	done chan struct{}
	attrs *gxcontext.ValuesContext
	grNum int32
	rDone chan struct{}
	lock  sync.RWMutex
}
func newSession(endPoint EndPoint, conn Connection) *session {
	ss := &session{
		name:     defaultSessionName,
		endPoint: endPoint,
		Connection: conn,
		maxMsgLen: maxReadBufLen,
		period: period,
		once:  &sync.Once{},
		done:  make(chan struct{}),
		wait:  pendingDuration,
		attrs: gxcontext.NewValuesContext(nil),
		rDone: make(chan struct{}),
	}
	ss.Connection.setSession(ss)
	ss.SetWriteTimeout(netIOTimeout)
	ss.SetReadTimeout(netIOTimeout)
	return ss
}
func newTCPSession(conn net.Conn, endPoint EndPoint) Session {
	c := newGettyTCPConn(conn)
	session := newSession(endPoint, c)
	session.name = defaultTCPSessionName
	return session
}
func newUDPSession(conn *net.UDPConn, endPoint EndPoint) Session {
	c := newGettyUDPConn(conn)
	session := newSession(endPoint, c)
	session.name = defaultUDPSessionName
	return session
}
func newWSSession(conn *websocket.Conn, endPoint EndPoint) Session {
	c := newGettyWSConn(conn)
	session := newSession(endPoint, c)
	session.name = defaultWSSessionName
	return session
}
func (s *session) Reset() {
	*s = session{
		name:   defaultSessionName,
		once:   &sync.Once{},
		done:   make(chan struct{}),
		period: period,
		wait:   pendingDuration,
		attrs:  gxcontext.NewValuesContext(nil),
		rDone:  make(chan struct{}),
	}
}
func (s *session) Conn() net.Conn {
	if tc, ok := s.Connection.(*gettyTCPConn); ok {
		return tc.conn
	}
	if uc, ok := s.Connection.(*gettyUDPConn); ok {
		return uc.conn
	}
	if wc, ok := s.Connection.(*gettyWSConn); ok {
		return wc.conn.UnderlyingConn()
	}
	return nil
}
func (s *session) EndPoint() EndPoint {
	return s.endPoint
}
func (s *session) gettyConn() *gettyConn {
	if tc, ok := s.Connection.(*gettyTCPConn); ok {
		return &(tc.gettyConn)
	}
	if uc, ok := s.Connection.(*gettyUDPConn); ok {
		return &(uc.gettyConn)
	}
	if wc, ok := s.Connection.(*gettyWSConn); ok {
		return &(wc.gettyConn)
	}
	return nil
}
func (s *session) Stat() string {
	var conn *gettyConn
	if conn = s.gettyConn(); conn == nil {
		return ""
	}
	return fmt.Sprintf(
		outputFormat,
		s.sessionToken(),
		atomic.LoadUint32(&(conn.readBytes)),
		atomic.LoadUint32(&(conn.writeBytes)),
		atomic.LoadUint32(&(conn.readPkgNum)),
		atomic.LoadUint32(&(conn.writePkgNum)),
	)
}
func (s *session) IsClosed() bool {
	select {
	case <-s.done:
		return true
	default:
		return false
	}
}
func (s *session) SetMaxMsgLen(length int) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.maxMsgLen = int32(length)
}
func (s *session) SetName(name string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.name = name
}
func (s *session) SetEventListener(listener EventListener) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.listener = listener
}
func (s *session) SetPkgHandler(handler ReadWriter) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.reader = handler
	s.writer = handler
}
func (s *session) SetReader(reader Reader) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.reader = reader
}
func (s *session) SetWriter(writer Writer) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.writer = writer
}
func (s *session) SetCronPeriod(period int) {
	if period < 1 {
		panic("@period < 1")
	}
	s.lock.Lock()
	defer s.lock.Unlock()
	s.period = time.Duration(period) * time.Millisecond
}
func (s *session) SetRQLen(readQLen int) {}
func (s *session) SetWQLen(writeQLen int) {
	if writeQLen < 1 {
		panic("@writeQLen < 1")
	}
	s.lock.Lock()
	defer s.lock.Unlock()
	s.wQ = make(chan interface{}, writeQLen)
	log.Debugf("%s, [session.SetWQLen] wQ{len:%d, cap:%d}", s.Stat(), len(s.wQ), cap(s.wQ))
}