]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/threadengines/threadengine_pthread.cpp
Change ThreadSignalSocket to EventHandler to avoid calling recv() on an eventfd,...
[user/henk/code/inspircd.git] / src / threadengines / threadengine_pthread.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "threadengines/threadengine_pthread.h"
16 #include <pthread.h>
17 #include <signal.h>
18 #include <fcntl.h>
19
20 ThreadEngine::ThreadEngine()
21 {
22 }
23
24 static void* entry_point(void* parameter)
25 {
26         /* Recommended by nenolod, signal safety on a per-thread basis */
27         sigset_t set;
28         sigemptyset(&set);
29         sigaddset(&set, SIGPIPE);
30         pthread_sigmask(SIG_BLOCK, &set, NULL);
31
32         Thread* pt = static_cast<Thread*>(parameter);
33         pt->Run();
34         return parameter;
35 }
36
37
38 void ThreadEngine::Start(Thread* thread)
39 {
40         ThreadData* data = new ThreadData;
41         thread->state = data;
42
43         if (pthread_create(&data->pthread_id, NULL, entry_point, thread) != 0)
44         {
45                 thread->state = NULL;
46                 delete data;
47                 throw CoreException("Unable to create new thread: " + std::string(strerror(errno)));
48         }
49 }
50
51 ThreadEngine::~ThreadEngine()
52 {
53 }
54
55 void ThreadData::FreeThread(Thread* thread)
56 {
57         thread->SetExitFlag();
58         pthread_join(pthread_id, NULL);
59 }
60
61 #ifdef HAS_EVENTFD
62 #include <sys/eventfd.h>
63
64 class ThreadSignalSocket : public EventHandler
65 {
66         SocketThread* parent;
67  public:
68         ThreadSignalSocket(SocketThread* p, int newfd) : parent(p)
69         {
70                 SetFd(newfd);
71                 ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
72         }
73
74         ~ThreadSignalSocket()
75         {
76         }
77
78         void Notify()
79         {
80                 eventfd_write(fd, 1);
81         }
82
83         void HandleEvent(EventType et, int errornum)
84         {
85                 if (et == EVENT_READ)
86                 {
87                         eventfd_t dummy;
88                         eventfd_read(fd, &dummy);
89                         parent->OnNotify();
90                 }
91                 else
92                 {
93                         ServerInstance->GlobalCulls.AddItem(this);
94                 }
95         }
96 };
97
98 SocketThread::SocketThread()
99 {
100         int fd = eventfd(0, EFD_NONBLOCK);
101         if (fd < 0)
102                 throw new CoreException("Could not create pipe " + std::string(strerror(errno)));
103         signal.sock = new ThreadSignalSocket(this, fd);
104 }
105 #else
106
107 class ThreadSignalSocket : public EventHandler
108 {
109         SocketThread* parent;
110         int send_fd;
111  public:
112         ThreadSignalSocket(SocketThread* p, int recvfd, int sendfd) :
113                 parent(p), send_fd(sendfd)
114         {
115                 SetFd(recvfd);
116                 ServerInstance->SE->NonBlocking(fd);
117                 ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
118         }
119
120         ~ThreadSignalSocket()
121         {
122                 close(send_fd);
123         }
124
125         void Notify()
126         {
127                 static const char dummy = '*';
128                 write(send_fd, &dummy, 1);
129         }
130
131         void HandleEvent(EventType et, int errornum)
132         {
133                 if (et == EVENT_READ)
134                 {
135                         char dummy[128];
136                         read(fd, dummy, 128);
137                         parent->OnNotify();
138                 }
139                 else
140                 {
141                         ServerInstance->GlobalCulls.AddItem(this);
142                 }
143         }
144 };
145
146 SocketThread::SocketThread()
147 {
148         int fds[2];
149         if (pipe(fds))
150                 throw new CoreException("Could not create pipe " + std::string(strerror(errno)));
151         signal.sock = new ThreadSignalSocket(this, fds[0], fds[1]);
152 }
153 #endif
154
155 void SocketThread::NotifyParent()
156 {
157         signal.sock->Notify();
158 }
159
160 SocketThread::~SocketThread()
161 {
162 }