Но после закрытия дескриптора, ядро автоматически удалит этот дескриптор из своих структур и не будет по нему отслеживать события.
Ход событий в общем: воркер блокируется на epoll_wait(), по истечении тайм-аута либо по получении nevent событий, воркер просыпается и в цикле перебирает эти события. Допустим, встретилось событие на чтение и recv() вернуло 0, мы закрываем соединение, при этом дескриптор удаляется из структур подсистемы epoll, также в массив cycle->free_connections возвращается структура ngx_connection_t.
Я не понимаю такой момент: почему ядро потом может вернуть событие для уже закрытого сокета?