source: nscp/include/thread.h @ 047516e

0.4.00.4.10.4.2stable
Last change on this file since 047516e was 047516e, checked in by Michael Medin <michael@…>, 5 years ago

2008-02-08 MickeM

+ Added some more default catch handlers (on the "core" side of plugin-calls).

2008-02-07 MickeM

+ Added default catch handlers to all wrapped plugin calls.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2004-2007 by Michael Medin <michael@medin.name>         *
3*                                                                         *
4*   This code is part of NSClient++ - http://trac.nakednuns.org/nscp      *
5*                                                                         *
6*   This program is free software; you can redistribute it and/or modify  *
7*   it under the terms of the GNU General Public License as published by  *
8*   the Free Software Foundation; either version 2 of the License, or     *
9*   (at your option) any later version.                                   *
10*                                                                         *
11*   This program is distributed in the hope that it will be useful,       *
12*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14*   GNU General Public License for more details.                          *
15*                                                                         *
16*   You should have received a copy of the GNU General Public License     *
17*   along with this program; if not, write to the                         *
18*   Free Software Foundation, Inc.,                                       *
19*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20***************************************************************************/
21#pragma once
22
23#include <process.h>
24#include <Mutex.h>
25
26class ThreadException {
27public:
28        std::wstring e_;
29        ThreadException(std::wstring e) : e_(e) {
30                std::wcerr << e << std::endl;
31        }
32};
33
34/**
35 * @ingroup NSClientCompat
36 * Thread helper class.
37 * This class wraps another class inside it and makes that class run in the background as a working thread.
38 * Notice that no threading issues are handled so you are on your own when it comes to that.
39 * This simply wraps some API function inside a pretty interface.
40 *
41 * @version 1.0
42 * first version
43 *
44 * @date 02-13-2005
45 *
46 * @author mickem
47 *
48 * @par license
49 * This code is absolutely free to use and modify. The code is provided "as is" with
50 * no expressed or implied warranty. The author accepts no liability if it causes
51 * any damage to your computer, causes your pet to fall ill, increases baldness
52 * or makes your car start emitting strange noises when you start it up.
53 * This code has no bugs, just undocumented features!
54 *
55 * @todo Make this class (or another) handle multiple instances of the thread ?
56 */
57template <class T>
58class Thread {
59private:
60        std::wstring threadid_;
61        HANDLE hThread_;                // Thread handle
62        T* pObject_;                    // Wrapped object
63        HANDLE hMutex_;                 // Mutex to protect internal data
64        unsigned uThreadID;             // THe thread ID
65
66
67        bool bThreadHasTerminated;
68        bool bThreadHasBeenClosed;
69
70
71
72        typedef struct thread_param {
73                T *instance;            // The thread instance object
74                LPVOID lpParam;         // The optional argument to the thread
75                Thread *pCore;
76        } thread_param;
77
78public:
79        /**
80         * Default c-tor.
81         * Sets up default values
82         */
83        Thread(std::wstring threadid) : threadid_(threadid), hThread_(NULL), pObject_(NULL), uThreadID(-1), bThreadHasTerminated(false), bThreadHasBeenClosed(false) {
84                hMutex_ = CreateMutex(NULL, FALSE, NULL);
85                assert(hMutex_ != NULL);
86        }
87        /**
88         * Default d-tor.
89         * Does not really kill the thread only closes the handle to it.
90         *  @bug Should perhaps kill the thread, delete the object etc ?
91         */
92        virtual ~Thread() {
93                {
94                        if (bThreadHasBeenClosed && bThreadHasTerminated)
95                                ;
96                        else if (bThreadHasBeenClosed||bThreadHasTerminated)
97                                std::wcout << "Thread has not terminated correctly: " << threadid_ << "..." << std::endl;
98                        /*
99                        MutexLock mutex(hMutex_, 5000L);
100                        if (!mutex.hasMutex()) {
101                                throw ThreadException("Could not retrieve mutex when killing thread, we are fucked...");
102                        }
103                        hThread_ = NULL;
104                        if (hStopEvent_)
105                                CloseHandle(hStopEvent_);
106                        hStopEvent_ = NULL;
107                        delete pObject_;
108                        */
109//                      pObject_ = NULL;
110//                      CloseHandle(hThread_);
111                }
112                if (hMutex_)
113                        CloseHandle(hMutex_);
114                hMutex_ = NULL;
115        }
116
117private:
118        /**
119         * Static thread instance (this is the real thread procedure that wraps the internal objects)
120         * This function will wait for <b>nice</b> termination of the process so if that does not happen the thread canoot quit.
121         *
122         * @param lpParameter thread_param* with arguments for the thread construction
123         * @return exit status
124         */
125        static unsigned __stdcall threadProc(void* lpParameter) {
126                thread_param* param = static_cast<thread_param*>(lpParameter);
127                T* instance = param->instance;
128                LPVOID lpParam = param->lpParam;
129                Thread *pCore = param->pCore;
130                delete param;
131
132                unsigned returnCode = instance->threadProc(lpParam);
133                pCore->terminate();
134                _endthreadex( 0 );
135                return returnCode;
136
137//              _endthread();
138        }
139
140public:
141        /**
142         * Create a thread and possibly send a parameter to it.
143         * If a thread has already been create this function will throw an exception
144         * <b>NOTICE</b> The object returned is managed inside this object so it is not very safe to use it.
145         *
146         * @param lpParam An argument to the thread
147         * @return An instance of the thread object.
148         * @bug the object return thing is *unsafe* and should be changed (if the thread is terminated that pointer is invalidated without any signal).
149         */
150        void createThread(LPVOID lpParam = NULL) {
151                thread_param* param = NULL;
152                {
153                        MutexLock mutex(hMutex_, 5000L);
154                        if (!mutex.hasMutex()) {
155                                throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not started..."));
156                        }
157                        if (pObject_) {
158                                throw ThreadException(_T("Thread already started, thread (") + threadid_ + _T(") not started..."));
159                        }
160//                      assert(hStopEvent_ == NULL);
161                        param = new thread_param;
162                        param->instance = pObject_ = new T;
163//                      param->hStopEvent = hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
164                        param->lpParam = lpParam;
165                        param->pCore = this;
166                }
167                //hThread_ = reinterpret_cast<HANDLE>(::_beginthreadex(threadProc, 0, reinterpret_cast<VOID*>(param)));
168                //hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );
169                uintptr_t thread_handle = ::_beginthreadex(NULL, 0, threadProc, reinterpret_cast<VOID*>(param), 0, &uThreadID);
170                if (thread_handle == 0 || thread_handle == 1 || thread_handle == -1) {
171                        throw ThreadException(_T("Failed to create the thread (") + threadid_ + _T(")."));
172                }
173                hThread_ = reinterpret_cast<HANDLE>(thread_handle);
174        }
175        /**
176         * Ask the thread to terminate (within 5 seconds) if not return false.
177         * @param delay The time to wait for the thread
178         * @return true if the thread has terminated
179         */
180        bool exitThread(const unsigned int delay = 20000L) {
181                DWORD dwWaitResult = -1;
182                {
183                        MutexLock mutex(hMutex_, delay);
184                        if (!mutex.hasMutex()) {
185                                throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
186                        }
187                        if (!pObject_)
188                                return true;
189                        pObject_->exitThread();
190                }
191                dwWaitResult = WaitForSingleObject(hThread_, delay);
192                if (dwWaitResult == WAIT_OBJECT_0) {
193                        bThreadHasBeenClosed = true;
194                        CloseHandle(hThread_);
195                        delete pObject_;
196                        pObject_ = NULL;
197                        return true;
198                }
199                std::wcerr << _T("Failed to terminate thread: ") << threadid_ << _T("...") << std::endl;
200                //assert(false);
201                return false;
202        }
203        bool hasActiveThread() const {
204                MutexLock mutex(hMutex_, 5000L);
205                if (!mutex.hasMutex()) {
206                        throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
207                }
208                if (bThreadHasTerminated||bThreadHasBeenClosed)
209                        return false;
210                return pObject_ != NULL;
211        }
212        const T* getThreadConst() const {
213                MutexLock mutex(hMutex_, 5000L);
214                if (!mutex.hasMutex()) {
215                        throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
216                }
217                if (bThreadHasTerminated||bThreadHasBeenClosed)
218                        return NULL;
219                return pObject_;
220        }
221        T* getThread() {
222                MutexLock mutex(hMutex_, 5000L);
223                if (!mutex.hasMutex()) {
224                        throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
225                }
226                if (bThreadHasTerminated||bThreadHasBeenClosed)
227                        return NULL;
228                return pObject_;
229        }
230private:
231        void terminate() {
232                bThreadHasTerminated = true;
233        }
234};
235
Note: See TracBrowser for help on using the repository browser.