summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure32
-rw-r--r--src/commands.cpp20
-rw-r--r--src/inspircd.cpp193
-rw-r--r--src/modules.cpp21
4 files changed, 219 insertions, 47 deletions
diff --git a/configure b/configure
index 428328e42..3cceec02e 100755
--- a/configure
+++ b/configure
@@ -28,6 +28,7 @@ $config{MAX_CHANNE} = "20"; # Default Max.
$config{MAXI_MODES} = "20"; # Default Max. Number of Modes set at once.
$config{HAS_STRLCPY} = "false"; # strlcpy Check.
$config{USE_KQUEUE} = "n"; # kqueue enabled
+$config{USE_EPOLL} = "n"; # epoll enabled
chomp($config{MAX_CLIENT_T} = `sh -c \"ulimit -n\"`); # FD Limit
chomp($config{GCCVER} = `gcc -dumpversion | cut -c 1`); # Major GCC Version
chomp($config{GCC34} = `gcc -dumpversion | cut -c 3`); # Minor GCC Version
@@ -117,6 +118,26 @@ if (!$fail)
print "yes\n" if $has_kqueue == 1;
print "no\n" if $has_kqueue == 0;
+printf "Checking if epoll exists... ";
+$has_epoll = 0;
+$fail = 0;
+open(EPOLL, "</usr/include/sys/epoll.h") or $fail = 1;
+if (!$fail)
+{
+ while (chomp($line = <EPOLL>))
+ {
+ # try and find the declaration of:
+ # extern int epoll_create (int __size) __THROW;
+ if (($line =~ /int(\0x9|\s)+epoll_create(\0x9|\s)+\(/) || ($line =~ /int(\0x9|\s)+epoll_create\(/))
+ {
+ $has_epoll = 1;
+ }
+ }
+ close(EPOLL);
+}
+print "yes\n" if $has_epoll == 1;
+print "no\n" if $has_epoll == 0;
+
################################################################################
# BEGIN INTERACTIVE PART #
################################################################################
@@ -152,6 +173,9 @@ dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
if ($has_kqueue) {
yesno(USE_KQUEUE,"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nIf you are unsure, answer no.\n\nEnable kqueue?");
}
+if ($has_epoll) {
+ yesno(USE_EPOLL,"You are running a linux operating system, and epoll\nwas detected. Would you like to enable epoll support?\nIf you are unsure, answer no.\n\nEnable epoll?");
+}
# File Descriptor Settings..
my $continue = 0;
@@ -422,6 +446,14 @@ EOF
if ($config{USE_KQUEUE} eq "y") {
print FILEHANDLE "#define USE_KQUEUE\n";
}
+ if ($config{USE_EPOLL} eq "y") {
+ print FILEHANDLE "#define USE_EPOLL\n";
+ }
+ # user didn't choose either epoll or select for their OS.
+ # default them to USE_SELECT (ewwy puke puke)
+ if (($config{USE_EPOLL} eq "n") && ($config{USE_KQUEUE} eq "n")) {
+ print FILEHANDLE "#define USE_SELECT\n";
+ }
close(FILEHANDLE);
# Create a Modules List..
diff --git a/src/commands.cpp b/src/commands.cpp
index 5ffd870da..5011b7d61 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -24,11 +24,17 @@ using namespace std;
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
+
#ifdef USE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif
+
+#ifdef USE_EPOLL
+#include <sys/epoll.h>
+#endif
+
#include <cstdio>
#include <time.h>
#include <string>
@@ -68,6 +74,10 @@ using namespace std;
extern int kq;
#endif
+#ifdef USE_EPOLL
+int ep;
+#endif
+
extern int MODCOUNT;
extern std::vector<Module*> modules;
extern std::vector<ircd_module*> factory;
@@ -921,6 +931,16 @@ void handle_quit(char **parameters, int pcnt, userrec *user)
log(DEBUG,"kqueue: Failed to remove user from queue!");
}
#endif
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = user->fd;
+ int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List deletion failure!");
+ }
+#endif
shutdown(user->fd,2);
close(user->fd);
}
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index a0cfb008d..52f7b6479 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -27,11 +27,18 @@ using namespace std;
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
+
#ifdef USE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif
+
+#ifdef USE_EPOLL
+#include <sys/epoll.h>
+#define EP_DELAY 10
+#endif
+
#include <time.h>
#include <string>
#ifdef GCC3
@@ -107,6 +114,10 @@ time_t TIME = time(NULL), OLDTIME = time(NULL);
int kq, lkq, skq;
#endif
+#ifdef USE_EPOLL
+int ep, lep, sep;
+#endif
+
typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, irc::InAddr_HashComp> address_cache;
@@ -1077,6 +1088,16 @@ void kill_link(userrec *user,const char* r)
log(DEBUG,"kqueue: Failed to remove user from queue!");
}
#endif
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = user->fd;
+ int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List deletion failure!");
+ }
+#endif
shutdown(user->fd,2);
close(user->fd);
}
@@ -1141,6 +1162,16 @@ void kill_link_silent(userrec *user,const char* r)
log(DEBUG,"kqueue: Failed to remove user from queue!");
}
#endif
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = user->fd;
+ int i = epoll_ctl(ep, EPOLL_CTL_DEL, user->fd, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List deletion failure!");
+ }
+#endif
shutdown(user->fd,2);
close(user->fd);
}
@@ -1417,6 +1448,17 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
}
fd_ref_table[socket] = clientlist[tempnick];
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ log(DEBUG,"epoll: Adduser to events, ep=%d socket=%d",ep,socket);
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = socket;
+ int i = epoll_ctl(ep, EPOLL_CTL_ADD, socket, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List insertion failure!");
+ }
+#endif
#ifdef USE_KQUEUE
struct kevent ke;
log(DEBUG,"kqueue: Add user to events, kq=%d socket=%d",kq,socket);
@@ -1424,37 +1466,7 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
int i = kevent(kq, &ke, 1, 0, 0, NULL);
if (i == -1)
{
- switch (errno)
- {
- case EACCES:
- log(DEBUG,"kqueue: EACCES");
- break;
- case EFAULT:
- log(DEBUG,"kqueue: EFAULT");
- break;
- case EBADF:
- log(DEBUG,"kqueue: EBADF=%d",ke.ident);
- break;
- case EINTR:
- log(DEBUG,"kqueue: EINTR");
- break;
- case EINVAL:
- log(DEBUG,"kqueue: EINVAL");
- break;
- case ENOENT:
- log(DEBUG,"kqueue: ENOENT");
- break;
- case ENOMEM:
- log(DEBUG,"kqueue: ENOMEM");
- break;
- case ESRCH:
- log(DEBUG,"kqueue: ESRCH");
- break;
- default:
- log(DEBUG,"kqueue: UNKNOWN!");
- break;
- }
- log(DEBUG,"kqueue: Failed to add user to queue!");
+ log(DEBUG,"kqueue: List insertion failure!");
}
#endif
@@ -1569,9 +1581,13 @@ std::string GetVersionString()
s1 = savept;
#ifdef USE_KQUEUE
char socketengine[] = "kqueue";
-#else
+#endif
+#ifdef USE_SELECT
char socketengine[] = "select";
#endif
+#ifdef USE_EPOLL
+ char socketengine[] = "epoll";
+#endif
snprintf(versiondata,MAXBUF,"%s Rev. %s %s :%s (O=%lu) [SE=%s]",VERSION,v2,ServerName,SYSTEM,(unsigned long)OPTIMISATION,socketengine);
return versiondata;
}
@@ -2638,7 +2654,50 @@ int InspIRCd(char** argv, int argc)
}
#endif
+#ifdef USE_EPOLL
+ ep = epoll_create(MAXCLIENTS);
+ lep = epoll_create(32);
+ sep = epoll_create(128);
+ if ((ep == -1) || (lep == -1) || (sep == -1))
+ {
+ log(DEFAULT,"main: epoll_create() failed!");
+ printf("ERROR: could not initialise epoll event system. Shutting down.\n");
+ Exit(ERROR);
+ }
+#endif
+#ifdef USE_EPOLL
+ log(DEFAULT,"epoll socket engine is enabled. Filling listen list. boundPortcount=%d",boundPortCount);
+ for (count = 0; count < boundPortCount; count++)
+ {
+ struct epoll_event ev;
+ log(DEBUG,"epoll: Add listening socket to events, ep=%d socket=%d",lep,openSockfd[count]);
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = openSockfd[count];
+ int i = epoll_ctl(lep, EPOLL_CTL_ADD, openSockfd[count], &ev);
+ if (i < 0)
+ {
+ log(DEFAULT,"main: add listen ports, epoll_ctl failed!");
+ printf("ERROR: could not initialise listening sockets in epoll list. Shutting down.\n");
+ Exit(ERROR);
+ }
+
+ }
+ for (int t = 0; t != SERVERportCount; t++)
+ {
+ struct epoll_event ev;
+ log(DEBUG,"epoll: Add listening server socket to events, ep=%d socket=%d",sep,me[t]->fd);
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = me[t]->fd;
+ int i = epoll_ctl(sep, EPOLL_CTL_ADD, me[t]->fd, &ev);
+ if (i == -1)
+ {
+ log(DEFAULT,"main: add server listen ports, epoll_ctl failed!");
+ printf("ERROR: could not initialise server listening sockets in epoll list. Shutting down.\n");
+ Exit(ERROR);
+ }
+ }
+#else
#ifdef USE_KQUEUE
log(DEFAULT,"kqueue socket engine is enabled. Filling listen list.");
for (count = 0; count < boundPortCount; count++)
@@ -2651,6 +2710,7 @@ int InspIRCd(char** argv, int argc)
{
log(DEFAULT,"main: add listen ports to kqueue failed!");
printf("ERROR: could not initialise listening sockets in kqueue. Shutting down.\n");
+ Exit(ERROR);
}
}
for (int t = 0; t != SERVERportCount; t++)
@@ -2665,6 +2725,7 @@ int InspIRCd(char** argv, int argc)
{
log(DEFAULT,"main: add server listen ports to kqueue failed!");
printf("ERROR: could not initialise listening server sockets in kqueue. Shutting down.\n");
+ Exit(ERROR);
}
}
}
@@ -2673,6 +2734,7 @@ int InspIRCd(char** argv, int argc)
#else
log(DEFAULT,"Using standard select socket engine.");
#endif
+#endif
WritePID(PID);
@@ -2684,6 +2746,9 @@ int InspIRCd(char** argv, int argc)
struct kevent ke_list[33];
struct timespec ts;
#endif
+#ifdef USE_EPOLL
+ struct epoll_event event[33];
+#endif
fd_set serverfds;
timeval tvs;
tvs.tv_usec = 10000L;
@@ -2705,10 +2770,9 @@ int InspIRCd(char** argv, int argc)
#ifdef _POSIX_PRIORITY_SCHEDULING
sched_yield();
#endif
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
FD_ZERO(&sfd);
#endif
-
// we only read time() once per iteration rather than tons of times!
OLDTIME = TIME;
TIME = time(NULL);
@@ -2730,6 +2794,16 @@ int InspIRCd(char** argv, int argc)
// fix by brain - this must be below any manipulation of the hashmap by modules
user_hash::iterator count2 = clientlist.begin();
+#ifdef USE_EPOLL
+ i = epoll_wait(sep, event, 1, EP_DELAY);
+ if (i > 0)
+ {
+ log(DEBUG,"epoll: Listening server socket event, i=%d, event.data.fd=%d",i,event[0].data.fd);
+ for (int x = 0; x != SERVERportCount; x++)
+ {
+ if ((me[x]) && (event[0].data.fd == me[x]->fd))
+ {
+#endif
#ifdef USE_KQUEUE
ts.tv_sec = 0;
ts.tv_nsec = 30000L;
@@ -2742,7 +2816,8 @@ int InspIRCd(char** argv, int argc)
if ((me[x]) && (ke.ident == me[x]->fd))
{
-#else
+#endif
+#ifdef USE_SELECT
FD_ZERO(&serverfds);
for (int x = 0; x != SERVERportCount; x++)
{
@@ -2819,7 +2894,7 @@ int InspIRCd(char** argv, int argc)
while (count2 != clientlist.end())
{
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
FD_ZERO(&sfd);
#endif
@@ -2845,7 +2920,7 @@ int InspIRCd(char** argv, int argc)
//
// This should be up to 64x faster than the
// old implementation.
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
while (total_in_this_set < 1024)
{
if (count2 != clientlist.end())
@@ -2908,10 +2983,10 @@ int InspIRCd(char** argv, int argc)
endingiter = count2;
count2 = xcount; // roll back to where we were
#else
- // KQUEUE: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again.
+ // KQUEUE and EPOLL: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again.
// TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue.
cycle_iter++;
- if (cycle_iter > 10) while (count2 != clientlist.end())
+ if (cycle_iter > 20) while (count2 != clientlist.end())
{
cycle_iter = 0;
if (count2 != clientlist.end())
@@ -2973,7 +3048,14 @@ int InspIRCd(char** argv, int argc)
#endif
v = 0;
-
+#ifdef USE_EPOLL
+ int i = epoll_wait(ep, event, 1, EP_DELAY);
+ if (i > 0)
+ {
+ log(DEBUG,"epoll_wait call: ep=%d, i=%d",ep,i);
+ // EPOLL: we asked epoll_wait for ONE fd which is ready. Do something.
+ userrec* cu = fd_ref_table[event[0].data.fd];
+#endif
#ifdef USE_KQUEUE
ts.tv_sec = 0;
ts.tv_nsec = 1000L;
@@ -2984,7 +3066,8 @@ int InspIRCd(char** argv, int argc)
log(DEBUG,"kevent call: kq=%d, i=%d",kq,i);
// KQUEUE: kevent gives us ONE fd which is ready to have something done to it. Do something to it.
userrec* cu = fd_ref_table[ke.ident];
-#else
+#endif
+#ifdef USE_SELECT
tval.tv_usec = 1000L;
selectResult2 = select(65535, &sfd, NULL, NULL, &tval);
@@ -3000,10 +3083,15 @@ int InspIRCd(char** argv, int argc)
sched_yield();
#endif
result = EAGAIN;
+#ifdef USE_EPOLL
+ // EPOLL: We already know we have a valid FD. No checks needed.
+ if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
+#endif
#ifdef USE_KQUEUE
// KQUEUE: We already know we have a valid FD. No checks needed.
if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1))
-#else
+#endif
+#ifdef USE_SELECT
// SELECT: We don't know if our FD is valid.
if ((cu->fd != FD_MAGIC_NUMBER) && (cu->fd != -1) && (FD_ISSET (cu->fd, &sfd)))
#endif
@@ -3145,7 +3233,7 @@ int InspIRCd(char** argv, int argc)
else
if (result == 0)
{
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
if (count2->second)
{
#endif
@@ -3154,7 +3242,7 @@ int InspIRCd(char** argv, int argc)
// must bail here? kill_link removes the hash, corrupting the iterator
log(DEBUG,"Bailing from client exit");
goto label;
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
}
#endif
}
@@ -3173,7 +3261,7 @@ int InspIRCd(char** argv, int argc)
sched_yield();
#endif
-#ifndef USE_KQUEUE
+#ifdef USE_SELECT
// set up select call
for (count = 0; count < boundPortCount; count++)
{
@@ -3190,13 +3278,14 @@ int InspIRCd(char** argv, int argc)
{
if (FD_ISSET (openSockfd[count], &selectFds))
{
-#else
+#endif
+#ifdef USE_KQUEUE
ts.tv_sec = 0;
ts.tv_nsec = 30000L;
i = kevent(lkq, NULL, 0, ke_list, 32, &ts);
if (i > 0) for (j = 0; j < i; j++)
{
- log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke.ident);
+ log(DEBUG,"kqueue: Listening socket event, i=%d, ke.ident=%d",i,ke_list[j].ident);
// this isnt as efficient as it could be, we could create a reference table
// to reference bound ports by fd, but this isnt a big bottleneck as the actual
// number of listening ports on the average ircd is a small number (less than 20)
@@ -3206,6 +3295,16 @@ int InspIRCd(char** argv, int argc)
if (ke_list[j].ident == openSockfd[count])
{
#endif
+#ifdef USE_EPOLL
+ i = epoll_wait(lep, event, 32, EP_DELAY);
+ if (i > 0) for (j = 0; j < i; j++)
+ {
+ log(DEBUG,"epoll: Listening socket event, i=%d,events[j].data.fd=%d",i,event[j].data.fd);
+ for (count = 0; count < boundPortCount; count++)
+ {
+ if (event[j].data.fd == openSockfd[count])
+ {
+#endif
char target[MAXBUF], resolved[MAXBUF];
length = sizeof (client);
incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
diff --git a/src/modules.cpp b/src/modules.cpp
index ffc6e0c8d..b53dd4f7f 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -22,11 +22,17 @@ using namespace std;
#include "inspircd_config.h"
#include <unistd.h>
#include <sys/errno.h>
+
#ifdef USE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif
+
+#ifdef USE_EPOLL
+#include <sys/epoll.h>
+#endif
+
#include <time.h>
#include <string>
#ifdef GCC3
@@ -58,6 +64,10 @@ using namespace std;
extern int kq;
#endif
+#ifdef USE_EPOLL
+int ep;
+#endif
+
extern int MODCOUNT;
extern std::vector<Module*> modules;
extern std::vector<ircd_module*> factory;
@@ -621,6 +631,17 @@ bool Server::UserToPseudo(userrec* user,std::string message)
log(DEBUG,"kqueue: Failed to remove user from queue!");
}
#endif
+#ifdef USE_EPOLL
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = old_fd;
+ int i = epoll_ctl(ep, EPOLL_CTL_DEL, old_fd, &ev);
+ if (i < 0)
+ {
+ log(DEBUG,"epoll: List deletion failure!");
+ }
+#endif
+
shutdown(old_fd,2);
close(old_fd);
}