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 | |
50 | namespace 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. |
55 | class ThreadBase { |
56 | public: |
57 | virtual ~ThreadBase(); |
58 | virtual void invoke() = 0; |
59 | }; |
60 | |
61 | // Call the run() method of passed argument. Always returns NULL. |
62 | #ifdef WIN32 |
63 | DWORD WINAPI start_thread(LPVOID arg); |
64 | #else |
65 | extern "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. |
70 | template <typename T> class Thread : public ThreadBase { |
71 | private: |
72 | std::unique_ptr<T> obj_; |
73 | TThread tid_; |
74 | #ifndef WIN32 |
75 | TThreadAttr attr_; |
76 | #endif |
77 | int stacksize_; |
78 | |
79 | public: |
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 | |
120 | template <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 | |
129 | template <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 | |
144 | template <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 | |
164 | template <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 | |