Commit 199b9956 authored by jan.koester's avatar jan.koester
Browse files

reattach added

parent d7b11933
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -260,4 +260,24 @@ namespace netplus {
        // handler, which is invoked with it already held -- see requestWritablePoll's
        // identical precondition).
        std::unique_ptr<socket> detachConnection(con &c);

        // Re-registers a connection previously removed via detachConnection() with the same
        // epoll/kqueue instance it originally belonged to (c->ownerPollFd, set once at accept
        // time and never cleared by detachConnection). For a caller that finished background
        // work on a connection's socket -- already restored into c->slots[0].csock and
        // switched back to non-blocking, since the event loop always runs non-blocking
        // sockets -- and wants normal HttpEvent dispatch (further reads, keep-alive) to
        // resume.
        //
        // Unlike detachConnection/requestWritablePoll, the CALLER MUST NOT hold
        // c->event_mutex -- this takes the lock itself, since it's meant to be called from a
        // background thread once it's done with the connection (mirroring
        // ConnectEventHandler's own locking around initial registration), not from within an
        // already-locked RequestEvent handler.
        //
        // Returns false if there's no socket to reattach, or ownerPollFd was never recorded
        // (shouldn't happen for a connection that reached here via a prior successful
        // detachConnection()). Implemented per event backend like detachConnection/
        // requestWritablePoll above; same select-based poll.cpp/iocp.cpp no-op caveat.
        bool reattachConnection(std::shared_ptr<con> c);
};
+29 −0
Original line number Diff line number Diff line
@@ -1173,4 +1173,33 @@ namespace netplus {
        return std::move(c.slots[0].csock);
    }

    bool reattachConnection(std::shared_ptr<con> c) {
        if (!c || c->slots.empty() || !c->slots[0].csock || c->ownerPollFd < 0) return false;
        int fd = c->slots[0].csock->fd();
        if (fd < 0) return false;

        {
            std::unique_lock<std::shared_mutex> lk(POLL_HANDLER_MUTEX);
            CONNECTIONS[fd] = c;
        }

        std::lock_guard<std::recursive_mutex> evlk(c->event_mutex);
        epoll_event ev{};
        ev.data.fd = fd;
        ev.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
        if (c->SendData.pos < c->SendData.size() || c->slots[0].csock->hasPendingWrite())
            ev.events |= EPOLLOUT;

        // Unlike ConnectEventHandler's fresh accept(), this fd may still be registered with
        // the kernel from before detachConnection() -- EPOLLONESHOT only disarms interest, it
        // doesn't deregister (see detachConnection's comment above). MOD is therefore the
        // common case; ADD is the fallback for the rare case the fd was never registered
        // (shouldn't happen for a connection that went through a real detachConnection(), but
        // mirrors requestWritablePoll's own MOD-then-ADD-on-ENOENT idiom rather than assuming).
        if (epoll_ctl(c->ownerPollFd, EPOLL_CTL_MOD, fd, &ev) < 0 && errno == ENOENT)
            epoll_ctl(c->ownerPollFd, EPOLL_CTL_ADD, fd, &ev);

        return true;
    }

} // namespace netplus
+5 −0
Original line number Diff line number Diff line
@@ -1032,4 +1032,9 @@ namespace netplus {
    // documented no-op, matching requestWritablePoll() above.
    std::unique_ptr<socket> detachConnection(con &) { return nullptr; }

    // detachConnection() never hands out a real socket on this backend (always nullptr
    // above), so no caller can ever have one to reattach -- documented no-op for the same
    // reason.
    bool reattachConnection(std::shared_ptr<con>) { return false; }

} // namespace netplus
+25 −0
Original line number Diff line number Diff line
@@ -1226,4 +1226,29 @@ namespace netplus {
        return std::move(c.slots[0].csock);
    }

    bool reattachConnection(std::shared_ptr<con> c) {
        if (!c || c->slots.empty() || !c->slots[0].csock || c->ownerPollFd < 0) return false;
        int fd = c->slots[0].csock->fd();
        if (fd < 0) return false;

        {
            std::unique_lock<std::shared_mutex> lk(POLL_HANDLER_MUTEX);
            CONNECTIONS[fd] = c;
        }

        std::lock_guard<std::recursive_mutex> evlk(c->event_mutex);
        // Unlike epoll's EPOLLONESHOT, a kqueue EV_ONESHOT filter is removed by the kernel
        // the instant it fires (see detachConnection's comment above) -- there is nothing
        // left to MOD, so this is always a fresh EV_ADD, exactly like ConnectEventHandler's
        // initial registration.
        struct kevent changes[2];
        int n = 0;
        EV_SET(&changes[n++], fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, nullptr);
        if (c->SendData.pos < c->SendData.size() || c->slots[0].csock->hasPendingWrite())
            EV_SET(&changes[n++], fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, nullptr);
        kevent(c->ownerPollFd, changes, n, nullptr, 0, nullptr);

        return true;
    }

} // namespace netplus
+5 −0
Original line number Diff line number Diff line
@@ -1099,4 +1099,9 @@ namespace netplus {
    // documented no-op, matching requestWritablePoll() above.
    std::unique_ptr<socket> detachConnection(con &) { return nullptr; }

    // detachConnection() never hands out a real socket on this backend (always nullptr
    // above), so no caller can ever have one to reattach -- documented no-op for the same
    // reason.
    bool reattachConnection(std::shared_ptr<con>) { return false; }

} // namespace netplus