From 2b04f2d580ec1f2b2dce08dd1ca4aeefab080496 Mon Sep 17 00:00:00 2001 From: fangdingjun Date: Fri, 6 Jul 2018 19:10:01 +0800 Subject: [PATCH] fix high cpu usage and crash issue fix high cpu usage fix crash issue on server stream close change function name --- _nghttp2.h | 4 ++-- conn.go | 29 ++++++++++++++++++++++------- data_provider.go | 3 ++- nghttp2.c | 4 ++-- stream.go | 4 +++- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/_nghttp2.h b/_nghttp2.h index 41eb69a..2afca5b 100644 --- a/_nghttp2.h +++ b/_nghttp2.h @@ -46,7 +46,7 @@ int32_t submit_request(nghttp2_session *session, nghttp2_nv *hdrs, size_t hdrlen int send_client_connection_header(nghttp2_session *session); -nghttp2_session *init_client_session(size_t data); -nghttp2_session *init_server_session(size_t data); +nghttp2_session *init_nghttp2_client_session(size_t data); +nghttp2_session *init_nghttp2_server_session(size_t data); #endif \ No newline at end of file diff --git a/conn.go b/conn.go index f6f386b..f3512eb 100644 --- a/conn.go +++ b/conn.go @@ -12,6 +12,7 @@ import ( "io" "net" "net/http" + "net/url" "strings" "sync" "time" @@ -41,7 +42,7 @@ func NewClientConn(c net.Conn) (*ClientConn, error) { errch: make(chan struct{}), exitch: make(chan struct{}), } - conn.session = C.init_client_session( + conn.session = C.init_nghttp2_client_session( C.size_t(int(uintptr(unsafe.Pointer(conn))))) if conn.session == nil { return nil, fmt.Errorf("init session failed") @@ -247,6 +248,7 @@ type ServerConn struct { // Handler handler to handle request Handler http.Handler + closed bool session *C.nghttp2_session streams map[int]*ServerStream lock *sync.Mutex @@ -287,7 +289,7 @@ func NewServerConn(c net.Conn, handler http.Handler) (*ServerConn, error) { errch: make(chan struct{}), exitch: make(chan struct{}), } - conn.session = C.init_server_session(C.size_t(uintptr(unsafe.Pointer(conn)))) + conn.session = C.init_nghttp2_server_session(C.size_t(uintptr(unsafe.Pointer(conn)))) if conn.session == nil { return nil, fmt.Errorf("init session failed") } @@ -306,12 +308,18 @@ func (c *ServerConn) serve(s *ServerStream) { if c.Handler == nil { handler = http.DefaultServeMux } + if s.req.URL == nil { + s.req.URL = &url.URL{} + } handler.ServeHTTP(s, s.req) s.Close() } // Close close the server connection func (c *ServerConn) Close() error { + if c.closed { + return nil + } for _, s := range c.streams { s.Close() } @@ -319,6 +327,7 @@ func (c *ServerConn) Close() error { C.nghttp2_session_del(c.session) close(c.exitch) c.conn.Close() + c.closed = true return nil } @@ -326,8 +335,9 @@ func (c *ServerConn) Close() error { func (c *ServerConn) Run() { var wantRead int var wantWrite int - var delay = 50 + var delay = 100 * time.Millisecond var ret C.int + var shouldDelay bool defer c.Close() defer close(c.errch) @@ -391,14 +401,19 @@ loop: //log.Println(c.err) break loop } + shouldDelay = false default: + // want read but data not avaliable + if wantRead != 0 { + shouldDelay = true + } } + wantWrite = int(C.nghttp2_session_want_write(c.session)) + // make delay when no data read/write - if wantRead == 0 && wantWrite == 0 { - select { - case <-time.After(time.Duration(delay) * time.Millisecond): - } + if (shouldDelay || wantRead == 0) && wantWrite == 0 { + time.Sleep(delay) } } } diff --git a/data_provider.go b/data_provider.go index b53ec1c..6ded9b7 100644 --- a/data_provider.go +++ b/data_provider.go @@ -73,12 +73,13 @@ type bodyProvider struct { // Read read data from provider // will block when data not yet avaliable func (bp *bodyProvider) Read(buf []byte) (int, error) { + var delay = 100 * time.Millisecond for { bp.lock.Lock() n, err := bp.buf.Read(buf) bp.lock.Unlock() if err != nil && !bp.closed { - time.Sleep(100 * time.Millisecond) + time.Sleep(delay) continue } return n, err diff --git a/nghttp2.c b/nghttp2.c index c04a5d2..c3b0afe 100644 --- a/nghttp2.c +++ b/nghttp2.c @@ -84,7 +84,7 @@ static int on_server_begin_headers_callback(nghttp2_session *session, return 0; } -nghttp2_session *init_server_session(size_t data) +nghttp2_session *init_nghttp2_server_session(size_t data) { nghttp2_session_callbacks *callbacks; nghttp2_session *session; @@ -312,7 +312,7 @@ void init_client_callbacks(nghttp2_session_callbacks *callbacks) callbacks, on_client_begin_headers_callback); } -nghttp2_session *init_client_session(size_t data) +nghttp2_session *init_nghttp2_client_session(size_t data) { int ret; nghttp2_session *session; diff --git a/stream.go b/stream.go index 397ee29..f28fa18 100644 --- a/stream.go +++ b/stream.go @@ -162,7 +162,9 @@ func (s *ServerStream) Close() error { return nil } //C.nghttp2_submit_rst_stream(s.conn.session, 0, C.int(s.streamID), 0) - s.req.Body.Close() + if s.req.Body != nil { + s.req.Body.Close() + } if s.dp != nil { s.dp.Close() }