summaryrefslogtreecommitdiff
path: root/src/threadengines/threadengine_pthread.cpp
blob: 15f5567a4a90d2609d30177168417e4f5443c4fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*       +------------------------------------+
 *       | Inspire Internet Relay Chat Daemon |
 *       +------------------------------------+
 *
 *  InspIRCd: (C) 2002-2009 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 "threadengines/threadengine_pthread.h"
#include <pthread.h>
#include <signal.h>

pthread_mutex_t MyMutex = PTHREAD_MUTEX_INITIALIZER;

PThreadEngine::PThreadEngine(InspIRCd* Instance) : ThreadEngine(Instance)
{
}

void PThreadEngine::Create(Thread* thread_to_init)
{
	pthread_attr_t attribs;
	pthread_attr_init(&attribs);
	pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_JOINABLE);
	pthread_t* MyPThread = new pthread_t;

	/* Create a thread in a mutex. This prevents whacking the member value NewThread,
	 * and also prevents recursive creation of threads by mistake (instead, the thread
	 * will just deadlock itself)
	 */
	Mutex(true);

	if (pthread_create(MyPThread, &attribs, PThreadEngine::Entry, (void*)this) != 0)
	{
		delete MyPThread;
		Mutex(false);
		throw CoreException("Unable to create new PThreadEngine: " + std::string(strerror(errno)));
	}

	pthread_attr_destroy(&attribs);

	NewThread = thread_to_init;
	NewThread->Creator = this;
	NewThread->Extend("pthread", MyPThread);

	/* Always unset a mutex if you set it */
	Mutex(false);

	/* Wait for the PThreadEngine::Run method to take a copy of the
	 * pointer and clear this member value
	 */
	while (NewThread)
		usleep(1000);
}

PThreadEngine::~PThreadEngine()
{
}

void PThreadEngine::Run()
{
	/* Take a copy of the member value, then clear it. Do this
	 * in a mutex so that we can be sure nothing else is looking
	 * at it.
	 */
	Mutex(true);
	Thread* nt = NewThread;
	NewThread = NULL;
	Mutex(false);
	/* Now we have our own safe copy, call the object on it */
	nt->Run();
}

bool PThreadEngine::Mutex(bool enable)
{
	if (enable)
		pthread_mutex_lock(&MyMutex);
	else
		pthread_mutex_unlock(&MyMutex);

	return false;
}

void* PThreadEngine::Entry(void* parameter)
{
	/* Recommended by nenolod, signal safety on a per-thread basis */
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set, SIGPIPE);
	if(pthread_sigmask(SIG_BLOCK, &set, NULL))
		signal(SIGPIPE, SIG_IGN);

	ThreadEngine * pt = (ThreadEngine*)parameter;
	pt->Run();
	return NULL;
}

void PThreadEngine::FreeThread(Thread* thread)
{
	pthread_t* pthread = NULL;
	if (thread->GetExt("pthread", pthread))
	{
		thread->SetExitFlag();
		int rc;
		void* status;
		rc = pthread_join(*pthread, &status);
		delete pthread;
	}
}

MutexFactory::MutexFactory(InspIRCd* Instance) : ServerInstance(Instance)
{
}

Mutex* MutexFactory::CreateMutex()
{
	return new PosixMutex(this->ServerInstance);
}

PosixMutex::PosixMutex(InspIRCd* Instance) : Mutex(Instance)
{
	pthread_mutex_init(&putex, NULL);
}

PosixMutex::~PosixMutex()
{
	pthread_mutex_destroy(&putex);
}

void PosixMutex::Enable(bool enable)
{
	if (enable)
		pthread_mutex_lock(&putex);
	else
		pthread_mutex_unlock(&putex);
}