isearch/comm/poller.cc
2021-03-19 18:38:34 +08:00

358 lines
6.9 KiB
C++

#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <fcntl.h>
#include "memcheck.h"
#include "poll_thread.h"
#include "poller.h"
#include "log.h"
CPollerObject::~CPollerObject ()
{
if (ownerUnit && epslot)
ownerUnit->FreeEpollSlot (epslot);
if (netfd > 0) {
log_debug("%d fd been closed!",netfd);
close (netfd);
netfd = 0;
}
if(eventSlot)
{
eventSlot->poller = NULL;
eventSlot = NULL;
}
}
int CPollerObject::AttachPoller (CPollerUnit *unit)
{
if(unit) {
if( ownerUnit==NULL)
ownerUnit = unit;
else
return -1;
}
if(netfd < 0)
return -1;
if(epslot <= 0) {
if (!(epslot = ownerUnit->AllocEpollSlot ()))
return -1;
struct CEpollSlot *slot = ownerUnit->GetSlot(epslot);
slot->poller = this;
int flag = fcntl (netfd, F_GETFL);
fcntl (netfd, F_SETFL, O_NONBLOCK | flag);
struct epoll_event ev;
memset(&ev,0x0,sizeof(ev));
ev.events = newEvents;
slot->seq++;
ev.data.u64 = ((unsigned long long)slot->seq << 32) + epslot;
if (ownerUnit->Epctl (EPOLL_CTL_ADD, netfd, &ev) == 0)
oldEvents = newEvents;
else {
ownerUnit->FreeEpollSlot(epslot);
log_warning("Epctl: %m");
return -1;
}
return 0;
}
return ApplyEvents ();
}
int CPollerObject::DetachPoller() {
if(epslot) {
struct epoll_event ev;
memset(&ev,0x0,sizeof(ev));
if (ownerUnit->Epctl (EPOLL_CTL_DEL, netfd, &ev) == 0)
oldEvents = newEvents;
else {
log_warning("Epctl: %m");
return -1;
}
ownerUnit->FreeEpollSlot(epslot);
epslot = 0;
}
return 0;
}
int CPollerObject::ApplyEvents ()
{
if (epslot <= 0 || oldEvents == newEvents)
return 0;
struct epoll_event ev;
memset(&ev,0x0,sizeof(ev));
ev.events = newEvents;
struct CEpollSlot *slot = ownerUnit->GetSlot(epslot);
slot->seq++;
ev.data.u64 = ((unsigned long long)slot->seq << 32) + epslot;
if (ownerUnit->Epctl (EPOLL_CTL_MOD, netfd, &ev) == 0)
oldEvents = newEvents;
else {
log_warning("Epctl: %m");
return -1;
}
return 0;
}
int CPollerObject::DelayApplyEvents ()
{
if (epslot <= 0 || oldEvents == newEvents)
return 0;
if(eventSlot)
return 0;
eventSlot = ownerUnit->AddDelayEventPoller(this);
if(eventSlot == NULL)
{
log_error("max events!!!!!!");
struct epoll_event ev;
ev.events = newEvents;
struct CEpollSlot *slot = ownerUnit->GetSlot(epslot);
slot->seq++;
ev.data.u64 = ((unsigned long long)slot->seq << 32) + epslot;
if (ownerUnit->Epctl (EPOLL_CTL_MOD, netfd, &ev) == 0)
oldEvents = newEvents;
else {
log_warning("Epctl: %m");
return -1;
}
}
return 0;
}
int CPollerObject::CheckLinkStatus(void)
{
char msg[1] = {0};
int err = 0;
err = recv(netfd, msg, sizeof(msg), MSG_DONTWAIT|MSG_PEEK);
/* client already close connection. */
if(err == 0 || (err < 0 && errno != EAGAIN))
return -1;
return 0;
}
void CPollerObject::InitPollFd(struct pollfd *pfd)
{
pfd->fd = netfd;
pfd->events = newEvents;
pfd->revents = 0;
}
void CPollerObject::InputNotify(void) {
EnableInput(false);
}
void CPollerObject::OutputNotify(void) {
EnableOutput(false);
}
int CPollerUnit::totalEventSlot = 40960;
void CPollerObject::HangupNotify(void) {
delete this;
}
CPollerUnit::CPollerUnit(int mp)
{
maxPollers = mp;
eeSize = maxPollers > 1024 ? 1024 : maxPollers;
epfd = -1;
ep_events = NULL;
pollerTable = NULL;
freeSlotList = 0;
usedPollers = 0;
//not initailize eventCnt variable may crash, fix crash bug by linjinming 2014-05-18
eventCnt = 0;
}
CPollerUnit::~CPollerUnit() {
// skip first one
for (int i = 1; i < maxPollers; i++)
{
if (pollerTable[i].freeList)
continue;
delete pollerTable[i].poller;
}
FREE_CLEAR(pollerTable);
if (epfd != -1)
{
close (epfd);
epfd = -1;
}
FREE_CLEAR(ep_events);
}
int CPollerUnit::SetMaxPollers(int mp)
{
if(epfd >= 0)
return -1;
maxPollers = mp;
return 0;
}
int CPollerUnit::InitializePollerUnit(void)
{
pollerTable = (struct CEpollSlot *)CALLOC(maxPollers, sizeof (*pollerTable));
if (!pollerTable)
{
log_error("calloc failed, num=%d, %m", maxPollers);
return -1;
}
// already zero-ed
for (int i = 1; i < maxPollers - 1; i++)
{
pollerTable[i].freeList = i+1;
}
pollerTable[maxPollers - 1].freeList = 0;
freeSlotList = 1;
ep_events = (struct epoll_event *)CALLOC(eeSize, sizeof (struct epoll_event));
if (!ep_events)
{
log_error("malloc failed, %m");
return -1;
}
if ((epfd = epoll_create (maxPollers)) == -1)
{
log_warning("epoll_create failed, %m");
return -1;
}
fcntl(epfd, F_SETFD, FD_CLOEXEC);
return 0;
}
inline int CPollerUnit::VerifyEvents (struct epoll_event *ev)
{
int idx = EPOLL_DATA_SLOT (ev);
if ((idx >= maxPollers) || (EPOLL_DATA_SEQ (ev) != pollerTable[idx].seq))
{
return -1;
}
if(pollerTable[idx].poller == NULL || pollerTable[idx].freeList != 0)
{
log_notice("receive invalid epoll event. idx=%d seq=%d poller=%p freelist=%d event=%x",
idx, (int)EPOLL_DATA_SEQ(ev), pollerTable[idx].poller,
pollerTable[idx].freeList, ev->events);
return -1;
}
return 0;
}
void CPollerUnit::FreeEpollSlot (int n)
{
if(n <= 0) return;
pollerTable[n].freeList = freeSlotList;
freeSlotList = n;
usedPollers--;
pollerTable[n].seq++;
pollerTable[n].poller = NULL;
}
int CPollerUnit::AllocEpollSlot ()
{
if (0 == freeSlotList)
{
log_crit("no free epoll slot, usedPollers = %d", usedPollers);
return -1;
}
int n = freeSlotList;
usedPollers++;
freeSlotList = pollerTable[n].freeList;
pollerTable[n].freeList = 0;
return n;
}
int CPollerUnit::Epctl (int op, int fd, struct epoll_event *events)
{
if (epoll_ctl (epfd, op, fd, events) == -1)
{
log_warning("epoll_ctl error, epfd=%d, fd=%d", epfd, fd);
return -1;
}
return 0;
}
int CPollerUnit::WaitPollerEvents(int timeout) {
nrEvents = epoll_wait (epfd, ep_events, eeSize, timeout);
return nrEvents;
}
void CPollerUnit::ProcessPollerEvents(void) {
for (int i = 0; i < nrEvents; i++)
{
if(VerifyEvents (ep_events+i) == -1)
{
log_notice("VerifyEvents failed, ep_events[%d].data.u64 = %llu", i, (unsigned long long)ep_events[i].data.u64);
continue;
}
CEpollSlot *s = &pollerTable[EPOLL_DATA_SLOT(ep_events+i)];
CPollerObject *p = s->poller;
p->newEvents = p->oldEvents;
if(ep_events[i].events & (EPOLLHUP | EPOLLERR))
{
p->HangupNotify();
continue;
}
if(ep_events[i].events & EPOLLIN)
p->InputNotify();
s = &pollerTable[EPOLL_DATA_SLOT(ep_events+i)];
if(s->poller==p && ep_events[i].events & EPOLLOUT)
p->OutputNotify();
s = &pollerTable[EPOLL_DATA_SLOT(ep_events+i)];
if(s->poller==p)
p->DelayApplyEvents();
}
}
int CPollerUnit::DelayApplyEvents()
{
for(int i = 0; i < eventCnt; i++)
{
CPollerObject * p = eventSlot[i].poller;
if(p)
{
p->ApplyEvents();
eventSlot[i].poller = NULL;
p->ClearDelayApplyEvents();
}
}
eventCnt = 0;
return 0;
}