source: sources/src/pcExecutionProcess.cc @ 1471:b85ecf59f9ab

Revision 1471:b85ecf59f9ab, 9.6 KB checked in by niam, 21 months ago (diff)

[lib] finished non-c++ exception integration

Line 
1/***************************************************************************
2 *            pcExecutionProcess.cc
3 *
4 *  Wed Oct 08 2009
5 *  Copyright  2009  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#ifdef DL_EXT
33#include <dlfcn.h>
34#endif
35
36#include <sys/types.h>
37#include <signal.h>
38#include <unistd.h>
39#include <sys/wait.h>
40#include <errno.h>
41#include <string.h>
42
43namespace dodo {
44    namespace pc {
45        namespace execution {
46            /**
47             * @struct __process__
48             * @brief defines process information
49             */
50            struct __process__ {
51                /**
52                 * constuctor
53                 */
54                __process__() : executed(false),
55                                joined(false),
56                                status(0)
57#ifdef DL_EXT
58                              ,
59                                handle(NULL)
60#endif
61                {
62#ifdef DL_EXT
63                    memset(cookie, 0x0, 32);
64#endif
65                }
66
67                pid_t           pid;                ///< process pid
68                void            *data;              ///< process data
69                bool            executed;           ///< true if the process was executed
70                bool            joined;             ///< true if the process was joined
71                int             status;             ///< process exit status
72                void            *func;              ///< function to execute
73                short           action;             ///< action on object destruction[@see onDestructionEnum]
74#ifdef DL_EXT
75                void            *handle;            ///< handle to library
76                char            cookie[32];         ///< cookie that would be passed to deinitModule
77#endif
78            };
79        };
80    };
81};
82
83#include <libdodo/pcExecutionProcess.h>
84#include <libdodo/types.h>
85#include <libdodo/pcExecutionJob.h>
86#include <libdodo/pcExecutionProcessEx.h>
87
88using namespace dodo::pc::execution;
89
90process::process(const process &p) : job(p),
91                                     handle(new __process__)
92{
93    *handle = *p.handle;
94}
95
96//-------------------------------------------------------------------
97
98process::process(routine func,
99                 void    *data,
100                 short   action) : job(TYPE_PROCESS),
101                                   handle(new __process__)
102{
103    handle->data = data;
104    handle->func = (void *)func;
105    handle->action = action;
106
107#ifdef DL_EXT
108    handle->handle = NULL;
109#endif
110}
111
112//-------------------------------------------------------------------
113
114#ifdef DL_EXT
115process::process(const dodo::string &module,
116                 void             *data,
117                 void             *toInit) : job(TYPE_PROCESS),
118                                             handle(new __process__)
119{
120    handle->data = data;
121
122#ifdef DL_FAST
123    handle->handle = dlopen(module.data(), RTLD_LAZY | RTLD_NODELETE);
124#else
125    handle->handle = dlopen(module.data(), RTLD_LAZY);
126#endif
127    if (handle->handle == NULL) {
128        delete handle;
129
130        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_CONSTRUCTOR, exception::ERRNO_DYNLOAD, 0, dlerror(), __LINE__, __FILE__);
131    }
132
133    initModule init = (initModule)dlsym(handle->handle, "initPcExecutionProcessModule");
134    if (init == NULL) {
135        dlclose(handle->handle);
136        delete handle;
137
138        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_CONSTRUCTOR, exception::ERRNO_DYNLOAD, 0, dlerror(), __LINE__, __FILE__);
139    }
140
141    __module__ m = init(toInit);
142
143    void *f = dlsym(handle->handle, m.hook);
144    if (f == NULL) {
145        dlclose(handle->handle);
146        delete handle;
147
148        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_CONSTRUCTOR, exception::ERRNO_DYNLOAD, 0, dlerror(), __LINE__, __FILE__);
149    }
150
151    handle->action = m.action;
152    handle->func = f;
153    memcpy(handle->cookie, m.cookie, 32);
154}
155#endif
156
157//-------------------------------------------------------------------
158
159process::~process()
160{
161    if (!cloned) {
162#ifdef DL_EXT
163        deinitModule deinit;
164#endif
165
166        if (isRunning()) {
167            switch (handle->action) {
168                case ON_DESTRUCTION_KEEP_ALIVE:
169
170                    waitpid(handle->pid, NULL, WNOHANG);
171
172                    break;
173
174                case ON_DESTRUCTION_STOP:
175
176                    kill(handle->pid, 2);
177
178                    break;
179
180                case ON_DESTRUCTION_WAIT:
181                default:
182
183                    waitpid(handle->pid, NULL, 0);
184            }
185        }
186
187#ifdef DL_EXT
188        if (handle->handle != NULL) {
189            deinit = (deinitModule)dlsym(handle->handle, "deinitPcExecutionProcessModule");
190            if (deinit != NULL)
191                deinit(handle->cookie);
192
193#ifndef DL_FAST
194            dlclose(handle->handle);
195#endif
196        }
197#endif
198    }
199
200    delete handle;
201}
202
203//-------------------------------------------------------------------
204
205bool
206process::isRunning() const
207{
208    if (!handle->executed)
209        return false;
210
211    int res = kill(handle->pid, 0);
212    if (res != 0) {
213        if (errno == ESRCH)
214            return false;
215
216        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_ISRUNNING, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
217    }
218
219    int status;
220
221    res = waitpid(handle->pid, &status, WNOHANG);
222
223    if (res == 0) {
224        return true;
225    } else if (res == handle->pid) {
226        if (WIFEXITED(status))
227            handle->status = WEXITSTATUS(status);
228
229        handle->executed = false;
230        handle->joined = true;
231
232        return false;
233    }
234
235    dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_ISRUNNING, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
236}
237
238//-------------------------------------------------------------------
239
240void
241process::run()
242{
243    if (isRunning())
244        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_RUN, exception::ERRNO_LIBDODO, PROCESSEX_ISALREADYRUNNING, PCEXECUTIONPROCESSEX_ISALREADYRUNNING_STR, __LINE__, __FILE__);
245
246    pid_t pid = fork();
247
248    if (pid == 0) {
249        _exit(((routine)handle->func)(handle->data));
250    } else {
251        if (pid == -1)
252            dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_RUN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
253        else
254            handle->pid = pid;
255    }
256
257    handle->executed = true;
258    handle->joined = false;
259}
260
261//-------------------------------------------------------------------
262
263void
264process::stop()
265{
266    if (kill(handle->pid, 9) == -1)
267        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_STOP, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
268
269    handle->executed = false;
270}
271
272//-------------------------------------------------------------------
273
274int
275process::wait()
276{
277    if (handle->joined)
278        return handle->status;
279
280    if (!handle->executed)
281        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_WAIT, exception::ERRNO_LIBDODO, PROCESSEX_ISNOTLAUNCHED, PCEXECUTIONPROCESSEX_ISNOTLAUNCHED_STR, __LINE__, __FILE__);
282
283    int status;
284
285    if (waitpid(handle->pid, &status, 0) == -1)
286        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_WAIT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
287
288    if (WIFEXITED(status))
289        handle->status = WEXITSTATUS(status);
290
291    handle->executed = false;
292    handle->joined = true;
293
294    return handle->status;
295}
296
297//-------------------------------------------------------------------
298
299#ifdef DL_EXT
300process::__module__
301process::module(const dodo::string &module,
302                void             *toInit)
303{
304#ifdef DL_FAST
305    void *handle = dlopen(module.data(), RTLD_LAZY | RTLD_NODELETE);
306#else
307    void *handle = dlopen(module.data(), RTLD_LAZY);
308#endif
309    if (handle == NULL)
310        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_MODULE, exception::ERRNO_DYNLOAD, 0, dlerror(), __LINE__, __FILE__);
311
312    initModule init = (initModule)dlsym(handle, "initPcExecutionProcessModule");
313    if (init == NULL)
314        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_MODULE, exception::ERRNO_DYNLOAD, 0, dlerror(), __LINE__, __FILE__);
315
316    __module__ mod = init(toInit);
317
318    deinitModule deinit = (deinitModule)dlsym(handle, "deinitPcExecutionProcessModule");
319    if (deinit != NULL)
320        deinit(mod.cookie);
321
322#ifndef DL_FAST
323    if (dlclose(handle) != 0)
324        dodo_throw exception::basic(exception::MODULE_PCEXECUTIONPROCESS, PROCESSEX_MODULE, exception::ERRNO_DYNLOAD, 0, dlerror(), __LINE__, __FILE__);
325#endif
326
327    return mod;
328}
329#endif
330
331//-------------------------------------------------------------------
332
Note: See TracBrowser for help on using the repository browser.