1 /*
2
3 Firewall Builder
4
5 Copyright (C) 2000 NetCitadel, LLC
6
7 Author: Vadim Kurland vadim@fwbuilder.org
8 Vadim Zaliva lord@crocodile.org
9
10 $Id$
11
12
13 This program is free software which we release under the GNU General Public
14 License. You may redistribute and/or modify this program under the terms
15 of that license as published by the Free Software Foundation; either
16 version 2 of the License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 To get a copy of the GNU General Public License, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
26 */
27
28 #include "config.h"
29 #include "fwbuilder/libfwbuilder-config.h"
30
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <vector>
35 #include <iostream>
36 #include <pthread.h>
37
38 // #include <unistd.h>
39 #include <sys/types.h>
40 #include <errno.h>
41 #include <signal.h>
42
43 #include "fwbuilder/BackgroundOp.h"
44
45 using namespace std;
46 using namespace libfwbuilder;
47
48
BackgroundOp()49 BackgroundOp::BackgroundOp():running(false),connected(true)
50 {
51 error = NULL;
52 stop_program = new SyncFlag(false);
53 iamdead = new SyncFlag(false);
54 pthread_attr_init(&tattr);
55 }
56
57 /*
58 * we destroy logger in the background thread because run_impl may use
59 * logger and we should be able to destroy object of this class even
60 * while background thread is working.
61 *
62 * iamdead should not be deleted either because it is used as a flag
63 * so that background thread would know if this object has been deleted
64 * while run_impl was running
65 */
~BackgroundOp()66 BackgroundOp::~BackgroundOp()
67 {
68 stop_program->lock();
69 stop_program->modify(true);
70 stop_program->unlock();
71
72 iamdead->lock();
73 iamdead->modify(true);
74 iamdead->unlock();
75
76 pthread_attr_destroy(&tattr);
77 }
78
79 /* replaced by a macro
80 void BackgroundOp::check_stop()
81 {
82 stop_program->lock();
83 if ( stop_program->peek() )
84 {
85 stop_program->unlock();
86 pthread_exit(NULL);
87 }
88 stop_program->unlock();
89 }
90 */
91
isRunning()92 bool BackgroundOp::isRunning() { return running; }
setRunning()93 void BackgroundOp::setRunning() { running=true; }
clearRunning()94 void BackgroundOp::clearRunning() { running=false; }
95
isConnected()96 bool BackgroundOp::isConnected() { return connected; }
disconnect()97 void BackgroundOp::disconnect() { connected=false; }
98
99
100
start_operation()101 Logger* BackgroundOp::start_operation() throw(FWException)
102 {
103 /*
104 * Suppose calling program wants to stop background operation. It
105 * calls stop_oprtation and some times immediately destroys
106 * BackgroundOp object. If background op. was stuck in a system
107 * call when this happened, it will check stop_program flag only
108 * after it returns from the system call. Since BackgroundOp
109 * object has been destroyed by then, the program crashes. To
110 * avoid this, we create stop_program flag here so that even
111 * BackgroundOp object is destoryed, this flag is still available
112 * and can be properly checked.
113 */
114 stop_program->lock();
115 stop_program->modify(false);
116 stop_program->unlock();
117
118 running = true;
119
120 Logger *logger = new QueueLogger();
121
122 void **void_pair = new void*[4];
123 void_pair[0] = this;
124 void_pair[1] = logger;
125 void_pair[2] = iamdead;
126 void_pair[3] = stop_program;
127
128 pthread_t tid;
129 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
130 int err = pthread_create(&tid, &tattr, background_thread, void_pair);
131 switch (err)
132 {
133 case EAGAIN:
134 throw FWException("Not enough system resources to create new thread");
135 case EINVAL:
136 throw FWException("The value specified by attr is invalid.");
137 }
138 return logger;
139 }
140
stop_operation()141 void BackgroundOp::stop_operation()
142 {
143 error = new FWException("Interrupted by user");
144 stop_program->lock();
145 stop_program->modify(true);
146 stop_program->unlock();
147 }
148
149 namespace libfwbuilder
150 {
background_thread(void * args)151 void *background_thread(void *args)
152 {
153 void **void_pair=(void**)args;
154
155 BackgroundOp *bop = (BackgroundOp*)void_pair[0];
156 Logger *logger = (Logger *) void_pair[1];
157 SyncFlag *isdead = (SyncFlag*) void_pair[2];
158 SyncFlag *stop_program = (SyncFlag*) void_pair[3];
159
160 try
161 {
162 bop->run_impl(logger,stop_program);
163 } catch (FWException &ex)
164 {
165 isdead->lock();
166 if (isdead->peek())
167 {
168 isdead->unlock();
169 delete logger;
170 delete isdead;
171 delete void_pair;
172 return(NULL);
173 }
174 *logger << "Exception: " << ex.toString().c_str() << '\n';
175 bop->error=new FWException(ex);
176 isdead->unlock();
177 }
178
179 *logger << "Background process has finished\n";
180
181 isdead->lock();
182 if (isdead->peek())
183 {
184 isdead->unlock();
185 delete logger;
186 delete isdead;
187 delete void_pair;
188 return(NULL);
189 }
190
191 /* operation completed - clear "running" flag */
192 bop->clearRunning();
193
194 isdead->unlock();
195
196 /* wait till the other thread reads all the lines from logger. If
197 * widget that was reading lines from this logger has been destroyed,
198 * it should have called BackhroundOp::disconnect to release BackgroundOp
199 * object
200 */
201
202 while (true) {
203
204 isdead->lock();
205 if (isdead->peek() || !bop->isConnected())
206 {
207 isdead->unlock();
208 break;
209 }
210 isdead->unlock();
211
212 libfwbuilder::cxx_sleep(1);
213 }
214
215 delete logger;
216 delete void_pair;
217
218 return(NULL);
219 }
220
221 }
222
223
224
225
226
227