Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions engine_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gin

import (
"testing"
)

func TestRoutesConcurrent(t *testing.T) {
r := New()

done := make(chan bool)

// Concurrently read routes
go func() {
_ = r.Routes()
done <- true
}()

// Register a route at the same time
r.GET("/", func(c *Context) { c.String(200, "OK") })

<-done
}
5 changes: 5 additions & 0 deletions gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ type Engine struct {
noMethod HandlersChain
pool sync.Pool
trees methodTrees
treesMu sync.RWMutex
maxParams uint16
maxSections uint16
trustedProxies []string
Expand Down Expand Up @@ -362,6 +363,8 @@ func (engine *Engine) rebuild405Handlers() {
}

func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
engine.treesMu.Lock()
defer engine.treesMu.Unlock()
assert1(path[0] == '/', "path must begin with '/'")
assert1(method != "", "HTTP method can not be empty")
assert1(len(handlers) > 0, "there must be at least one handler")
Expand All @@ -388,6 +391,8 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
// Routes returns a slice of registered routes, including some useful information, such as:
// the http method, path, and the handler name.
func (engine *Engine) Routes() (routes RoutesInfo) {
engine.treesMu.RLock()
defer engine.treesMu.RUnlock()
for _, tree := range engine.trees {
routes = iterate("", tree.method, routes, tree.root)
}
Expand Down