Archived
1
0
This repository has been archived on 2023-08-12. You can view files and clone it, but cannot push or open issues or pull requests.
nntpchan/contrib/backends/nntpchan-daemon/libnntpchan/kqueue.hpp

162 lines
5.2 KiB
C++
Raw Normal View History

2018-05-04 18:52:54 +05:00
#include <nntpchan/event.hpp>
#include <sys/types.h>
2018-05-04 18:52:54 +05:00
#include <sys/event.h>
2018-05-06 20:15:55 +05:00
#include <iostream>
2018-05-06 20:15:01 +05:00
#include <cstring>
2018-05-06 20:15:33 +05:00
#include <errno.h>
2018-05-06 17:52:37 +05:00
2018-05-04 18:52:54 +05:00
namespace nntpchan
{
namespace ev
{
2018-05-06 17:17:32 +05:00
template<size_t bufsz>
2018-05-04 18:52:54 +05:00
struct KqueueLoop : public Loop
{
int kfd;
size_t conns;
2018-05-06 17:17:32 +05:00
char readbuf[bufsz];
2018-05-04 18:52:54 +05:00
KqueueLoop() : kfd(kqueue()), conns(0)
{
};
virtual ~KqueueLoop()
{
::close(kfd);
}
virtual bool TrackConn(ev::io * handler)
{
struct kevent event;
2018-05-04 18:52:54 +05:00
short filter = 0;
if(handler->readable() || handler->acceptable())
{
filter |= EVFILT_READ;
}
2018-05-06 17:51:39 +05:00
if(handler->writeable())
2018-05-04 18:52:54 +05:00
{
filter |= EVFILT_WRITE;
}
EV_SET(&event, handler->fd, filter, EV_ADD | EV_CLEAR, 0, 0, handler);
int ret = kevent(kfd, &event, 1, nullptr, 0, nullptr);
if(ret == -1) return false;
if(event.flags & EV_ERROR)
{
std::cerr << "KqueueLoop::TrackConn() kevent failed: " << strerror(event.data) << std::endl;
return false;
}
++conns;
return true;
}
virtual void UntrackConn(ev::io * handler)
{
struct kevent event;
2018-05-04 18:52:54 +05:00
short filter = 0;
if(handler->readable() || handler->acceptable())
{
filter |= EVFILT_READ;
}
2018-05-06 17:52:37 +05:00
if(handler->writeable())
2018-05-04 18:52:54 +05:00
{
filter |= EVFILT_WRITE;
}
EV_SET(&event, handler->fd, filter, EV_DELETE, 0, 0, handler);
int ret = kevent(kfd, &event, 1, nullptr, 0, nullptr);
if(ret == -1 || event.flags & EV_ERROR)
2018-05-04 18:52:54 +05:00
std::cerr << "KqueueLoop::UntrackConn() kevent failed: " << strerror(event.data) << std::endl;
2018-05-06 17:53:41 +05:00
else
--conns;
2018-05-04 18:52:54 +05:00
}
virtual void Run()
{
struct kevent events[512];
struct kevent * event;
2018-05-04 18:52:54 +05:00
io * handler;
int ret, idx;
do
{
idx = 0;
2018-05-06 18:00:14 +05:00
ret = kevent(kfd, nullptr, 0, events, 512, nullptr);
2018-05-04 18:52:54 +05:00
if(ret > 0)
{
while(idx < ret)
{
event = &events[idx++];
2018-05-06 17:56:20 +05:00
handler = static_cast<io *>(event->udata);
if(event->flags & EV_EOF)
2018-05-04 18:52:54 +05:00
{
handler->close();
delete handler;
continue;
}
if(event->filter & EVFILT_READ && handler->acceptable())
2018-05-04 18:52:54 +05:00
{
int backlog = event->data;
2018-05-04 18:52:54 +05:00
while(backlog)
{
handler->accept();
--backlog;
}
}
if(event->filter & EVFILT_READ && handler->readable())
2018-05-04 18:52:54 +05:00
{
int readed = 0;
2018-05-06 17:59:03 +05:00
size_t readnum = event->data;
2018-05-04 18:52:54 +05:00
while(readnum > sizeof(readbuf))
{
int r = handler->read(readbuf, sizeof(readbuf));
if(r > 0)
{
readnum -= r;
readed += r;
}
else
readnum = 0;
}
if(readnum && readed != -1)
{
int r = handler->read(readbuf, readnum);
if(r > 0)
readed += r;
else
readed = r;
}
}
if(event->filter & EVFILT_WRITE && handler->writeable())
2018-05-04 18:52:54 +05:00
{
2018-05-06 20:06:40 +05:00
int writespace = 1024;
2018-05-04 19:08:09 +05:00
int written = handler->write(writespace);
2018-05-06 20:15:01 +05:00
if(written == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
// blocking
}
else
{
perror("write()");
handler->close();
delete handler;
continue;
}
}
2018-05-04 19:08:09 +05:00
}
if(!handler->keepalive())
{
handler->close();
delete handler;
2018-05-04 18:52:54 +05:00
}
}
}
}
while(ret != -1);
}
};
}
}