1 /* thread-util.c
2 * Implementation of thread utilities
3 *
4 * Yersinia
5 * By David Barroso <tomac@yersinia.net> and Alfredo Andres <aandreswork@hotmail.com>
6 * Copyright 2005-2017 Alfredo Andres and David Barroso
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #ifndef _REENTRANT
28 #define _REENTRANT
29 #endif
30
31 #include <stdio.h>
32 #include <errno.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_INTTYPES_H
39 #include <inttypes.h>
40 #endif
41
42 #include <sys/socket.h>
43
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
46 #else
47 #ifdef HAVE_NETINET_IN_SYSTEM_H
48 #include <netinet/in_system.h>
49 #endif
50 #endif
51
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <signal.h>
55 #include <time.h>
56
57 #ifdef TIME_WITH_SYS_TIME
58 #include <sys/time.h>
59 #endif
60
61 #ifdef HAVE_UNISTD_H
62 #include <unistd.h>
63 #endif
64
65 #ifdef HAVE_STRING_H
66 #include <string.h>
67 #endif
68
69 #ifdef HAVE_STRINGS_H
70 #include <strings.h>
71 #endif
72
73 #ifdef HAVE_BSTRING_H
74 #include <bstring.h>
75 #endif
76
77 #ifdef STDC_HEADERS
78 #include <stdlib.h>
79 #endif
80
81 #include <stdarg.h>
82
83 #include "thread-util.h"
84
85 extern void write_log( u_int16_t mode, char *msg, ...);
86
87 /*
88 * Create a thread
89 *
90 int8_t
91 thread_create(pthread_t *thread_id, void *thread_body , void *arg)
92 {
93 if (pthread_create(thread_id, NULL, thread_body, arg) != 0)
94 {
95 thread_error("pthread_create",errno);
96 return -1;
97 }
98
99 return 0;
100 }
101 */
102
thread_create(THREAD * thread,void * thread_body,void * arg)103 int8_t thread_create( THREAD *thread, void *thread_body, void *arg )
104 {
105 if ( ! pthread_mutex_init( &thread->finished, NULL ) )
106 {
107 if ( ! pthread_create( &thread->id, NULL, thread_body, arg ) )
108 return 0;
109
110 thread_error( "thread_create pthread_create", errno );
111
112 pthread_mutex_destroy( &thread->finished );
113 }
114 else
115 thread_error( "thread_create pthread_mutex_init", errno );
116
117 return -1 ;
118 }
119
120
121 /*
122 * Destroy a thread with polling...
123 */
thread_destroy(THREAD * thread)124 int8_t thread_destroy( THREAD *thread )
125 {
126 int8_t ret = 0 ;
127
128 write_log(0,"\n thread_destroy %X destroying %X...\n",(int)pthread_self(), (int)thread->id);
129
130 thread->stop = 1;
131
132 if ( ! PTHREAD_JOIN( thread ) )
133 {
134 if ( pthread_mutex_unlock( &thread->finished ) )
135 {
136 thread_error( "thread_destroy pthread_mutex_unlock", errno );
137 ret = -1 ;
138 }
139 }
140 else
141 {
142 thread_error(" thread_destroy PTHREAD_JOIN",errno);
143 ret = -1;
144 }
145
146 write_log(0," thread_destroy %X after PTHREAD_JOIN %X...\n", (int)pthread_self(), (int)thread->id );
147
148 thread->stop = 0;
149 thread->id = 0;
150
151 return ret;
152 }
153
154
155 /*
156 * Destroy a thread with cancellation...
157 */
158 int8_t
thread_destroy_cancel(pthread_t thread_id)159 thread_destroy_cancel(pthread_t thread_id)
160 {
161 pthread_t id = thread_id;
162
163 if (pthread_cancel(id) != 0) {
164 thread_error(" thread_destroy_cancel pthread_cancel",errno);
165 return -1;
166 }
167
168 if (pthread_join(id, NULL) != 0) {
169 thread_error(" thread_destroy_cancel pthread_join",errno);
170 return -1;
171 }
172
173 return 0;
174 }
175
176
177 int8_t
thread_create_condsem(struct condsem * condsem)178 thread_create_condsem(struct condsem *condsem)
179 {
180 if (pthread_mutex_init(&condsem->mutex, NULL) != 0)
181 {
182 thread_error("pthread_mutex_init",errno);
183 return -1;
184 }
185
186 if (pthread_cond_init(&condsem->condvar, NULL) != 0)
187 {
188 thread_error("pthread_cond_init",errno);
189 return -1;
190 }
191
192 condsem->value = 0;
193
194 return 0;
195 }
196
197
198 void
thread_delete_condsem(struct condsem * condsem)199 thread_delete_condsem(struct condsem *condsem)
200 {
201 if (pthread_mutex_destroy(&condsem->mutex) != 0)
202 thread_error("pthread_mutex_destroy(&condsem->mutex)",errno);
203
204 if (pthread_cond_destroy(&condsem->condvar) != 0)
205 thread_error("pthread_cond_destroy(&condsem->condvar)",errno);
206 }
207
208
209 int8_t
thread_wait_cond(struct condsem * condsem)210 thread_wait_cond(struct condsem *condsem)
211 {
212 if (pthread_mutex_lock(&condsem->mutex) != 0)
213 {
214 thread_error("pthread_mutex_lock",errno);
215 return -1;
216 }
217
218 while (condsem->value <= 0)
219 {
220 if (pthread_cond_wait(&condsem->condvar, &condsem->mutex) != 0)
221 {
222 thread_error("pthread_cond_wait",errno);
223 return -1;
224 }
225 }
226
227 condsem->value--;
228
229 if (pthread_mutex_unlock(&condsem->mutex) != 0)
230 {
231 thread_error("pthread_mutex_unlock",errno);
232 return -1;
233 }
234
235 return 0;
236 }
237
238
239
240 /*
241 * Wait for condition wariable with timeout.
242 * Be aware of disabling cancellation before calling this function!!!
243 * Return THREAD_TIMEOUT on timeout, -1 on error, 0 if Ok.
244 */
245 int8_t
thread_wait_cond_timed(struct condsem * condsem,struct timeval * timeout)246 thread_wait_cond_timed(struct condsem *condsem, struct timeval *timeout)
247 {
248 int ret=0;
249 struct timeval now;
250 struct timespec abstimeout;
251
252 if (pthread_mutex_lock(&condsem->mutex) != 0)
253 {
254 thread_error("pthread_mutex_lock",errno);
255 return -1;
256 }
257
258 gettimeofday(&now, NULL);
259
260 abstimeout.tv_sec = now.tv_sec + timeout->tv_sec;
261 abstimeout.tv_nsec = (now.tv_usec + timeout->tv_usec) * 1000;
262
263 if (abstimeout.tv_nsec > 999999999)
264 {
265 abstimeout.tv_sec += (abstimeout.tv_nsec/1000000000);
266 abstimeout.tv_nsec = (abstimeout.tv_nsec%1000000000);
267 }
268
269 while (condsem->value <= 0)
270 {
271 ret = pthread_cond_timedwait(&condsem->condvar, &condsem->mutex,
272 &abstimeout);
273 if ( (ret == ETIMEDOUT) || (ret != 0) )
274 break;
275 }
276
277 if (ret == ETIMEDOUT)
278 {
279 pthread_mutex_unlock(&condsem->mutex);
280 return THREAD_TIMEOUT;
281 }
282 else
283 {
284 if (ret)
285 {
286 thread_error(" pthread_cond_timedwait()",ret);
287 pthread_mutex_unlock(&condsem->mutex);
288 return -1;
289 }
290
291 condsem->value--;
292 }
293
294 pthread_mutex_unlock(&condsem->mutex);
295
296 return 0;
297 }
298
299
300
301
302 int8_t
thread_signal_cond(struct condsem * condsem)303 thread_signal_cond(struct condsem *condsem)
304 {
305 if (pthread_mutex_lock(&condsem->mutex) != 0)
306 {
307 thread_error("pthread_mutex_lock",errno);
308 return -1;
309 }
310
311 condsem->value++;
312
313 if (pthread_mutex_unlock(&condsem->mutex) != 0)
314 {
315 thread_error("pthread_mutex_unlock",errno);
316 return -1;
317 }
318
319 if (pthread_cond_signal(&condsem->condvar) != 0)
320 {
321 thread_error("pthread_cond_signal",errno);
322 return -1;
323 }
324
325 return 0;
326 }
327
328
329 int8_t
thread_send_broadcast(struct condsem * condsem,int8_t total)330 thread_send_broadcast(struct condsem *condsem, int8_t total)
331 {
332 if (pthread_mutex_lock(&condsem->mutex) != 0)
333 {
334 thread_error("pthread_mutex_lock",errno);
335 return -1;
336 }
337
338 condsem->value += total;
339
340 if (pthread_mutex_unlock(&condsem->mutex) != 0)
341 {
342 thread_error("pthread_mutex_unlock",errno);
343 return -1;
344 }
345
346 if (pthread_cond_broadcast(&condsem->condvar) != 0)
347 {
348 thread_error("pthread_send_broadcast",errno);
349 return -1;
350 }
351
352 return 0;
353 }
354
355
356 void
thread_error(char * msg,int8_t errn)357 thread_error( char *msg, int8_t errn)
358 {
359 #ifdef HAVE_GLIBC_STRERROR_R
360 /* At least on glibc >= 2.0 Can anybody confirm?... */
361 char buf[64];
362
363 write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
364 strerror_r(errn, buf, sizeof(buf)));
365 #else
366
367 #ifdef HAVE_STRERROR
368 write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
369 strerror(errn) );
370 #else
371 write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
372 sys_errlist[errn] );
373 #endif
374
375 #endif
376
377 }
378
379
380 void
thread_libnet_error(char * msg,libnet_t * lhandler)381 thread_libnet_error( char *msg, libnet_t *lhandler)
382 {
383 write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
384 libnet_geterror(lhandler));
385 }
386
387
388 /*
389 * Our own calloc function.
390 */
391 void *
thread_calloc_r(size_t size)392 thread_calloc_r(size_t size)
393 {
394 void *aux;
395
396 #ifdef HAVE_CALLOC_R
397 aux = calloc_r(1,size);
398 #else
399 aux = calloc(1,size);
400 #endif
401
402 return aux;
403 }
404
405
406 void
thread_free_r(void * ptr)407 thread_free_r(void *ptr)
408 {
409 #ifdef HAVE_FREE_R
410 free_r(ptr);
411 #else
412 free(ptr);
413 #endif
414 }
415
416
417 int
thread_usleep(unsigned long useconds)418 thread_usleep(unsigned long useconds)
419 {
420 int ret;
421 #ifdef HAVE_NANOSLEEP
422 struct timespec timeout;
423 #else
424 struct timeval timeout;
425 #endif
426
427 if (useconds > 999999)
428 useconds = 999999;
429
430 timeout.tv_sec = 0;
431
432 #ifdef HAVE_NANOSLEEP
433 timeout.tv_nsec = (useconds*1000);
434 #else
435 timeout.tv_usec = useconds;
436 #endif
437
438 #ifdef HAVE_NANOSLEEP
439 ret = nanosleep(&timeout, NULL);
440 #else
441 ret = select(0,NULL,NULL,NULL,&timeout);
442 #endif
443
444 return ret;
445 }
446
447 /* vim:set tabstop=4:set expandtab:set shiftwidth=4:set textwidth=120: */
448