summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2005-05-09 20:56:44 +0000
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2005-05-09 20:56:44 +0000
commit8399a0bede79afd8f8a7cb23a4ded974584d437a (patch)
treee6251fa20dcbf07046730bb92e26142ca5abf811
parent5f5d2c12315effeeee24637266a25a814b9fdd73 (diff)
Basics of kqueue() implementation for socket engine
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@1348 e03df62e-2008-0410-955e-edbf42e46eb7
-rwxr-xr-xconfigure33
-rw-r--r--src/commands.cpp22
-rw-r--r--src/inspircd.cpp135
-rw-r--r--src/modules.cpp22
4 files changed, 193 insertions, 19 deletions
diff --git a/configure b/configure
index f33a8d503..0d8b13146 100755
--- a/configure
+++ b/configure
@@ -27,6 +27,7 @@ $config{CHAN_LENGT} = "64"; # Default Chan
$config{MAX_CHANNE} = "20"; # Default Max. Channels per user..
$config{MAXI_MODES} = "20"; # Default Max. Number of Modes set at once.
$config{HAS_STRLCPY} = "false"; # strlcpy Check.
+$config{USE_KQUEUE} = "false"; # kqueue 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
@@ -122,6 +123,12 @@ dir_check("are the modules to be compiled to", "MODULE_DIR");
dir_check("is the IRCd binary to be placed", "BINARY_DIR");
dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
+if ($config{OSNAME} =~ /BSD$/) {
+ if (yesno(0,"You are running a BSD operating system.\nWould you like to enable kqueue support?\nPlease be aware that kqueue support is\nEXPERIMENTAL and not gauranteed to work properly.\nIf you are unsure, answer no.\n\nEnable kqueue?")) {
+ $config{USE_KQUEUE} = "true";
+ }
+}
+
# File Descriptor Settings..
my $continue = 0;
while (!$continue) {
@@ -384,6 +391,9 @@ EOF
if ($config{HAS_STRLCPY} eq "true") {
print FILEHANDLE "#define HAS_STRLCPY\n";
}
+ if ($config{USE_KQUEUE} eq "true") {
+ print FILEHANDLE "#define USE_KQUEUE\n";
+ }
close(FILEHANDLE);
# Create a Modules List..
@@ -490,13 +500,20 @@ sub show_splash {
sub resolve_directory {
use File::Spec;
return File::Spec->rel2abs($_[0]);
+}
- #my $dir = $_[0];
- #my $old_dir = "";
- #my $real_dir = "";
- #getpwd($old_dir);
- #chdir($dir);
- #getpwd($real_dir);
- #chdir($old_dir);
- #return $real_dir;
+sub yesno {
+ my ($default,$prompt) = @_;
+ if (!$default) {
+ print "$prompt [\033[1;32mn\033[0m] ";
+ chomp($tmp = <STDIN>);
+ return ($tmp =~ /^y/i);
+
+ }
+ else {
+ print "$prompt [\033[1;32my\033[0m] ";
+ chomp($tmp = <STDIN>);
+ return (($tmp eq "") || ($tmp =~ /^y/i));
+ }
+ return 0;
}
diff --git a/src/commands.cpp b/src/commands.cpp
index 315caf9b9..f98ad5eb2 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -23,6 +23,11 @@
#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
#include <cstdio>
#include <time.h>
#include <string>
@@ -68,6 +73,10 @@
using namespace std;
+#ifdef USE_KQUEUE
+extern int kq;
+#endif
+
extern int MODCOUNT;
extern std::vector<Module*> modules;
extern std::vector<ircd_module*> factory;
@@ -960,8 +969,17 @@ void handle_quit(char **parameters, int pcnt, userrec *user)
/* push the socket on a stack of sockets due to be closed at the next opportunity */
if (user->fd > -1)
{
- shutdown(user->fd,2);
- close(user->fd);
+#ifdef USE_KQUEUE
+ struct kevent ke;
+ EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ int i = kevent(kq, &ke, 1, 0, 0, NULL);
+ if (i == -1)
+ {
+ log(DEBUG,"kqueue: Failed to remove user from queue!");
+ }
+#endif
+ shutdown(user->fd,2);
+ close(user->fd);
}
if (iter != clientlist.end())
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 3dee7cd29..79b34247c 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -27,6 +27,11 @@ 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
#include <cstdio>
#include <time.h>
#include <string>
@@ -106,6 +111,10 @@ bool unlimitcore = false;
time_t TIME = time(NULL);
+#ifdef USE_KQUEUE
+int kq;
+#endif
+
namespace nspace
{
#ifdef GCC34
@@ -2192,8 +2201,17 @@ void kill_link(userrec *user,const char* r)
if (user->fd > -1)
{
FOREACH_MOD OnRawSocketClose(user->fd);
- shutdown(user->fd,2);
- close(user->fd);
+#ifdef USE_KQUEUE
+ struct kevent ke;
+ EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ int i = kevent(kq, &ke, 1, 0, 0, NULL);
+ if (i == -1)
+ {
+ log(DEBUG,"kqueue: Failed to remove user from queue!");
+ }
+#endif
+ shutdown(user->fd,2);
+ close(user->fd);
}
if (user->registered == 7) {
@@ -2247,6 +2265,15 @@ void kill_link_silent(userrec *user,const char* r)
if (user->fd > -1)
{
FOREACH_MOD OnRawSocketClose(user->fd);
+#ifdef USE_KQUEUE
+ struct kevent ke;
+ EV_SET(&ke, user->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ int i = kevent(kq, &ke, 1, 0, 0, NULL);
+ if (i == -1)
+ {
+ log(DEBUG,"kqueue: Failed to remove user from queue!");
+ }
+#endif
shutdown(user->fd,2);
close(user->fd);
}
@@ -2370,6 +2397,16 @@ int main(int argc, char** argv)
lowermap[']'] = '}';
lowermap['\\'] = '|';
+#ifdef USE_KQUEUE
+ kq = kqueue();
+ if (kq == -1)
+ {
+ log(DEFAULT,"main: kqueue() failed!");
+ printf("ERROR: could not initialise kqueue event system. Shutting down.\n");
+ Exit(ERROR);
+ }
+#endif
+
if (InspIRCd(argv,argc) == ERROR)
{
log(DEFAULT,"main: daemon function bailed");
@@ -2574,6 +2611,17 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
}
}
fd_ref_table[socket] = clientlist[tempnick];
+
+#ifdef USE_KQUEUE
+ struct kevent ke;
+ EV_SET(&ke, socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ int i = kevent(kq, &ke, 1, 0, 0, NULL);
+ if (i == -1)
+ {
+ log(DEBUG,"kqueue: Failed to add user to queue!");
+ }
+
+#endif
}
// this function counts all users connected, wether they are registered or NOT.
@@ -4165,10 +4213,10 @@ int InspIRCd(char** argv, int argc)
}
}
-
while (count2 != clientlist.end())
{
FD_ZERO(&sfd);
+
total_in_this_set = 0;
user_hash::iterator xcount = count2;
@@ -4191,6 +4239,7 @@ int InspIRCd(char** argv, int argc)
//
// This should be up to 64x faster than the
// old implementation.
+#ifndef USE_KQUEUE
while (total_in_this_set < 1024)
{
if (count2 != clientlist.end())
@@ -4242,14 +4291,78 @@ int InspIRCd(char** argv, int argc)
}
else break;
}
-
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.
+ // TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue.
+ while (count2 != clientlist.end())
+ {
+ if (count2 != clientlist.end())
+ {
+ curr = count2->second;
+ // we don't check the state of remote users.
+ if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
+ {
+ // registration timeout -- didnt send USER/NICK/HOST in the time specified in
+ // their connection class.
+ if ((TIME > curr->timeout) && (curr->registered != 7))
+ {
+ log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick);
+ kill_link(curr,"Registration timeout");
+ goto label;
+ }
+ if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr)))
+ {
+ log(DEBUG,"signon exceed, registered=3, and modules ready, OK");
+ curr->dns_done = true;
+ statsDnsBad++;
+ FullConnectUser(curr);
+ goto label;
+ }
+ if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr)))
+ {
+ log(DEBUG,"dns done, registered=3, and modules ready, OK");
+ FullConnectUser(curr);
+ goto label;
+ }
+ if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7))
+ {
+ if ((!curr->lastping) && (curr->registered == 7))
+ {
+ log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick);
+ kill_link(curr,"Ping timeout");
+ goto label;
+ }
+ Write(curr->fd,"PING :%s",ServerName);
+ log(DEBUG,"InspIRCd: pinging: %s",curr->nick);
+ curr->lastping = 0;
+ curr->nping = TIME+curr->pingmax; // was hard coded to 120
+ }
+ }
+ }
+ else break;
+ count2++;
+ }
+ // increment the counter right to the end of the list, as kqueue processes everything in one go
+#endif
v = 0;
- // tvals defined here
-
+#ifdef USE_KQUEUE
+ struct kevent ke;
+ int fd_to_process = 0;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000L;
+ // for now, we only read 1 event. We could read soooo many more :)
+ int i = kevent(kq, NULL, 0, &ke, 1, &ts);
+ if (i > 0)
+ {
+ 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
tval.tv_usec = 1000L;
selectResult2 = select(65535, &sfd, NULL, NULL, &tval);
@@ -4257,13 +4370,21 @@ int InspIRCd(char** argv, int argc)
if (selectResult2 > 0)
for (user_hash::iterator count2a = xcount; count2a != endingiter; count2a++)
{
+ // SELECT: we have to iterate...
+ userrec* cu = count2a->second;
+#endif
#ifdef _POSIX_PRIORITY_SCHEDULING
sched_yield();
#endif
- userrec* cu = count2a->second;
result = EAGAIN;
+#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
+ // 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
{
log(DEBUG,"Data waiting on socket %d",cu->fd);
int MOD_RESULT = 0;
diff --git a/src/modules.cpp b/src/modules.cpp
index 006802cf5..e29299d5e 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -23,6 +23,11 @@
#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
#include <cstdio>
#include <time.h>
#include <string>
@@ -61,6 +66,10 @@
using namespace std;
+#ifdef USE_KQUEUE
+extern int kq;
+#endif
+
extern int MODCOUNT;
extern std::vector<Module*> modules;
extern std::vector<ircd_module*> factory;
@@ -674,8 +683,17 @@ bool Server::UserToPseudo(userrec* user,std::string message)
user->fd = FD_MAGIC_NUMBER;
user->ClearBuffer();
Write(old_fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,message.c_str());
- shutdown(old_fd,2);
- close(old_fd);
+#ifdef USE_KQUEUE
+ struct kevent ke;
+ EV_SET(&ke, old_fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ int i = kevent(kq, &ke, 1, 0, 0, NULL);
+ if (i == -1)
+ {
+ log(DEBUG,"kqueue: Failed to remove user from queue!");
+ }
+#endif
+ shutdown(old_fd,2);
+ close(old_fd);
}
bool Server::PseudoToUser(userrec* alive,userrec* zombie,std::string message)