[Solved]Epoll Timeout 100% CPU Auslastung



  • Moin habe Probleme wenn ich timeout auf den socket bekomme bei recv bekomme ich erwartungs gemäß EAGAIN das problem epoll_wait wartet denn nicht und habe dann entsprechen 100% CPU Auslastung. Gitlab Code

    Fehlerausgabe:

    Thread 950145: Socket recvdata 5: Resource temporarily unavailable
    Thread 950145: Socket recvdata 6: Resource temporarily unavailable
    

    event.cpp

    void libhttppp::Event::runEventloop(){
            CpuInfo cpuinfo;
            size_t thrs = cpuinfo.getCores();
            initEventHandler();
    MAINWORKERLOOP:
            ThreadPool thpool;
            for (size_t i = 0; i < thrs; i++) {
                _wArg arg;
                arg.event=this;
                arg.cthread=thpool.addThread();
                arg.cthread->Create(WorkerThread, (void*)&arg);
            }
            initLockPool(&thpool);
            for (Thread *curth = thpool.getfirstThread(); curth; curth = curth->nextThread()) {
                curth->Join();
            }
            destroyLockPool();
            if(libhttppp::Event::_Restart){
                libhttppp::Event::_Restart=false;
                goto MAINWORKERLOOP;
            }
    }
    
    void * libhttppp::Event::WorkerThread(void* wrkevent){
        Event *eventptr=((_wArg*)wrkevent)->event;
        Thread *cthread=((_wArg*)wrkevent)->cthread;
        cthread->setPid(getpid());
        while (libhttppp::Event::_Run) {
            try {
                for (int i = 0; i < eventptr->waitEventHandler(); ++i) {
                    try{
                         if(eventptr->LockConnection(cthread,i)){
                            switch(eventptr->StatusEventHandler(i)){
                                case EventApi::EventHandlerStatus::EVNOTREADY:
                                    eventptr->ConnectEventHandler(i);
                                    break;
                                case EventApi::EventHandlerStatus::EVOUT:
                                    eventptr->WriteEventHandler(i);
                                    break;
                                case EventApi::EventHandlerStatus::EVIN:
                                    eventptr->ReadEventHandler(i);
                                    break;
                            }
                            eventptr->UnlockConnection(cthread,i);
                        }
                    }catch(HTTPException &e){
                        Console con;
                        con << "Thread " << cthread->getPid() << ": " << e.what() << con.endl;
                        switch(e.getErrorType()){
                            case HTTPException::Critical:
                                throw e;
                                break;
                            case HTTPException::Error:
                                try{
                                    eventptr->CloseEventHandler(i);
                                }catch(HTTPException &e){ 
                                    eventptr->UnlockConnection(cthread,i);
                                    throw e;
                                };
                                break;            
                        }                 
                        eventptr->UnlockConnection(cthread,i);
                    }
                }
            }catch(HTTPException &e){
                switch(e.getErrorType()){
                    case HTTPException::Warning:
                        break;
                    default:
                        throw e;
                }
            }
        }
        return NULL;
    }
    
    

    epoll.cpp

    void libhttppp::EPOLL::initEventHandler(){
        HTTPException httpexception;
        try{
            _ServerSocket->setnonblocking();
            _ServerSocket->listenSocket();
        }catch(HTTPException &e){
            throw e;
        }
        
        struct epoll_event setevent= (struct epoll_event) {
            0
        };
    
        _epollFD = epoll_create1(0);
    
        if (_epollFD == -1) {
            httpexception[HTTPException::Critical]<<"initEventHandler:" << "can't create epoll";
            throw httpexception;
        }
    
        setevent.events = EPOLLIN;
    
        if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, _ServerSocket->getSocket(), &setevent) < 0) {
            httpexception[HTTPException::Critical] << "initEventHandler: can't create epoll";
            throw httpexception;
        }
        
        _Events = new epoll_event[(_ServerSocket->getMaxconnections())];
        for(int i=0; i<_ServerSocket->getMaxconnections(); ++i)
            _Events[i].data.ptr = nullptr;
    }
    
    int libhttppp::EPOLL::waitEventHandler(){
        int n = epoll_wait(_epollFD,_Events,_ServerSocket->getMaxconnections(), -1);
        if(n<0) {
            HTTPException httpexception;
            if(errno== EINTR) {
                httpexception[HTTPException::Warning] << "initEventHandler: EINTR";
            } else {
                httpexception[HTTPException::Critical] << "initEventHandler: epoll wait failure";
            }
            throw httpexception;
        }
        return n;
    }
    
    int libhttppp::EPOLL::StatusEventHandler(int des){
        HTTPException httpexception;
        if(!_Events[des].data.ptr)
            return EventHandlerStatus::EVNOTREADY;
        if(((Connection*)_Events[des].data.ptr)->getSendSize()!=0)
            return EventHandlerStatus::EVOUT;
        return EventHandlerStatus::EVIN;
    }
    
    void libhttppp::EPOLL::ConnectEventHandler(int des) {
        HTTPException httpexception;
        struct epoll_event setevent { 0 };
        Connection* curct = new Connection(_ServerSocket);
        try {
            /*will create warning debug mode that normally because the check already connection
             * with this socket if getconnection throw they will be create a new one
             */
            _ServerSocket->acceptEvent(curct->getClientSocket());
            curct->getClientSocket()->setnonblocking();
            setevent.events = EPOLLIN | EPOLLOUT;
            setevent.data.ptr = curct;
            if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, curct->getClientSocket()->Socket, &setevent) == -1) {
    #ifdef __GLIBCXX__
                char errbuf[255];
                httpexception[HTTPException::Error] << "ConnectEventHandler: " << strerror_r(errno, errbuf, 255);
    #else
                char errbuf[255];
                strerror_r(errno, errbuf, 255);
                httpexception.Error("ConnectEventHandler: ",errbuf);
    #endif
                throw httpexception;
            }
            ConnectEvent(curct);
        }catch (HTTPException& e) {
            delete curct;
            setevent.data.ptr=nullptr;
            throw e;
        }
        
    }
    
    void libhttppp::EPOLL::ReadEventHandler(int des){
        HTTPException httpexception;
        Connection *curct=((Connection*)_Events[des].data.ptr);
        char buf[BLOCKSIZE];
        int rcvsize=_ServerSocket->recvData(curct->getClientSocket(),&buf,BLOCKSIZE);
        curct->addRecvQueue(buf,rcvsize);
        RequestEvent(curct);
    }
    
    void libhttppp::EPOLL::WriteEventHandler(int des){
        HTTPException httpexception;
        Connection *curct=((Connection*)_Events[des].data.ptr);
        try {
            ssize_t sended=_ServerSocket->sendData(curct->getClientSocket(),
                                           (void*)curct->getSendData()->getData(),
                                           curct->getSendData()->getDataSize());
            curct->resizeSendQueue(sended);
            ResponseEvent(curct);
        } catch(HTTPException &e) {
                throw e;
        }
    }
    
    void libhttppp::EPOLL::CloseEventHandler(int des){
        HTTPException httpexception;
        struct epoll_event setevent { 0 };
        try {
            Connection *curct=((Connection*)_Events[des].data.ptr);
            if(!curct){
                httpexception[HTTPException::Error] << "CloseEvent empty DataPtr!";
                throw httpexception;
            }
            int ect=epoll_ctl(_epollFD, EPOLL_CTL_DEL, curct->getClientSocket()->Socket, &setevent);
            if(ect==-1) {
                httpexception[HTTPException::Error] << "CloseEvent can't delete Connection from epoll";
                throw httpexception;
            }
            DisconnectEvent(curct);
            delete ((Connection*)_Events[des].data.ptr);
            _Events[des].data.ptr=nullptr;
            httpexception[HTTPException::Note] << "CloseEventHandler: Connection shutdown!";
        } catch(HTTPException &e) {
            httpexception[HTTPException::Warning] << "CloseEventHandler: Can't do Connection shutdown!";
        }
    }
    
    

    socket.cpp

    /*******************************************************************************
    Copyright (c) 2014, Jan Koester jan.koester@gmx.net
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
        * Neither the name of the <organization> nor the
          names of its contributors may be used to endorse or promote products
          derived from this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *******************************************************************************/
    
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <sys/fcntl.h>
    #include <sys/types.h>
    #include <config.h>
    #include <errno.h>
    
    #include <openssl/ssl.h>
    #include <openssl/err.h>
    #include <openssl/x509.h>
    
    #include "utils.h"
    #include "socket.h"
    
    
    libhttppp::ClientSocket::ClientSocket(){
      Socket = 0;
      _SSL=nullptr;
      _ClientAddr = new struct sockaddr;
    }
    
    libhttppp::ClientSocket::~ClientSocket(){
        Close();
        if(_SSL)
            SSL_free(_SSL);
        delete _ClientAddr;
    }
    
    void libhttppp::ClientSocket::Close(){
        HTTPException exp;
        if(close(Socket)<0){
    #ifdef __GLIBCXX__
            char errbuf[255];
            exp[HTTPException::Error] << "Can't close Socket: " << strerror_r(errno, errbuf, 255);
    #else
            char errbuf[255];
            strerror_r(errno, errbuf, 255);
            exp[HTTPException::Error] << "Can't close Socket: " << errbuf;
    #endif
            throw exp;
        }
    }
    
    void libhttppp::ClientSocket::setnonblocking(){
        fcntl(Socket, F_SETFL, fcntl(Socket, F_GETFL, 0) | O_NONBLOCK);
    }
    
    libhttppp::ServerSocket::ServerSocket(const char* uxsocket,int maxconnections){
        HTTPException httpexception;
        int optval = 1;
        _Maxconnections=maxconnections;
        _UXSocketAddr = new sockaddr_un;
        _UXSocketAddr->sun_family = AF_UNIX;
        try {
            scopy(uxsocket,uxsocket+getlen(uxsocket),_UXSocketAddr->sun_path);
        }catch(...){
            httpexception[HTTPException::Critical] << "Can't copy Server UnixSocket";
            throw httpexception;
        }
        
        if ((Socket = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0){
            httpexception[HTTPException::Critical] << "Can't create Socket UnixSocket";
            throw httpexception;
        }
        
        setsockopt(Socket,SOL_SOCKET,SO_REUSEADDR,&optval, sizeof(optval));
        
        if (bind(Socket, (struct sockaddr *)_UXSocketAddr, sizeof(struct sockaddr)) < 0){
            #ifdef __GLIBCXX__
            char errbuf[255];
            httpexception[HTTPException::Error] << "Can't bind Server UnixSocket"
                                                << strerror_r(errno, errbuf, 255);
            #else
            char errbuf[255];
            strerror_r(errno, errbuf, 255);
            httpexception[HTTPException::Critical] << "Can't bind Server UnixSocket" << errbuf;
            #endif
            throw httpexception;
        }
    }
    
    
    libhttppp::ServerSocket::ServerSocket(int socket) {
        Socket = socket;
        _Maxconnections = MAXDEFAULTCONN;
        _UXSocketAddr = NULL;
    }
    
    libhttppp::ServerSocket::ServerSocket(const char* addr, int port,int maxconnections){
        HTTPException httpexception;
        _Maxconnections=maxconnections;
        _UXSocketAddr = NULL;
        
        char port_buffer[6];
        snprintf(port_buffer,6, "%d", port);
        struct addrinfo *result, *rp;
        memset(&_SockAddr, 0, sizeof(struct addrinfo));
        _SockAddr.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
        _SockAddr.ai_socktype = SOCK_STREAM; /* Datagram socket */
        _SockAddr.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
        _SockAddr.ai_protocol = 0;          /* Any protocol */
        _SockAddr.ai_canonname = NULL;
        _SockAddr.ai_addr = NULL;
        _SockAddr.ai_next = NULL;
        
        int s = getaddrinfo(addr, port_buffer, &_SockAddr, &result);
        if (s != 0) {
            httpexception[HTTPException::Critical] << "getaddrinfo failed " << gai_strerror(s);
            throw httpexception;
        }
        
        /* getaddrinfo() returns a list of address structures.
         *  Try each address until we successfully bind(2).
         *  If socket(2) (or bind(2)) fails, we (close the socket
         *  and) try the next address. */
        
        for (rp = result; rp != NULL; rp = rp->ai_next) {
            Socket = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);
            if (Socket == -1)
                continue;
            
            int optval = 1;
            setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
           
            if (bind(Socket, rp->ai_addr, rp->ai_addrlen) == 0)
                break;                  /* Success */
                
            close(Socket);
        }
        
        if (rp == NULL) {               /* No address succeeded */
            httpexception[HTTPException::Critical] << "Could not bind\n";
            throw httpexception;
        }
        freeaddrinfo(result);
    }
    
    libhttppp::ServerSocket::~ServerSocket(){
        if(_UXSocketAddr)
            unlink(_UXSocketAddr->sun_path);
        delete _UXSocketAddr;
    }
    
    void libhttppp::ServerSocket::setnonblocking(){
        fcntl(Socket, F_SETFL, fcntl(Socket, F_GETFL, 0) | O_NONBLOCK);
    }
    
    void libhttppp::ServerSocket::listenSocket(){
        HTTPException httpexception;
        if(listen(Socket, _Maxconnections) < 0){
            httpexception[HTTPException::Critical] << "Can't listen Server Socket"<< errno;
            throw httpexception;
        }
    }
    
    int libhttppp::ServerSocket::getSocket(){
        return Socket;
    }
    
    int libhttppp::ServerSocket::getMaxconnections(){
        return _Maxconnections;
    }
    
    int libhttppp::ServerSocket::acceptEvent(ClientSocket *clientsocket){
        HTTPException httpexception;
        clientsocket->_ClientAddrLen=sizeof(clientsocket);
        int socket = accept(Socket,clientsocket->_ClientAddr, &clientsocket->_ClientAddrLen);
        if(socket<0){
    #ifdef __GLIBCXX__
            char errbuf[255];
            if(errno == EAGAIN)
                httpexception[HTTPException::Warning] << "Can't accept on  Socket"  << errbuf;
            else
                httpexception[HTTPException::Error] << "Can't accept on  Socket" << strerror_r(errno, errbuf, 255);
    #else
            char errbuf[255];
            strerror_r(errno, errbuf, 255);
            if(errno == EAGAIN)
                httpexception[HTTPException::Warning] << "Can't accept on  Socket"  << errbuf;
            else
                httpexception[HTTPException::Error] << "Can't accept on  Socket" << errbuf;
    #endif
        }
        clientsocket->Socket=socket;
        if(isSSLTrue()){
            clientsocket->_SSL = SSL_new(_CTX);
            SSL_set_fd(clientsocket->_SSL, socket);
            if (SSL_accept(clientsocket->_SSL) <= 0) {
                ERR_print_errors_fp(stderr);
                return -1;
            }
        }
        return socket;
    }
    
    
    
    ssize_t libhttppp::ServerSocket::sendData(ClientSocket* socket, void* data, size_t size){
        return sendData(socket,data,size,0);
    }
    
    ssize_t libhttppp::ServerSocket::sendData(ClientSocket* socket, void* data, size_t size,int flags){
        HTTPException httpexception;
        ssize_t rval=0;
        if(isSSLTrue() && socket->_SSL){
            rval=SSL_write(socket->_SSL,data,size);
        }else{
            rval=sendto(socket->Socket,data,size,flags,(struct sockaddr*)socket->_ClientAddr,sizeof(struct sockaddr));
        }
        if(rval<0){
            char errbuf[255];
    #ifdef __GLIBCXX__
            if(errno==EAGAIN)
                httpexception[HTTPException::Warning] << "Socket sendata:" << strerror_r(errno,errbuf,255);   
            else
                httpexception[HTTPException::Error] << "Socket sendata:" << strerror_r(errno,errbuf,255);
    #else
            strerror_r(errno,errbuf,255);
            if(errno == EAGAIN)
                httpexception[HTTPException::Warning] << "Socket sendata:" << errbuf;
            else 
                httpexception[HTTPException::Error] << "Socket sendata:" << errbuf;
    #endif
            throw httpexception;
        }
        return rval;
    }
    
    ssize_t libhttppp::ServerSocket::recvData(ClientSocket* socket, void* data, size_t size){
        return recvData(socket,data,size,0);
    }
    
    ssize_t libhttppp::ServerSocket::recvData(ClientSocket* socket, void* data, size_t size,int flags){
        HTTPException httpexception;
        ssize_t recvsize=0;
        if(isSSLTrue() && socket->_SSL){
            recvsize=SSL_read(socket->_SSL,data,size);
        }else{
            recvsize=recvfrom(socket->Socket,data, size,flags,
                              socket->_ClientAddr, &socket->_ClientAddrLen);
        }
        if(recvsize<0){
            char errbuf[255];
    #ifdef __GLIBCXX__ 
            if(errno==EAGAIN){
                httpexception[HTTPException::Warning] << "Socket recvdata "  <<  socket->Socket << ": "<< strerror_r(errno,errbuf,255);
            }else{
                httpexception[HTTPException::Error] << "Socket recvdata " << socket->Socket << ": " << strerror_r(errno,errbuf,255);
            }
    #else
            strerror_r(errno,errbuf,255);
            if(errno == EAGAIN)
                httpexception[HTTPException::Warning] << "Socket recvdata:" << socket->Socket << ": " << errbuf;
            else
                httpexception[HTTPException::Critical] << "Socket recvdata:" << socket->Socket << ":" <<  errbuf;
    #endif
            throw httpexception;
        }
        return recvsize;
    }
    


  • @Tuxist1 solved externen trigger gesetzt und nur auf pollin ausser es wird gesendet


Log in to reply