]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/threadengines/threadengine_pthread.cpp
36ba3ab42726ebea2c3756dc89d5fe6f8f6fcf0e
[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 <fcntl.h>
25
26 static void* entry_point(void* parameter)
27 {
28         /* Recommended by nenolod, signal safety on a per-thread basis */
29         sigset_t set;
30         sigemptyset(&set);
31         sigaddset(&set, SIGPIPE);
32         pthread_sigmask(SIG_BLOCK, &set, NULL);
33
34         Thread* pt = static_cast<Thread*>(parameter);
35         pt->Run();
36         return parameter;
37 }
38
39
40 void ThreadEngine::Start(Thread* thread)
41 {
42         ThreadData* data = new ThreadData;
43         thread->state = data;
44
45         if (pthread_create(&data->pthread_id, NULL, entry_point, thread) != 0)
46         {
47                 thread->state = NULL;
48                 delete data;
49                 throw CoreException("Unable to create new thread: " + std::string(strerror(errno)));
50         }
51 }
52
53 void ThreadData::FreeThread(Thread* thread)
54 {
55         thread->SetExitFlag();
56         pthread_join(pthread_id, NULL);
57 }
58
59 #ifdef HAS_EVENTFD
60 #include <sys/eventfd.h>
61
62 class ThreadSignalSocket : public EventHandler
63 {
64         SocketThread* parent;
65  public:
66         ThreadSignalSocket(SocketThread* p, int newfd) : parent(p)
67         {
68                 SetFd(newfd);
69                 SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
70         }
71
72         ~ThreadSignalSocket()
73         {
74                 SocketEngine::Close(this);
75         }
76
77         void Notify()
78         {
79                 eventfd_write(fd, 1);
80         }
81
82         void HandleEvent(EventType et, int errornum)
83         {
84                 if (et == EVENT_READ)
85                 {
86                         eventfd_t dummy;
87                         eventfd_read(fd, &dummy);
88                         parent->OnNotify();
89                 }
90                 else
91                 {
92                         ServerInstance->GlobalCulls.AddItem(this);
93                 }
94         }
95 };
96
97 SocketThread::SocketThread()
98 {
99         signal.sock = NULL;
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                 SocketEngine::NonBlocking(fd);
117                 SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_NO_WRITE);
118         }
119
120         ~ThreadSignalSocket()
121         {
122                 close(send_fd);
123                 SocketEngine::Close(this);
124         }
125
126         void Notify()
127         {
128                 static const char dummy = '*';
129                 write(send_fd, &dummy, 1);
130         }
131
132         void HandleEvent(EventType et, int errornum)
133         {
134                 if (et == EVENT_READ)
135                 {
136                         char dummy[128];
137                         read(fd, dummy, 128);
138                         parent->OnNotify();
139                 }
140                 else
141                 {
142                         ServerInstance->GlobalCulls.AddItem(this);
143                 }
144         }
145 };
146
147 SocketThread::SocketThread()
148 {
149         signal.sock = NULL;
150         int fds[2];
151         if (pipe(fds))
152                 throw new CoreException("Could not create pipe " + std::string(strerror(errno)));
153         signal.sock = new ThreadSignalSocket(this, fds[0], fds[1]);
154 }
155 #endif
156
157 void SocketThread::NotifyParent()
158 {
159         signal.sock->Notify();
160 }
161
162 SocketThread::~SocketThread()
163 {
164         if (signal.sock)
165         {
166                 signal.sock->cull();
167                 delete signal.sock;
168         }
169 }