]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/threadengines/threadengine_pthread.cpp
ebd11d487cbf83f042fdb4e92a773eaaf76fc8f8
[user/henk/code/inspircd.git] / src / threadengines / threadengine_pthread.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #include "inspircd.h"
22 #include "threadengines/threadengine_pthread.h"
23 #include <pthread.h>
24 #include <signal.h>
25 #include <fcntl.h>
26
27 ThreadEngine::ThreadEngine()
28 {
29 }
30
31 static void* entry_point(void* parameter)
32 {
33         /* Recommended by nenolod, signal safety on a per-thread basis */
34         sigset_t set;
35         sigemptyset(&set);
36         sigaddset(&set, SIGPIPE);
37         pthread_sigmask(SIG_BLOCK, &set, NULL);
38
39         Thread* pt = static_cast<Thread*>(parameter);
40         pt->Run();
41         return parameter;
42 }
43
44
45 void ThreadEngine::Start(Thread* thread)
46 {
47         ThreadData* data = new ThreadData;
48         thread->state = data;
49
50         if (pthread_create(&data->pthread_id, NULL, entry_point, thread) != 0)
51         {
52                 thread->state = NULL;
53                 delete data;
54                 throw CoreException("Unable to create new thread: " + std::string(strerror(errno)));
55         }
56 }
57
58 ThreadEngine::~ThreadEngine()
59 {
60 }
61
62 void ThreadData::FreeThread(Thread* thread)
63 {
64         thread->SetExitFlag();
65         pthread_join(pthread_id, NULL);
66 }
67
68 #ifdef HAS_EVENTFD
69 #include <sys/eventfd.h>
70
71 class ThreadSignalSocket : public EventHandler
72 {
73         SocketThread* parent;
74  public:
75         ThreadSignalSocket(SocketThread* p, int newfd) : parent(p)
76         {
77                 SetFd(newfd);
78                 ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
79         }
80
81         ~ThreadSignalSocket()
82         {
83                 ServerInstance->SE->DelFd(this);
84                 SocketEngine::Close(GetFd());
85         }
86
87         void Notify()
88         {
89                 eventfd_write(fd, 1);
90         }
91
92         void HandleEvent(EventType et, int errornum)
93         {
94                 if (et == EVENT_READ)
95                 {
96                         eventfd_t dummy;
97                         eventfd_read(fd, &dummy);
98                         parent->OnNotify();
99                 }
100                 else
101                 {
102                         ServerInstance->GlobalCulls.AddItem(this);
103                 }
104         }
105 };
106
107 SocketThread::SocketThread()
108 {
109         signal.sock = NULL;
110         int fd = eventfd(0, EFD_NONBLOCK);
111         if (fd < 0)
112                 throw new CoreException("Could not create pipe " + std::string(strerror(errno)));
113         signal.sock = new ThreadSignalSocket(this, fd);
114 }
115 #else
116
117 class ThreadSignalSocket : public EventHandler
118 {
119         SocketThread* parent;
120         int send_fd;
121  public:
122         ThreadSignalSocket(SocketThread* p, int recvfd, int sendfd) :
123                 parent(p), send_fd(sendfd)
124         {
125                 SetFd(recvfd);
126                 SocketEngine::NonBlocking(fd);
127                 ServerInstance->SE->AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
128         }
129
130         ~ThreadSignalSocket()
131         {
132                 close(send_fd);
133                 ServerInstance->SE->DelFd(this);
134                 SocketEngine::Close(GetFd());
135         }
136
137         void Notify()
138         {
139                 static const char dummy = '*';
140                 write(send_fd, &dummy, 1);
141         }
142
143         void HandleEvent(EventType et, int errornum)
144         {
145                 if (et == EVENT_READ)
146                 {
147                         char dummy[128];
148                         read(fd, dummy, 128);
149                         parent->OnNotify();
150                 }
151                 else
152                 {
153                         ServerInstance->GlobalCulls.AddItem(this);
154                 }
155         }
156 };
157
158 SocketThread::SocketThread()
159 {
160         signal.sock = NULL;
161         int fds[2];
162         if (pipe(fds))
163                 throw new CoreException("Could not create pipe " + std::string(strerror(errno)));
164         signal.sock = new ThreadSignalSocket(this, fds[0], fds[1]);
165 }
166 #endif
167
168 void SocketThread::NotifyParent()
169 {
170         signal.sock->Notify();
171 }
172
173 SocketThread::~SocketThread()
174 {
175         if (signal.sock)
176         {
177                 signal.sock->cull();
178                 delete signal.sock;
179         }
180 }