From 82b4cb57ed25967e43e965fdd02c93f8a89e3ab8 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 25 Aug 2014 18:52:57 +0100 Subject: [PATCH] add epoll communication manager --- include/Makefile.am | 1 + include/tr/comm_manager_epoll.h | 44 +++++++ include/trcomm.h | 1 + src/Makefile.am | 1 + src/comm_manager_epoll.c | 203 ++++++++++++++++++++++++++++++++ src/server.c | 3 +- 6 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 include/tr/comm_manager_epoll.h create mode 100644 src/comm_manager_epoll.c diff --git a/include/Makefile.am b/include/Makefile.am index a0d88a9..937e6a4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,7 @@ nobase_include_HEADERS = trcomm.h \ tr/comm_end_point.h \ tr/comm_manager.h \ tr/comm_manager_poll.h \ + tr/comm_manager_epoll.h \ tr/connect_entry_point.h \ tr/connection.h \ tr/connector.h \ diff --git a/include/tr/comm_manager_epoll.h b/include/tr/comm_manager_epoll.h new file mode 100644 index 0000000..d7f4051 --- /dev/null +++ b/include/tr/comm_manager_epoll.h @@ -0,0 +1,44 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2014 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TR_COMM_MANAGER_EPOLL_H__ +#define __TR_COMM_MANAGER_EPOLL_H__ + +#include + +#include "trbase.h" +#include "trevent.h" + +TR_CLASS(TR_CommManagerEpoll) { + TR_EXTENDS(TR_CommManager); + + int handle; +}; +TR_INSTANCE_INIT(TR_CommManagerEpoll); +TR_CLASSVARS_DECL(TR_CommManagerEpoll) { + TR_CV_EXTENDS(TR_EventHandler); +}; + +#endif // __TR_COMM_MANAGER_EPOLL_H__ + +// vim: set ts=4 sw=4: + diff --git a/include/trcomm.h b/include/trcomm.h index 26b72aa..e6d26f2 100644 --- a/include/trcomm.h +++ b/include/trcomm.h @@ -4,6 +4,7 @@ #include "tr/comm_end_point.h" #include "tr/comm_manager.h" #include "tr/comm_manager_poll.h" +#include "tr/comm_manager_epoll.h" #include "tr/connect_entry_point.h" #include "tr/connection.h" #include "tr/connector.h" diff --git a/src/Makefile.am b/src/Makefile.am index fa68c64..84c6105 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,7 @@ TRCOMM = cep_append_read_data.c \ comm_end_point.c \ comm_manager.c \ comm_manager_poll.c \ + comm_manager_epoll.c \ comm_manager_shutdown.c \ conn_entry_point.c \ connection.c \ diff --git a/src/comm_manager_epoll.c b/src/comm_manager_epoll.c new file mode 100644 index 0000000..019566f --- /dev/null +++ b/src/comm_manager_epoll.c @@ -0,0 +1,203 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2014 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "trbase.h" +#include "trevent.h" + +#include "tr/comm_manager.h" +#include "tr/comm_manager_epoll.h" +#include "tr/interface/comm_manager.h" +#include "tr/comm_end_point.h" +#include "tr/connection.h" +#include "tr/connect_entry_point.h" + +#define MAXEVENTS 64 + +struct epoll_event events[64]; + +static +int +commManagerEpollCtor(void * _this, va_list * params) +{ + TR_CommManagerEpoll this = _this; + TR_CommManager cmgr = _this; + + TR_PARENTCALL(TR_CommManagerEpoll, _this, TR_Class, ctor, params); + this->handle = epoll_create(cmgr->n_endpoints); + + return 0; +} + +static +void +commManagerEpollDtor(void * _this) +{ + TR_CommManagerEpoll this = _this; + + close(this->handle); +} + +static +void +TR_commManagerEpollAddEndpoint(void * _this, TR_CommEndPoint endpoint) +{ + TR_CommManagerEpoll this = _this; + struct epoll_event event; + + event.data.ptr = endpoint; + event.events = EPOLLIN | EPOLLET; + + epoll_ctl(this->handle, EPOLL_CTL_ADD, endpoint->transport->handle, &event); +} + +static +void +TR_commManagerEpollSelect(void * _this, TR_Event event, int timeout) +{ + TR_CommManagerEpoll this = _this; + int i, nevents; + + nevents = epoll_wait(this->handle, events, MAXEVENTS, timeout); + + for (i=0; itransport) + && ((TR_TcpSocket)endpoint->transport)->listen) { + event = TR_eventSubjectEmit( + (TR_EventSubject)endpoint, + TR_CET_EVENT_ACC_READY, + NULL); + } else { + event = TR_eventSubjectEmit( + (TR_EventSubject)endpoint, + TR_CEP_EVENT_READ_READY, + NULL); + } + + TR_eventHandlerIssueEvent((TR_EventHandler)this, event); + } + + if ((events[i].events & POLLOUT) == POLLOUT) { + TR_eventHandlerIssueEvent( + (TR_EventHandler)this, + TR_eventSubjectEmit( + (TR_EventSubject)endpoint, + TR_CEP_EVENT_WRITE_READY, + NULL)); + } + } +} + +static +void +TR_commManagerEpollEnableWrite(void * _this, TR_Event event) +{ + TR_CommManagerEpoll this = _this; + TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject; + + if (! TR_socketFinWr(endpoint->transport)) { + struct epoll_event epevent; + + epevent.data.ptr = endpoint; + epevent.events = EPOLLOUT | EPOLLIN | EPOLLET; + + epoll_ctl( + this->handle, + EPOLL_CTL_MOD, + endpoint->transport->handle, + &epevent); + } +} + +static +void +TR_commManagerEpollDisableWrite(void * _this, TR_Event event) +{ + TR_CommManagerEpoll this = _this; + TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject; + struct epoll_event epevent; + + epevent.data.ptr = endpoint; + epevent.events = EPOLLIN | EPOLLET; + + epoll_ctl( + this->handle, + EPOLL_CTL_MOD, + endpoint->transport->handle, + &epevent); +} + +static +void +TR_commManagerEpollClose(void * _this, TR_Event event) +{ + TR_CommManagerEpoll this = _this; + TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject; + + epoll_ctl(this->handle, EPOLL_CTL_DEL, endpoint->transport->handle, NULL); +} + +static +void +TR_commManagerEpollEnableRead(void * _this, TR_Event event) +{ +} + +static +void +TR_commManagerEpollDisableRead(void * _this, TR_Event event) +{ +} + +static +void +TR_commManagerEpollCvInit(TR_class_ptr cls) { + TR_INHERIT_CLASSVARS(TR_CommManagerEpoll, TR_CommManager); +} + +TR_INIT_IFACE(TR_Class, commManagerEpollCtor, commManagerEpollDtor, NULL); +TR_INIT_IFACE( + TR_CommManager, + TR_commManagerEpollAddEndpoint, + TR_commManagerEpollSelect, + TR_commManagerEpollEnableWrite, + TR_commManagerEpollDisableWrite, + TR_commManagerEpollEnableRead, + TR_commManagerEpollClose, + TR_commManagerEpollDisableRead, + TR_commManagerEpollDisableWrite); +TR_CREATE_CLASS( + TR_CommManagerEpoll, + TR_CommManager, + TR_commManagerEpollCvInit, + TR_IF(TR_Class), + TR_IF(TR_CommManager)); + +// vim: set ts=4 sw=4: diff --git a/src/server.c b/src/server.c index c9b2371..bc512e1 100644 --- a/src/server.c +++ b/src/server.c @@ -31,6 +31,7 @@ #include "tr/server.h" #include "tr/comm_manager.h" #include "tr/comm_manager_poll.h" +#include "tr/comm_manager_epoll.h" #include "tr/connector.h" #include "tr/io_handler.h" #include "tr/protocol_handler.h" @@ -42,7 +43,7 @@ serverCtor(void * _this, va_list * params) { TR_Server this = _this; - this->comm_manager = (TR_CommManager)TR_new(TR_CommManagerPoll); + this->comm_manager = (TR_CommManager)TR_new(TR_CommManagerEpoll); this->dispatcher = TR_new(TR_EventDispatcher, TR_EVD_SERVER, NULL, 100); this->connector = TR_new(TR_Connector); this->io_handler = TR_new(TR_IoHandler);