anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

socketengine_kqueue.cpp (2613B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "anope.h"
     14 #include "sockets.h"
     15 #include "socketengine.h"
     16 #include "logger.h"
     17 #include "config.h"
     18 
     19 #include <sys/types.h>
     20 #include <sys/event.h>
     21 #include <sys/time.h>
     22 #include <errno.h>
     23 
     24 static int kq_fd;
     25 static std::vector<struct kevent> change_events, event_events;
     26 static unsigned change_count;
     27 
     28 static inline struct kevent *GetChangeEvent()
     29 {
     30 	if (change_count == change_events.size())
     31 		change_events.resize(change_count * 2);
     32 
     33 	return &change_events[change_count++];
     34 }
     35 
     36 void SocketEngine::Init()
     37 {
     38 	kq_fd = kqueue();
     39 
     40 	if (kq_fd < 0)
     41 		throw SocketException("Unable to create kqueue engine: " + Anope::LastError());
     42 
     43 	change_events.resize(DefaultSize);
     44 	event_events.resize(DefaultSize);
     45 }
     46 
     47 void SocketEngine::Shutdown()
     48 {
     49 	while (!Sockets.empty())
     50 		delete Sockets.begin()->second;
     51 }
     52 
     53 void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
     54 {
     55 	if (set == s->flags[flag])
     56 		return;
     57 
     58 	s->flags[flag] = set;
     59 
     60 	int mod;
     61 	if (flag == SF_READABLE)
     62 		mod = EVFILT_READ;
     63 	else if (flag == SF_WRITABLE)
     64 		mod = EVFILT_WRITE;
     65 	else
     66 		return;
     67 
     68 	struct kevent *event = GetChangeEvent();
     69 	EV_SET(event, s->GetFD(), mod, set ? EV_ADD : EV_DELETE, 0, 0, NULL);
     70 }
     71 
     72 void SocketEngine::Process()
     73 {
     74 	if (Sockets.size() > event_events.size())
     75 		event_events.resize(event_events.size() * 2);
     76 
     77 	static timespec kq_timespec = { Config->ReadTimeout, 0 };
     78 	int total = kevent(kq_fd, &change_events.front(), change_count, &event_events.front(), event_events.size(), &kq_timespec);
     79 	change_count = 0;
     80 	Anope::CurTime = time(NULL);
     81 
     82 	/* EINTR can be given if the read timeout expires */
     83 	if (total == -1)
     84 	{
     85 		if (errno != EINTR)
     86 			Log() << "SockEngine::Process(): error: " << Anope::LastError();
     87 		return;
     88 	}
     89 
     90 	for (int i = 0; i < total; ++i)
     91 	{
     92 		struct kevent &event = event_events[i];
     93 		if (event.flags & EV_ERROR)
     94 			continue;
     95 
     96 		std::map<int, Socket *>::iterator it = Sockets.find(event.ident);
     97 		if (it == Sockets.end())
     98 			continue;
     99 		Socket *s = it->second;
    100 
    101 		if (event.flags & EV_EOF)
    102 		{
    103 			s->ProcessError();
    104 			delete s;
    105 			continue;
    106 		}
    107 
    108 		if (!s->Process())
    109 		{
    110 			if (s->flags[SF_DEAD])
    111 				delete s;
    112 			continue;
    113 		}
    114 
    115 		if (event.filter == EVFILT_READ && !s->ProcessRead())
    116 			s->flags[SF_DEAD] = true;
    117 		else if (event.filter == EVFILT_WRITE && !s->ProcessWrite())
    118 			s->flags[SF_DEAD] = true;
    119 
    120 		if (s->flags[SF_DEAD])
    121 			delete s;
    122 	}
    123 }