source: nscp/include/thread.h @ f029bc2

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

2008-02-09 MickeM

+ New module CheckExternalScripts to handle 1, external script (similar to the old NRPE but in its own module)

  • Can Check batch/vbs/programs/*
  • Works with NSCA module (if you don't want to have NRPE at the same time)
  • Simpler syntax (discarded old and added new section for alias)
  • Started to add "sample alias" to ease initial setup and give some nice ideas (please provide me with feedback on them)
  • Property mode set to 100644
File size: 8.7 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#define THREAD_MAGIC_ID 123456
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                unsigned int magic_id;
77        } thread_param;
78
79public:
80        /**
81         * Default c-tor.
82         * Sets up default values
83         */
84        Thread(std::wstring threadid) : threadid_(threadid), hThread_(NULL), pObject_(NULL), uThreadID(-1), bThreadHasTerminated(false), bThreadHasBeenClosed(false) {
85                hMutex_ = CreateMutex(NULL, FALSE, NULL);
86                if (hMutex_ == NULL) {
87                        std::wcerr << _T("Failed to create thread mutec for thread: ") << threadid << _T(": ") << GetLastError() << std::endl;
88                }
89        }
90        /**
91         * Default d-tor.
92         * Does not really kill the thread only closes the handle to it.
93         *  @bug Should perhaps kill the thread, delete the object etc ?
94         */
95        virtual ~Thread() {
96                {
97                        if (bThreadHasBeenClosed && bThreadHasTerminated)
98                                ;
99                        else if (bThreadHasBeenClosed||bThreadHasTerminated)
100                                std::wcout << "Thread has not terminated correctly: " << threadid_ << "..." << std::endl;
101                        /*
102                        MutexLock mutex(hMutex_, 5000L);
103                        if (!mutex.hasMutex()) {
104                                throw ThreadException("Could not retrieve mutex when killing thread, we are fucked...");
105                        }
106                        hThread_ = NULL;
107                        if (hStopEvent_)
108                                CloseHandle(hStopEvent_);
109                        hStopEvent_ = NULL;
110                        delete pObject_;
111                        */
112//                      pObject_ = NULL;
113//                      CloseHandle(hThread_);
114                }
115                if (hMutex_)
116                        CloseHandle(hMutex_);
117                hMutex_ = NULL;
118        }
119
120private:
121        /**
122         * Static thread instance (this is the real thread procedure that wraps the internal objects)
123         * This function will wait for <b>nice</b> termination of the process so if that does not happen the thread canoot quit.
124         *
125         * @param lpParameter thread_param* with arguments for the thread construction
126         * @return exit status
127         */
128        static unsigned __stdcall threadProc(void* lpParameter) {
129                thread_param* param = static_cast<thread_param*>(lpParameter);
130                if (param->magic_id != THREAD_MAGIC_ID) {
131                        std::wcerr << _T("Thread magic ID check failed :(") << std::endl;
132                        _endthreadex( 0 );
133                        return 0;
134                }
135                T* instance = param->instance;
136                LPVOID lpParam = param->lpParam;
137                Thread *pCore = param->pCore;
138                delete param;
139                unsigned returnCode = 0;
140                try {
141                        returnCode = instance->threadProc(lpParam);
142                } catch (...) {
143                        std::wcerr << _T("Unhandled exception in thread a :(") << std::endl;
144                }
145                pCore->terminate();
146                _endthreadex( 0 );
147                return returnCode;
148        }
149
150public:
151        /**
152         * Create a thread and possibly send a parameter to it.
153         * If a thread has already been create this function will throw an exception
154         * <b>NOTICE</b> The object returned is managed inside this object so it is not very safe to use it.
155         *
156         * @param lpParam An argument to the thread
157         * @return An instance of the thread object.
158         * @bug the object return thing is *unsafe* and should be changed (if the thread is terminated that pointer is invalidated without any signal).
159         */
160        void createThread(LPVOID lpParam = NULL) {
161                if (hMutex_ == NULL)
162                        throw ThreadException(_T("No mutex in createThread (") + threadid_ + _T(") not started..."));
163                thread_param* param = NULL;
164                {
165                        MutexLock mutex(hMutex_, 5000L);
166                        if (!mutex.hasMutex()) {
167                                throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not started..."));
168                        }
169                        if (pObject_) {
170                                throw ThreadException(_T("Thread already started, thread (") + threadid_ + _T(") not started..."));
171                        }
172                        param = new thread_param;
173                        if (param == NULL)
174                                throw ThreadException(_T("Failed to allocate memory for new thread: ") + threadid_);
175                        param->instance = pObject_ = new T;
176                        if (param->instance == NULL)
177                                throw ThreadException(_T("Failed to allocate memory for new thread: ") + threadid_);
178                        param->lpParam = lpParam;
179                        param->pCore = this;
180                        param->magic_id = THREAD_MAGIC_ID;
181                }
182                uintptr_t thread_handle = ::_beginthreadex(NULL, 0, threadProc, reinterpret_cast<VOID*>(param), 0, &uThreadID);
183                if (thread_handle == 0 || thread_handle == 1 || thread_handle == -1) {
184                        throw ThreadException(_T("Failed to create the thread (") + threadid_ + _T(")."));
185                }
186                hThread_ = reinterpret_cast<HANDLE>(thread_handle);
187        }
188        /**
189         * Ask the thread to terminate (within 5 seconds) if not return false.
190         * @param delay The time to wait for the thread
191         * @return true if the thread has terminated
192         */
193        bool exitThread(const unsigned int delay = 20000L) {
194                if (hMutex_ == NULL)
195                        throw ThreadException(_T("No mutex in createThread (") + threadid_ + _T(") not started..."));
196                DWORD dwWaitResult = -1;
197                {
198                        MutexLock mutex(hMutex_, delay);
199                        if (!mutex.hasMutex()) {
200                                throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
201                        }
202                        if (!pObject_)
203                                return true;
204                        pObject_->exitThread();
205                }
206                dwWaitResult = WaitForSingleObject(hThread_, delay);
207                if (dwWaitResult == WAIT_OBJECT_0) {
208                        bThreadHasBeenClosed = true;
209                        CloseHandle(hThread_);
210                        delete pObject_;
211                        pObject_ = NULL;
212                        return true;
213                }
214                std::wcerr << _T("Failed to terminate thread: ") << threadid_ << _T("...") << std::endl;
215                return false;
216        }
217        bool hasActiveThread() const {
218                MutexLock mutex(hMutex_, 5000L);
219                if (!mutex.hasMutex()) {
220                        throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
221                }
222                if (bThreadHasTerminated||bThreadHasBeenClosed)
223                        return false;
224                return pObject_ != NULL;
225        }
226        const T* getThreadConst() const {
227                MutexLock mutex(hMutex_, 5000L);
228                if (!mutex.hasMutex()) {
229                        throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
230                }
231                if (bThreadHasTerminated||bThreadHasBeenClosed)
232                        return NULL;
233                return pObject_;
234        }
235        T* getThread() {
236                MutexLock mutex(hMutex_, 5000L);
237                if (!mutex.hasMutex()) {
238                        throw ThreadException(_T("Could not retrieve mutex, thread (") + threadid_ + _T(") not stopped..."));
239                }
240                if (bThreadHasTerminated||bThreadHasBeenClosed)
241                        return NULL;
242                return pObject_;
243        }
244private:
245        void terminate() {
246                bThreadHasTerminated = true;
247        }
248};
249
Note: See TracBrowser for help on using the repository browser.