"Fossies" - the Fresh Open Source Software Archive 
Member "ettercap-0.8.3.1/src/ec_threads.c" (1 Aug 2020, 10284 Bytes) of package /linux/privat/ettercap-0.8.3.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ec_threads.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
0.8.3_vs_0.8.3.1.
1 /*
2 ettercap -- thread handling
3
4 Copyright (C) ALoR & NaGA
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 Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include <ec.h>
23 #include <ec_threads.h>
24
25 #include <pthread.h>
26 #include <errno.h>
27
28 struct thread_list {
29 struct ec_thread t;
30 LIST_ENTRY (thread_list) next;
31 };
32
33
34 /* global data */
35
36 /* a value to be used to return errors in fuctcions using pthread_t values */
37 static pthread_t EC_PTHREAD_NULL = 0;
38 #define EC_PTHREAD_SELF EC_PTHREAD_NULL
39
40 #define DETACHED_THREAD 1
41 #define JOINABLE_THREAD 0
42
43 static LIST_HEAD(, thread_list) thread_list_head;
44
45 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
46 #define THREADS_LOCK do{ pthread_mutex_lock(&threads_mutex); } while(0)
47 #define THREADS_UNLOCK do{ pthread_mutex_unlock(&threads_mutex); } while(0)
48
49 static pthread_mutex_t init_mtx = PTHREAD_MUTEX_INITIALIZER;
50 static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER;
51 #define INIT_LOCK do{ DEBUG_MSG("thread_init_lock"); pthread_mutex_lock(&init_mtx); } while(0)
52 #define INIT_UNLOCK do{ DEBUG_MSG("thread_init_unlock"); pthread_mutex_unlock(&init_mtx); } while(0)
53
54 /* protos... */
55
56 pthread_t ec_thread_detached(char *name, char *desc, void *(*function)(void *), void *args, int detached);
57
58 /*******************************************/
59
60 /* returns the name of a thread */
61
62 char * ec_thread_getname(pthread_t id)
63 {
64 struct thread_list *current;
65 char *name;
66
67 if (pthread_equal(id, EC_PTHREAD_SELF))
68 id = pthread_self();
69
70 /* don't lock here to avoid deadlock in debug messages */
71 #ifndef DEBUG
72 THREADS_LOCK;
73 #endif
74
75 LIST_FOREACH(current, &thread_list_head, next) {
76 if (pthread_equal(current->t.id, id)) {
77 name = current->t.name;
78 #ifndef DEBUG
79 THREADS_UNLOCK;
80 #endif
81 return name;
82 }
83 }
84
85 #ifndef DEBUG
86 THREADS_UNLOCK;
87 #endif
88
89 return "NR_THREAD";
90 }
91
92 /*
93 * returns the pid of a thread
94 * ZERO if not found !! (take care, not -E_NOTFOUND !)
95 */
96
97 pthread_t ec_thread_getpid(char *name)
98 {
99 struct thread_list *current;
100 pthread_t pid;
101
102 /*
103 * if "name" is explicitely set up NULL, the top-level pthread_t
104 * is returned w/o iterating through the thread-list
105 */
106 if (name == NULL)
107 return EC_PTHREAD_NULL;
108
109 THREADS_LOCK;
110
111 LIST_FOREACH(current, &thread_list_head, next) {
112 if (!strcasecmp(current->t.name,name)) {
113 pid = current->t.id;
114 THREADS_UNLOCK;
115 return pid;
116 }
117 }
118
119 THREADS_UNLOCK;
120
121 return EC_PTHREAD_NULL;
122 }
123
124 /* returns the description of a thread */
125
126 char * ec_thread_getdesc(pthread_t id)
127 {
128 struct thread_list *current;
129 char *desc;
130
131 if (pthread_equal(id, EC_PTHREAD_SELF))
132 id = pthread_self();
133
134 THREADS_LOCK;
135
136 LIST_FOREACH(current, &thread_list_head, next) {
137 if (pthread_equal(current->t.id, id)) {
138 desc = current->t.description;
139 THREADS_UNLOCK;
140 return desc;
141 }
142 }
143
144 THREADS_UNLOCK;
145
146 return "";
147 }
148
149
150 /* add a thread in the thread list */
151 void ec_thread_register(pthread_t id, char *name, char *desc)
152 {
153 ec_thread_register_detached(id, name, desc, JOINABLE_THREAD);
154 }
155
156 void ec_thread_register_detached(pthread_t id, char *name, char *desc, int detached)
157 {
158 struct thread_list *current, *newelem;
159
160 if (pthread_equal(id, EC_PTHREAD_SELF))
161 id = pthread_self();
162
163 DEBUG_MSG("ec_thread_register -- [%lu] %s", PTHREAD_ID(id), name);
164
165 SAFE_CALLOC(newelem, 1, sizeof(struct thread_list));
166
167 newelem->t.id = id;
168 newelem->t.name = strdup(name);
169 newelem->t.description = strdup(desc);
170 newelem->t.detached = detached;
171
172 THREADS_LOCK;
173
174 LIST_FOREACH(current, &thread_list_head, next) {
175 if (pthread_equal(current->t.id, id)) {
176 SAFE_FREE(current->t.name);
177 SAFE_FREE(current->t.description);
178 LIST_REPLACE(current, newelem, next);
179 SAFE_FREE(current);
180 THREADS_UNLOCK;
181 return;
182 }
183 }
184
185 LIST_INSERT_HEAD(&thread_list_head, newelem, next);
186
187 THREADS_UNLOCK;
188
189 }
190
191 /*
192 * creates a new thread on the given function
193 */
194
195 pthread_t ec_thread_new(char *name, char *desc, void *(*function)(void *), void *args) {
196 return ec_thread_new_detached(name, desc, function, args, JOINABLE_THREAD);
197 }
198
199 pthread_t ec_thread_new_detached(char *name, char *desc, void *(*function)(void *), void *args, int detached)
200 {
201 pthread_t id;
202 int e;
203
204 DEBUG_MSG("ec_thread_new -- %s detached %d", name, detached);
205
206 /*
207 * lock the mutex to syncronize with the new thread.
208 * the newly created thread will call ec_thread_init(),
209 * so at the end of this function we are sure that the
210 * thread had be initialized
211 */
212 INIT_LOCK;
213
214 if (detached == DETACHED_THREAD) {
215 pthread_attr_t attr;
216 pthread_attr_init(&attr);
217 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
218 if ((e = pthread_create(&id, &attr, function, args)) != 0)
219 ERROR_MSG("not enough resources to create a new thread in this process: %s", strerror(e));
220 }else {
221 if ((e = pthread_create(&id, NULL, function, args)) != 0)
222 ERROR_MSG("not enough resources to create a new thread in this process: %s", strerror(e));
223 }
224
225 ec_thread_register_detached(id, name, desc, detached);
226
227 DEBUG_MSG("ec_thread_new -- %lu created ", PTHREAD_ID(id));
228
229 if ((e = pthread_cond_wait(&init_cond, &init_mtx)))
230 ERROR_MSG("waiting on init_cond: %s", strerror(e));
231 INIT_UNLOCK;
232
233 return id;
234 }
235
236 /*
237 * set the state of a thread
238 * all the new thread MUST call this on startup
239 */
240 void ec_thread_init(void)
241 {
242 pthread_t id = pthread_self();
243 int e;
244
245 DEBUG_MSG("ec_thread_init -- %lu", PTHREAD_ID(id));
246
247 INIT_LOCK;
248
249 /*
250 * allow a thread to be cancelled as soon as the
251 * cancellation request is received
252 */
253 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
254 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
255
256 /* sync with the creator */
257 if ((e = pthread_cond_signal(&init_cond)))
258 ERROR_MSG("raising init_cond: %s", strerror(e));
259 INIT_UNLOCK;
260
261 DEBUG_MSG("ec_thread_init -- (%lu) ready and syncronized", PTHREAD_ID(id));
262 }
263
264 /*
265 * destroy a thread in the list
266 */
267 void ec_thread_destroy(pthread_t id)
268 {
269 struct thread_list *current;
270
271 if (pthread_equal(id, EC_PTHREAD_SELF))
272 id = pthread_self();
273
274 DEBUG_MSG("ec_thread_destroy -- terminating %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
275
276
277 /* send the cancel signal to the thread */
278 pthread_cancel((pthread_t)id);
279
280
281 DEBUG_MSG("ec_thread_destroy -- [%s] terminated", ec_thread_getname(id));
282
283 THREADS_LOCK;
284
285 LIST_FOREACH(current, &thread_list_head, next) {
286 if (pthread_equal(current->t.id, id)) {
287 #ifndef BROKEN_PTHREAD_JOIN
288 if (!current->t.detached) {
289 DEBUG_MSG("ec_thread_destroy: pthread_join");
290 /* wait until it has finished */
291 pthread_join((pthread_t)id, NULL);
292 }
293 #endif
294 SAFE_FREE(current->t.name);
295 SAFE_FREE(current->t.description);
296 LIST_REMOVE(current, next);
297 SAFE_FREE(current);
298 THREADS_UNLOCK;
299 return;
300 }
301 }
302
303 THREADS_UNLOCK;
304
305 }
306
307
308 /*
309 * kill all the registerd thread but
310 * the calling one
311 */
312
313 void ec_thread_kill_all(void)
314 {
315 struct thread_list *current, *old;
316 pthread_t id = pthread_self();
317
318 DEBUG_MSG("ec_thread_kill_all -- caller %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
319
320 THREADS_LOCK;
321
322 #ifdef OS_WINDOWS
323 /* prevent hanging UI. Not sure how this works, but it does... */
324 if (EC_GBL_IFACE->pcap)
325 ec_win_pcap_stop(EC_GBL_IFACE->pcap);
326 #endif
327
328 LIST_FOREACH_SAFE(current, &thread_list_head, next, old) {
329 /* skip ourself */
330 if (!pthread_equal(current->t.id, id)) {
331 DEBUG_MSG("ec_thread_kill_all -- terminating %lu [%s]", PTHREAD_ID(current->t.id), current->t.name);
332
333 /* send the cancel signal to the thread */
334 pthread_cancel((pthread_t)current->t.id);
335
336 #ifndef BROKEN_PTHREAD_JOIN
337 if (!current->t.detached) {
338 DEBUG_MSG("ec_thread_destroy: pthread_join");
339 /* wait until it has finished */
340 pthread_join(current->t.id, NULL);
341 }
342 #endif
343
344 DEBUG_MSG("ec_thread_kill_all -- [%s] terminated", current->t.name);
345
346 SAFE_FREE(current->t.name);
347 SAFE_FREE(current->t.description);
348 LIST_REMOVE(current, next);
349 SAFE_FREE(current);
350 }
351 }
352
353 THREADS_UNLOCK;
354 }
355
356 /*
357 * used by a thread that wants to terminate itself
358 */
359 void ec_thread_exit(void)
360 {
361 struct thread_list *current, *old;
362 pthread_t id = pthread_self();
363
364 DEBUG_MSG("ec_thread_exit -- caller %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
365
366 THREADS_LOCK;
367
368 LIST_FOREACH_SAFE(current, &thread_list_head, next, old) {
369 /* delete our entry */
370 if (pthread_equal(current->t.id, id)) {
371
372 /* thread is attempting to shut down on its own, check and see if the thread is detached,
373 if not set is as a detached thread since when a thread calls this method, there is no thread
374 that will do the pthread_join to force it to release all of its resources */
375 if (!current->t.detached) {
376 pthread_detach(id);
377 }
378
379 SAFE_FREE(current->t.name);
380 SAFE_FREE(current->t.description);
381 LIST_REMOVE(current, next);
382 SAFE_FREE(current);
383 }
384 }
385
386 THREADS_UNLOCK;
387
388 /* perform a clean exit of the thread */
389 pthread_exit(0);
390
391 }
392
393 /* EOF */
394
395 // vim:ts=3:expandtab
396