From 772dc6c47406b0ca6be5e49914dd739c8d580bd5 Mon Sep 17 00:00:00 2001 From: brain Date: Sun, 8 Apr 2007 18:08:20 +0000 Subject: Add support for solaris 10 IO Completion Ports, contributed by nenolod git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@6763 e03df62e-2008-0410-955e-edbf42e46eb7 --- configure | 48 ++++++++++++++++- include/socketengine_ports.h | 68 ++++++++++++++++++++++++ src/socketengine_ports.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 include/socketengine_ports.h create mode 100644 src/socketengine_ports.cpp diff --git a/configure b/configure index f051ccdf7..db0dd70e0 100755 --- a/configure +++ b/configure @@ -33,8 +33,10 @@ GetOptions ( 'with-nick-length=i' => \$opt_nick_length, 'with-channel-length=i' => \$opt_chan_length, 'with-max-clients=i' => \$opt_maxclients, + 'enable-ports' => \$opt_ports, 'enable-epoll' => \$opt_epoll, 'enable-kqueue' => \$opt_kqueue, + 'disable-ports' => \$opt_noports, 'disable-epoll' => \$opt_noepoll, 'disable-kqueue' => \$opt_nokqueue, 'enable-ipv6' => \$opt_ipv6, @@ -83,6 +85,7 @@ my $non_interactive = ( (defined $opt_noipv6links) || (defined $opt_kqueue) || (defined $opt_epoll) || + (defined $opt_ports) || (defined $opt_maxchans) || (defined $opt_opermaxchans) || (defined $opt_chan_length) || @@ -90,6 +93,7 @@ my $non_interactive = ( (defined $opt_use_openssl) || (defined $opt_nokqueue) || (defined $opt_noepoll) || + (defined $opt_noports) || (defined $opt_use_gnutls) ); my $interactive = !$non_interactive; @@ -190,6 +194,15 @@ if (defined $opt_noepoll) { $config{USE_EPOLL} = "n"; } +$config{USE_PORTS} = "y"; # epoll enabled +if (defined $opt_ports) +{ + $config{USE_PORTS} = "y"; +} +if (defined $opt_noports) +{ + $config{USE_PORTS} = "n"; +} $config{IPV6} = "n"; # IPv6 support (experimental) if (defined $opt_ipv6) { @@ -307,6 +320,7 @@ sub update getosflags(); } $has_epoll = $config{HAS_EPOLL}; + $has_ports = $config{HAS_PORTS}; $has_kqueue = $config{HAS_KQUEUE}; writefiles(1); makecache(); @@ -337,6 +351,7 @@ sub modupdate print "Updating Files..\n"; getosflags(); $has_epoll = $config{HAS_EPOLL}; + $has_ports = $config{HAS_PORTS}; $has_kqueue = $config{HAS_KQUEUE}; writefiles(0); makecache(); @@ -456,6 +471,22 @@ if ($has_epoll) { print "yes\n" if $has_epoll == 1; print "no\n" if $has_epoll == 0; +printf "Checking if Solaris I/O completion ports are available... "; +$has_ports = 0; +my $system = `uname -s`; +chomp ($system); +$has_ports = 1 if ($system eq "SunOS"); + +if ($has_ports) { + my $kernel = `uname -r`; + chomp($kernel); + if (($kernel !~ /^5\.10/)) { + $has_ports = 0; + } +} +print "yes\n" if $has_ports == 1; +print "no\n" if $has_ports == 0; + if (($config{OSNAME} =~ /CYGWIN/) || ($config{OSNAME} eq "CYG-STATIC")) { $config{HAS_STRLCPY} = "true"; } @@ -566,7 +597,11 @@ should NOT be used. You should probably specify a newer compiler.\n\n"; yesno(USE_EPOLL,"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?"); print "\n"; } - $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y")); + if ($has_ports) { + yesno(USE_PORTS,"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?"); + print "\n"; + } + $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y")); if (!$chose_hiperf) { print "No high-performance socket engines are available, or you chose\n"; print "not to enable one. Defaulting to select() engine.\n\n"; @@ -992,6 +1027,11 @@ EOF $se = "socketengine_epoll"; $use_hiperf = 1; } + if (($has_ports) && ($config{USE_PORTS} eq "y")) { + print FILEHANDLE "#define USE_PORTS\n"; + $se = "socketengine_ports"; + $use_hiperf = 1; + } # user didn't choose either epoll or select for their OS. # default them to USE_SELECT (ewwy puke puke) if (!$use_hiperf) { @@ -1370,6 +1410,9 @@ if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) { elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) { $se = "socketengine_epoll"; } +elsif (($has_ports) && ($config{USE_PORTS} eq "y")) { + $se = "socketengine_ports"; +} ### # This next section is for cygwin dynamic module builds. @@ -1504,6 +1547,9 @@ sub write_dynamic_makefile { elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) { $se = "socketengine_epoll"; } + elsif (($has_ports) && ($config{USE_PORTS} eq "y")) { + $se = "socketengine_ports"; + } open(FH,">src/Makefile") or die("Could not write src/Makefile"); print FH < +#include +#include +#include "inspircd_config.h" +#include "globals.h" +#include "inspircd.h" +#include "socketengine.h" +#include +#define EP_DELAY 5 + +class InspIRCd; + +/** A specialisation of the SocketEngine class, designed to use linux 2.6 epoll(). + */ +class PortsEngine : public SocketEngine +{ +private: + /** These are used by epoll() to hold socket events + */ + port_event_t events[MAX_DESCRIPTORS]; +public: + /** Create a new EPollEngine + * @param Instance The creator of this object + */ + PortsEngine(InspIRCd* Instance); + /** Delete an EPollEngine + */ + virtual ~PortsEngine(); + virtual bool AddFd(EventHandler* eh); + virtual int GetMaxFds(); + virtual int GetRemainingFds(); + virtual bool DelFd(EventHandler* eh, bool force = false); + virtual int DispatchEvents(); + virtual std::string GetName(); + virtual void WantWrite(EventHandler* eh); +}; + +/** Creates a SocketEngine + */ +class SocketEngineFactory +{ +public: + /** Create a new instance of SocketEngine based on PortsEngine + */ + SocketEngine* Create(InspIRCd* Instance) { return new PortsEngine(Instance); } +}; + +#endif diff --git a/src/socketengine_ports.cpp b/src/socketengine_ports.cpp new file mode 100644 index 000000000..f036a8e10 --- /dev/null +++ b/src/socketengine_ports.cpp @@ -0,0 +1,122 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "exitcodes.h" +#include +#include "socketengine_ports.h" + +PortsEngine::PortsEngine(InspIRCd* Instance) : SocketEngine(Instance) +{ + EngineHandle = port_create(); + + if (EngineHandle == -1) + { + ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno)); + ServerInstance->Log(SPARSE,"ERROR: This is a fatal error, exiting now."); + printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno)); + printf("ERROR: This is a fatal error, exiting now.\n"); + InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE); + } + CurrentSetSize = 0; +} + +PortsEngine::~PortsEngine() +{ + close(EngineHandle); +} + +bool PortsEngine::AddFd(EventHandler* eh) +{ + int fd = eh->GetFd(); + if ((fd < 0) || (fd > MAX_DESCRIPTORS)) + return false; + + if (GetRemainingFds() <= 1) + return false; + + if (ref[fd]) + return false; + + ref[fd] = eh; + port_associate(EngineHandle, PORT_SOURCE_FD, fd, eh->Readable() ? POLLRDNORM : POLLWRNORM, eh); + + ServerInstance->Log(DEBUG,"New file descriptor: %d", fd); + CurrentSetSize++; + return true; +} + +void PortsEngine::WantWrite(EventHandler* eh) +{ + port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), POLLWRNORM, eh); +} + +bool PortsEngine::DelFd(EventHandler* eh, bool force) +{ + int fd = eh->GetFd(); + if ((fd < 0) || (fd > MAX_DESCRIPTORS)) + return false; + + port_dissociate(EngineHandle, PORT_SOURCE_FD, fd); + + CurrentSetSize--; + ref[fd] = NULL; + + ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd); + return true; +} + +int PortsEngine::GetMaxFds() +{ + return MAX_DESCRIPTORS; +} + +int PortsEngine::GetRemainingFds() +{ + return MAX_DESCRIPTORS - CurrentSetSize; +} + +int PortsEngine::DispatchEvents() +{ + struct timespec poll_time; + + poll_time.tv_sec = 1; + poll_time.tv_nsec = 0; + + unsigned int nget = 1; // used to denote a retrieve request. + int i = port_getn(EngineHandle, this->events, MAX_DESCRIPTORS, &nget, &poll_time); + + // first handle an error condition + if (i == -1) + return i; + + for (i = 0; i < nget; i++) + { + switch (this->events[i].portev_source) + { + case PORT_SOURCE_FD: + int fd = this->events[i].portev_object; + ref[fd]->HandleEvent((this->events[i].portev_events & POLLRDNORM) ? EVENT_READ : EVENT_WRITE); + default: + break; + } + } + + return i; +} + +std::string PortsEngine::GetName() +{ + return "ports"; +} + -- cgit v1.2.3