You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
luci-base (ucode): dispatcher.uc opens ubus at import time, so forked uhttpd workers share one ubus socket and concurrent requests hang #9091
With uhttpd.main.max_requests > 1, several concurrent requests to /cgi-bin/luci/... hang until the client times out. Each uhttpd worker stays idle (no CPU) inside controller/admin/index.uc. With max_requests=1 the same client works reliably.
Likely cause
/usr/share/ucode/luci/uhttpd.uc imports luci.dispatcher when uhttpd loads the ucode handler (-O), which happens in the main uhttpd process.
modules/luci-base/ucode/dispatcher.uc line 16: let ubus = connect(); runs at module scope, so the ubus connection is created once in the parent.
uhttpd forks one worker per request. All workers inherit the same ubus socket. On the router, every worker held the same two socket inodes as the parent.
My hypothesis: concurrent workers on one ubus socket consume each other's replies, and the remaining workers wait forever. I haven't traced this at the ubus protocol level.
Set max_requests to 20: uci set uhttpd.main.max_requests=20; uci commit uhttpd; /etc/init.d/uhttpd restart.
Log in from a client that sends several requests to the LuCI dispatcher in parallel. I used the LuCI Mobile Android app, which opens about 8 parallel HTTPS connections right after login.
The login succeeds: logread shows dispatcher.uc: luci: accepted login on / for root.
The follow-up requests get no response. 8-11 uhttpd workers pile up with load near 0 and disappear only when the client disconnects 15-30 s later.
The same ubus methods called from a shell (ubus call luci-rpc getNetworkDevices, system board, network.interface dump, ...) return instantly.
With max_requests=1 the requests run one after another, and the client works.
Suggested fix
Connect to ubus lazily, per worker: for example, inside dispatch(), or on first use after the fork, instead of at module scope. The same pattern may apply to let uci = cursor(); on the next line.
Related
openwrt/openwrt c6aa9ff ("uhttpd: disable concurrent requests by default") and its revert f00a4ae, which says concurrent CGI requests are needed. So max_requests=1 is only a workaround, not a fix. The current default is max_requests 3.
Activity
fix: login hang and client detail reloads, add port forward source ad…