1/*
2 * Legal Notice
3 *
4 * This document and associated source code (the "Work") is a part of a
5 * benchmark specification maintained by the TPC.
6 *
7 * The TPC reserves all right, title, and interest to the Work as provided
8 * under U.S. and international laws, including without limitation all patent
9 * and trademark rights therein.
10 *
11 * No Warranty
12 *
13 * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION
14 * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE
15 * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER
16 * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
17 * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES,
18 * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
19 * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF
20 * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE.
21 * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT,
22 * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT
23 * WITH REGARD TO THE WORK.
24 * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO
25 * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE
26 * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS
27 * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT,
28 * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY,
29 * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT
30 * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD
31 * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * Contributors
34 * - Chris Chan-nui, Matt Emmerton
35 */
36
37#ifndef THREADING_H_INCLUDED
38#define THREADING_H_INCLUDED
39
40#include <memory>
41#include <stdexcept>
42
43#ifndef WIN32
44#include <sstream>
45#include <cstring>
46#endif
47
48#include "EGenStandardTypes.h"
49
50namespace TPCE {
51
52// Base class to provide a run() method for objects which can be threaded.
53// This is required because under pthreads we have to provide an interface
54// through a C ABI call, which we can't do with templated classes.
55class ThreadBase {
56public:
57 virtual ~ThreadBase();
58 virtual void invoke() = 0;
59};
60
61// Call the run() method of passed argument. Always returns NULL.
62#ifdef WIN32
63DWORD WINAPI start_thread(LPVOID arg);
64#else
65extern "C" void *start_thread(void *arg);
66#endif
67
68// Template to wrap around a class that has a ThreadBase::run() method and
69// spawn it in a thread of its own.
70template <typename T> class Thread : public ThreadBase {
71private:
72 std::unique_ptr<T> obj_;
73 TThread tid_;
74#ifndef WIN32
75 TThreadAttr attr_;
76#endif
77 int stacksize_;
78
79public:
80 Thread(std::unique_ptr<T> throbj)
81 : obj_(throbj), tid_()
82#ifndef WIN32
83 ,
84 attr_()
85#endif
86 ,
87 stacksize_(0) {
88#ifndef WIN32
89 pthread_attr_init(&attr_);
90#endif
91 }
92 Thread(std::unique_ptr<T> throbj, int stacksize)
93 : obj_(throbj), tid_()
94#ifndef WIN32
95 ,
96 attr_()
97#endif
98 ,
99 stacksize_(stacksize) {
100#ifndef WIN32
101 pthread_attr_init(&attr_);
102#endif
103 }
104 T *obj() {
105 return obj_.get();
106 }
107 void invoke() {
108 obj_->run(this);
109 }
110 void start();
111 void stop();
112};
113
114//////////////////////////////////////////////////////////
115// Windows Implementation
116//////////////////////////////////////////////////////////
117
118#ifdef WIN32
119
120template <typename T> void Thread<T>::start() {
121 tid_ = CreateThread(NULL, stacksize_, start_thread, this, NULL, NULL);
122 if (tid_ == NULL) {
123 std::ostringstream strm;
124 strm << "CreateThread error: " << GetLastError();
125 throw std::runtime_error(strm.str());
126 }
127}
128
129template <typename T> void Thread<T>::stop() {
130 DWORD rc = WaitForSingleObject(tid_, INFINITE);
131 if (rc != 0) {
132 std::ostringstream strm;
133 strm << "WaitForSingleObject error: " << GetLastError();
134 throw std::runtime_error(strm.str());
135 }
136}
137
138//////////////////////////////////////////////////////////
139// Non-Windows (pthread) Implementation
140//////////////////////////////////////////////////////////
141
142#else
143
144template <typename T> void Thread<T>::start() {
145 int rc = 0;
146
147 if (stacksize_ > 0) {
148 rc = pthread_attr_setstacksize(&attr_, stacksize_);
149 if (rc != 0) {
150 std::ostringstream strm;
151 strm << "pthread_attr_setstacksize error: " << strerror(rc) << "(" << rc << ")";
152 throw std::runtime_error(strm.str());
153 }
154 }
155
156 rc = pthread_create(&tid_, &attr_, start_thread, this);
157 if (rc != 0) {
158 std::ostringstream strm;
159 strm << "pthread_create error: " << strerror(rc) << "(" << rc << ")";
160 throw std::runtime_error(strm.str());
161 }
162}
163
164template <typename T> void Thread<T>::stop() {
165 int rc = pthread_join(tid_, NULL);
166 if (rc != 0) {
167 std::ostringstream strm;
168 strm << "pthread_join error: " << strerror(rc) << "(" << rc << ")";
169 throw std::runtime_error(strm.str());
170 }
171}
172
173#endif
174
175} // namespace TPCE
176
177#endif // THREADING_H_INCLUDED
178