1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * gwthread-pthread.c - implementation of gwthread.h using POSIX threads.
59 *
60 * Richard Braakman
61 */
62
63 #include <unistd.h>
64 #include <errno.h>
65 #include <pthread.h>
66 #include <signal.h>
67 #include <string.h>
68
69 #include "gwlib/gwlib.h"
70
71 #ifdef HAVE_LIBSSL
72 #include <openssl/err.h>
73 #endif /* HAVE_LIBSSL */
74
75 /* Maximum number of live threads we can support at once. Increasing
76 * this will increase the size of the threadtable. Use powers of two
77 * for efficiency. */
78 #define THREADTABLE_SIZE 1024
79
80 struct threadinfo
81 {
82 pthread_t self;
83 const char *name;
84 gwthread_func_t *func;
85 long number;
86 int wakefd_recv;
87 int wakefd_send;
88 /* joiners may be NULL. It is not allocated until a thread wants
89 * to register. This is safe because the thread table is always
90 * locked when a thread accesses this field. */
91 List *joiners;
92 pid_t pid;
93 };
94
95 struct new_thread_args
96 {
97 gwthread_func_t *func;
98 void *arg;
99 struct threadinfo *ti;
100 /* signals already started thread to die */
101 int failed;
102 };
103
104 /* The index is the external thread number modulo the table size; the
105 * thread number allocation code makes sure that there are no collisions. */
106 static struct threadinfo *threadtable[THREADTABLE_SIZE];
107 #define THREAD(t) (threadtable[(t) % THREADTABLE_SIZE])
108
109 /* Number of threads currently in the thread table. */
110 static long active_threads = 0;
111
112 /* Number to use for the next thread created. The actual number used
113 * may be higher than this, in order to avoid collisions in the threadtable.
114 * Specifically, (threadnumber % THREADTABLE_SIZE) must be unique for all
115 * live threads. */
116 static long next_threadnumber;
117
118 /* Info for the main thread is kept statically, because it should not
119 * be deallocated even after the thread module shuts down -- after all,
120 * the main thread is still running, and in practice, it can still
121 * output debug messages which will require the thread number. */
122 static struct threadinfo mainthread;
123
124 /* Our key for accessing the (struct gwthread *) we stash in the
125 * thread-specific-data area. This is much more efficient than
126 * accessing a global table, which we would have to lock. */
127 static pthread_key_t tsd_key;
128
129 static pthread_mutex_t threadtable_lock;
130
lock(void)131 static void inline lock(void)
132 {
133 int ret;
134
135 ret = pthread_mutex_lock(&threadtable_lock);
136 if (ret != 0) {
137 panic(ret, "gwthread-pthread: could not lock thread table");
138 }
139 }
140
unlock(void)141 static void inline unlock(void)
142 {
143 int ret;
144
145 ret = pthread_mutex_unlock(&threadtable_lock);
146 if (ret != 0) {
147 panic(ret, "gwthread-pthread: could not unlock thread table");
148 }
149 }
150
151 /* Empty the wakeup pipe, in case we got several wakeup signals before
152 * noticing. We want to wake up only once. */
flushpipe(int fd)153 static void flushpipe(int fd)
154 {
155 unsigned char buf[128];
156 ssize_t bytes;
157
158 do {
159 bytes = read(fd, buf, sizeof(buf));
160 } while (bytes > 0);
161 }
162
163 /* Allocate and fill a threadinfo structure for a new thread, and store
164 * it in a free slot in the thread table. The thread table must already
165 * be locked by the caller. Return the thread number chosen for this
166 * thread. The caller must make sure that there is room in the table. */
fill_threadinfo(pthread_t id,const char * name,gwthread_func_t * func,struct threadinfo * ti)167 static long fill_threadinfo(pthread_t id, const char *name,
168 gwthread_func_t *func,
169 struct threadinfo *ti)
170 {
171 int pipefds[2];
172 long first_try;
173
174 gw_assert(active_threads < THREADTABLE_SIZE);
175
176 /* initialize to default values */
177 ti->self = id;
178 ti->name = name;
179 ti->func = func;
180 ti->pid = -1;
181 ti->wakefd_recv = -1;
182 ti->wakefd_send = -1;
183 ti->joiners = NULL;
184 ti->number = -1;
185
186 if (pipe(pipefds) < 0) {
187 error(errno, "cannot allocate wakeup pipe for new thread");
188 return -1;
189 }
190 ti->wakefd_recv = pipefds[0];
191 ti->wakefd_send = pipefds[1];
192 socket_set_blocking(ti->wakefd_recv, 0);
193 socket_set_blocking(ti->wakefd_send, 0);
194
195 /* Find a free table entry and claim it. */
196 first_try = next_threadnumber;
197 do {
198 ti->number = next_threadnumber++;
199 /* Check if we looped all the way around the thread table. */
200 if (ti->number == first_try + THREADTABLE_SIZE) {
201 error(0, "Cannot have more than %d active threads", THREADTABLE_SIZE);
202 ti->number = -1;
203 return -1;
204 }
205 } while (THREAD(ti->number) != NULL);
206 THREAD(ti->number) = ti;
207
208 active_threads++;
209
210 return ti->number;
211 }
212
213 /* Look up the threadinfo pointer for the current thread */
getthreadinfo(void)214 static struct threadinfo *getthreadinfo(void)
215 {
216 struct threadinfo *threadinfo;
217
218 threadinfo = pthread_getspecific(tsd_key);
219 if (threadinfo == NULL) {
220 panic(0, "gwthread-pthread: pthread_getspecific failed");
221 } else {
222 gw_assert(pthread_equal(threadinfo->self, pthread_self()));
223 }
224 return threadinfo;
225 }
226
227 /*
228 * Go through the list of threads waiting for us to exit, and tell
229 * them that we're exiting. The joiner_cond entries are registered
230 * by those threads, and will be cleaned up by them.
231 */
alert_joiners(void)232 static void alert_joiners(void)
233 {
234 struct threadinfo *threadinfo;
235 pthread_cond_t *joiner_cond;
236
237 threadinfo = getthreadinfo();
238 if (!threadinfo->joiners)
239 return;
240 while ((joiner_cond = gwlist_extract_first(threadinfo->joiners))) {
241 pthread_cond_broadcast(joiner_cond);
242 }
243 }
244
delete_threadinfo(void)245 static void delete_threadinfo(void)
246 {
247 struct threadinfo *threadinfo;
248
249 threadinfo = getthreadinfo();
250 gwlist_destroy(threadinfo->joiners, NULL);
251 if (threadinfo->wakefd_recv != -1)
252 close(threadinfo->wakefd_recv);
253 if (threadinfo->wakefd_send != -1)
254 close(threadinfo->wakefd_send);
255 if (threadinfo->number != -1) {
256 THREAD(threadinfo->number) = NULL;
257 active_threads--;
258 }
259 gw_assert(threadinfo != &mainthread);
260 gw_free(threadinfo);
261 }
262
gwthread_init(void)263 void gwthread_init(void)
264 {
265 int ret;
266 int i;
267
268 pthread_mutex_init(&threadtable_lock, NULL);
269
270 ret = pthread_key_create(&tsd_key, NULL);
271 if (ret != 0) {
272 panic(ret, "gwthread-pthread: pthread_key_create failed");
273 }
274
275 for (i = 0; i < THREADTABLE_SIZE; i++) {
276 threadtable[i] = NULL;
277 }
278 active_threads = 0;
279
280 /* create main thread info */
281 if (fill_threadinfo(pthread_self(), "main", NULL, &mainthread) == -1)
282 panic(0, "gwthread-pthread: unable to fill main threadinfo.");
283
284 ret = pthread_setspecific(tsd_key, &mainthread);
285 if (ret != 0)
286 panic(ret, "gwthread-pthread: pthread_setspecific failed");
287 }
288
289 /* Note that the gwthread library can't shut down completely, because
290 * the main thread will still be running, and it may make calls to
291 * gwthread_self(). */
gwthread_shutdown(void)292 void gwthread_shutdown(void)
293 {
294 int ret;
295 int running;
296 int i;
297
298 /* Main thread must not have disappeared */
299 gw_assert(threadtable[0] != NULL);
300 lock();
301
302 running = 0;
303 /* Start i at 1 to skip the main thread, which is supposed to be
304 * still running. */
305 for (i = 1; i < THREADTABLE_SIZE; i++) {
306 if (threadtable[i] != NULL) {
307 debug("gwlib", 0, "Thread %ld (%s) still running",
308 threadtable[i]->number,
309 threadtable[i]->name);
310 running++;
311 }
312 }
313 unlock();
314
315 /* We can't do a full cleanup this way */
316 if (running)
317 return;
318
319 ret = pthread_mutex_destroy(&threadtable_lock);
320 if (ret != 0) {
321 warning(ret, "cannot destroy threadtable lock");
322 }
323
324 /* We can't delete the tsd_key here, because gwthread_self()
325 * still needs it to access the main thread's info. */
326 }
327
new_thread_cleanup(void * arg)328 static void new_thread_cleanup(void *arg)
329 {
330 struct new_thread_args *p = arg;
331
332 lock();
333 debug("gwlib.gwthread", 0, "Thread %ld (%s) terminates.",
334 p->ti->number, p->ti->name);
335 alert_joiners();
336 #ifdef HAVE_LIBSSL
337 /* Clear the OpenSSL thread-specific error queue to avoid
338 * memory leaks. */
339 ERR_remove_state(gwthread_self());
340 #endif /* HAVE_LIBSSL */
341 /* Must free p before signaling our exit, otherwise there is
342 * a race with gw_check_leaks at shutdown. */
343 gw_free(p);
344 delete_threadinfo();
345 unlock();
346 }
347
new_thread(void * arg)348 static void *new_thread(void *arg)
349 {
350 int ret;
351 struct new_thread_args *p = arg;
352
353 /* Make sure we don't start until our parent has entered
354 * our thread info in the thread table. */
355 lock();
356 /* check for initialization errors */
357 if (p->failed) {
358 /* Must free p before signaling our exit, otherwise there is
359 * a race with gw_check_leaks at shutdown. */
360 gw_free(p);
361 delete_threadinfo();
362 unlock();
363 return NULL;
364 }
365 unlock();
366
367 /* This has to be done here, because pthread_setspecific cannot
368 * be called by our parent on our behalf. That's why the ti
369 * pointer is passed in the new_thread_args structure. */
370 /* Synchronization is not a problem, because the only thread
371 * that relies on this call having been made is this one --
372 * no other thread can access our TSD anyway. */
373 ret = pthread_setspecific(tsd_key, p->ti);
374 if (ret != 0) {
375 panic(ret, "gwthread-pthread: pthread_setspecific failed");
376 }
377
378 p->ti->pid = getpid();
379 debug("gwlib.gwthread", 0, "Thread %ld (%s) maps to pid %ld.",
380 p->ti->number, p->ti->name, (long) p->ti->pid);
381
382 /* set cancel cleanup function */
383 pthread_cleanup_push(new_thread_cleanup, p);
384
385 (p->func)(p->arg);
386
387 pthread_cleanup_pop(0);
388
389 new_thread_cleanup(p);
390
391 return NULL;
392 }
393
394 /*
395 * Change this thread's signal mask to block user-visible signals
396 * (HUP, TERM, QUIT, INT), and store the old signal mask in
397 * *old_set_storage.
398 * Return 0 for success, or -1 if an error occurred.
399 */
400
401 /*
402 * This does not work in Darwin alias MacOS X alias Mach kernel,
403 * however. So we define a dummy function doing nothing.
404 */
405 #if defined(DARWIN_OLD)
406 static int pthread_sigmask();
407 #endif
408
block_user_signals(sigset_t * old_set_storage)409 static int block_user_signals(sigset_t *old_set_storage)
410 {
411 int ret;
412 sigset_t block_signals;
413
414 ret = sigemptyset(&block_signals);
415 if (ret != 0) {
416 error(errno, "gwthread-pthread: Couldn't initialize signal set");
417 return -1;
418 }
419 ret = sigaddset(&block_signals, SIGHUP);
420 ret |= sigaddset(&block_signals, SIGTERM);
421 ret |= sigaddset(&block_signals, SIGQUIT);
422 ret |= sigaddset(&block_signals, SIGINT);
423 if (ret != 0) {
424 error(0, "gwthread-pthread: Couldn't add signal to signal set");
425 return -1;
426 }
427 ret = pthread_sigmask(SIG_BLOCK, &block_signals, old_set_storage);
428 if (ret != 0) {
429 error(ret,
430 "gwthread-pthread: Couldn't disable signals for thread creation");
431 return -1;
432 }
433 return 0;
434 }
435
restore_user_signals(sigset_t * old_set)436 static void restore_user_signals(sigset_t *old_set)
437 {
438 int ret;
439
440 ret = pthread_sigmask(SIG_SETMASK, old_set, NULL);
441 if (ret != 0) {
442 panic(ret, "gwthread-pthread: Couldn't restore signal set.");
443 }
444 }
445
446
spawn_thread(gwthread_func_t * func,const char * name,void * arg)447 static long spawn_thread(gwthread_func_t *func, const char *name, void *arg)
448 {
449 int ret;
450 pthread_t id;
451 struct new_thread_args *p = NULL;
452 long new_thread_id;
453
454 /* We want to pass both these arguments to our wrapper function
455 * new_thread, but the pthread_create interface will only let
456 * us pass one pointer. So we wrap them in a little struct. */
457 p = gw_malloc(sizeof(*p));
458 p->func = func;
459 p->arg = arg;
460 p->ti = gw_malloc(sizeof(*(p->ti)));
461 p->failed = 0;
462
463 /* Lock the thread table here, so that new_thread can block
464 * on that lock. That way, the new thread won't start until
465 * we have entered it in the thread table. */
466 lock();
467
468 if (active_threads >= THREADTABLE_SIZE) {
469 unlock();
470 warning(0, "Too many threads, could not create new thread.");
471 gw_free(p);
472 return -1;
473 }
474
475 ret = pthread_create(&id, NULL, &new_thread, p);
476 if (ret != 0) {
477 unlock();
478 error(ret, "Could not create new thread.");
479 gw_free(p);
480 return -1;
481 }
482 ret = pthread_detach(id);
483 if (ret != 0) {
484 error(ret, "Could not detach new thread.");
485 }
486
487 new_thread_id = fill_threadinfo(id, name, func, p->ti);
488 if (new_thread_id == -1)
489 p->failed = 1;
490 unlock();
491
492 if (new_thread_id != -1)
493 debug("gwlib.gwthread", 0, "Started thread %ld (%s)", new_thread_id, name);
494 else
495 debug("gwlib.gwthread", 0, "Failed to start thread (%s)", name);
496
497 return new_thread_id;
498 }
499
gwthread_create_real(gwthread_func_t * func,const char * name,void * arg)500 long gwthread_create_real(gwthread_func_t *func, const char *name, void *arg)
501 {
502 int sigtrick = 0;
503 sigset_t old_signal_set;
504 long thread_id;
505
506 /*
507 * We want to make sure that only the main thread handles signals,
508 * so that each signal is handled exactly once. To do this, we
509 * make sure that each new thread has all the signals that we
510 * handle blocked. To avoid race conditions, we block them in
511 * the spawning thread first, then create the new thread (which
512 * inherits the settings), and then restore the old settings in
513 * the spawning thread. This means that there is a brief period
514 * when no signals will be processed, but during that time they
515 * should be queued by the operating system.
516 */
517 if (gwthread_self() == MAIN_THREAD_ID)
518 sigtrick = block_user_signals(&old_signal_set) == 0;
519
520 thread_id = spawn_thread(func, name, arg);
521
522 /*
523 * Restore the old signal mask. The new thread will have
524 * inherited the resticted one, but the main thread needs
525 * the old one back.
526 */
527 if (sigtrick)
528 restore_user_signals(&old_signal_set);
529
530 return thread_id;
531 }
532
gwthread_join(long thread)533 void gwthread_join(long thread)
534 {
535 struct threadinfo *threadinfo;
536 pthread_cond_t exit_cond;
537 int ret;
538
539 gw_assert(thread >= 0);
540
541 lock();
542 threadinfo = THREAD(thread);
543 if (threadinfo == NULL || threadinfo->number != thread) {
544 /* The other thread has already exited */
545 unlock();
546 return;
547 }
548
549 /* Register our desire to be alerted when that thread exits,
550 * and wait for it. */
551
552 ret = pthread_cond_init(&exit_cond, NULL);
553 if (ret != 0) {
554 warning(ret, "gwthread_join: cannot create condition variable.");
555 unlock();
556 return;
557 }
558
559 if (!threadinfo->joiners)
560 threadinfo->joiners = gwlist_create();
561 gwlist_append(threadinfo->joiners, &exit_cond);
562
563 /* The wait immediately releases the lock, and reacquires it
564 * when the condition is satisfied. So don't worry, we're not
565 * blocking while keeping the table locked. */
566 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &threadtable_lock);
567 ret = pthread_cond_wait(&exit_cond, &threadtable_lock);
568 pthread_cleanup_pop(0);
569 unlock();
570
571 if (ret != 0)
572 warning(ret, "gwthread_join: error in pthread_cond_wait");
573
574 pthread_cond_destroy(&exit_cond);
575 }
576
gwthread_join_all(void)577 void gwthread_join_all(void)
578 {
579 long i;
580 long our_thread = gwthread_self();
581
582 for (i = 0; i < THREADTABLE_SIZE; ++i) {
583 if (THREAD(our_thread) != THREAD(i))
584 gwthread_join(i);
585 }
586 }
587
gwthread_wakeup_all(void)588 void gwthread_wakeup_all(void)
589 {
590 long i;
591 long our_thread = gwthread_self();
592
593 for (i = 0; i < THREADTABLE_SIZE; ++i) {
594 if (THREAD(our_thread) != THREAD(i))
595 gwthread_wakeup(i);
596 }
597 }
598
gwthread_join_every(gwthread_func_t * func)599 void gwthread_join_every(gwthread_func_t *func)
600 {
601 struct threadinfo *ti;
602 pthread_cond_t exit_cond;
603 int ret;
604 long i;
605
606 ret = pthread_cond_init(&exit_cond, NULL);
607 if (ret != 0) {
608 warning(ret, "gwthread_join_every: cannot create condition variable.");
609 unlock();
610 return;
611 }
612
613 /*
614 * FIXME: To be really safe, this function should keep looping
615 * over the table until it does a complete run without having
616 * to call pthread_cond_wait. Otherwise, new threads could
617 * start while we wait, and we'll miss them.
618 */
619 lock();
620 for (i = 0; i < THREADTABLE_SIZE; ++i) {
621 ti = THREAD(i);
622 if (ti == NULL || ti->func != func)
623 continue;
624 debug("gwlib.gwthread", 0,
625 "Waiting for %ld (%s) to terminate",
626 ti->number, ti->name);
627 if (!ti->joiners)
628 ti->joiners = gwlist_create();
629 gwlist_append(ti->joiners, &exit_cond);
630 pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &threadtable_lock);
631 ret = pthread_cond_wait(&exit_cond, &threadtable_lock);
632 pthread_cleanup_pop(0);
633 if (ret != 0)
634 warning(ret, "gwthread_join_all: error in pthread_cond_wait");
635 }
636 unlock();
637
638 pthread_cond_destroy(&exit_cond);
639 }
640
641 /* Return the thread id of this thread. */
gwthread_self(void)642 long gwthread_self(void)
643 {
644 struct threadinfo *threadinfo;
645 threadinfo = pthread_getspecific(tsd_key);
646 if (threadinfo)
647 return threadinfo->number;
648 else
649 return -1;
650 }
651
652 /* Return the thread pid of this thread. */
gwthread_self_pid(void)653 long gwthread_self_pid(void)
654 {
655 struct threadinfo *threadinfo;
656 threadinfo = pthread_getspecific(tsd_key);
657 if (threadinfo && threadinfo->pid != -1)
658 return (long) threadinfo->pid;
659 else
660 return (long) getpid();
661 }
662
gwthread_self_ids(long * tid,long * pid)663 void gwthread_self_ids(long *tid, long *pid)
664 {
665 struct threadinfo *threadinfo;
666 threadinfo = pthread_getspecific(tsd_key);
667 if (threadinfo) {
668 *tid = threadinfo->number;
669 *pid = (threadinfo->pid != -1) ? threadinfo->pid : getpid();
670 } else {
671 *tid = -1;
672 *pid = getpid();
673 }
674 }
675
gwthread_wakeup(long thread)676 void gwthread_wakeup(long thread)
677 {
678 unsigned char c = 0;
679 struct threadinfo *threadinfo;
680 int fd;
681
682 gw_assert(thread >= 0);
683
684 lock();
685
686 threadinfo = THREAD(thread);
687 if (threadinfo == NULL || threadinfo->number != thread) {
688 unlock();
689 return;
690 }
691
692 fd = threadinfo->wakefd_send;
693 unlock();
694
695 write(fd, &c, 1);
696 }
697
gwthread_pollfd(int fd,int events,double timeout)698 int gwthread_pollfd(int fd, int events, double timeout)
699 {
700 struct pollfd pollfd[2];
701 struct threadinfo *threadinfo;
702 int milliseconds;
703 int ret;
704
705 threadinfo = getthreadinfo();
706
707 pollfd[0].fd = threadinfo->wakefd_recv;
708 pollfd[0].events = POLLIN;
709 pollfd[0].revents = 0;
710
711 pollfd[1].fd = fd;
712 pollfd[1].events = events;
713 pollfd[1].revents = 0;
714
715 milliseconds = timeout * 1000;
716 if (milliseconds < 0)
717 milliseconds = POLL_NOTIMEOUT;
718
719 ret = poll(pollfd, 2, milliseconds);
720 if (ret < 0) {
721 if (errno != EINTR)
722 error(errno, "gwthread_pollfd: error in poll");
723 return -1;
724 }
725
726 if (pollfd[0].revents)
727 flushpipe(pollfd[0].fd);
728
729 return pollfd[1].revents;
730 }
731
gwthread_poll(struct pollfd * fds,long numfds,double timeout)732 int gwthread_poll(struct pollfd *fds, long numfds, double timeout)
733 {
734 struct pollfd *pollfds;
735 struct threadinfo *threadinfo;
736 int milliseconds;
737 int ret;
738
739 threadinfo = getthreadinfo();
740
741 /* Create a new pollfd array with an extra element for the
742 * thread wakeup fd. */
743
744 pollfds = gw_malloc((numfds + 1) * sizeof(*pollfds));
745 pollfds[0].fd = threadinfo->wakefd_recv;
746 pollfds[0].events = POLLIN;
747 pollfds[0].revents = 0;
748 memcpy(pollfds + 1, fds, numfds * sizeof(*pollfds));
749
750 milliseconds = timeout * 1000;
751 if (milliseconds < 0)
752 milliseconds = POLL_NOTIMEOUT;
753
754 ret = poll(pollfds, numfds + 1, milliseconds);
755 if (ret < 0) {
756 if (errno != EINTR)
757 error(errno, "gwthread_poll: error in poll");
758 gw_free(pollfds);
759 return -1;
760 }
761 if (pollfds[0].revents)
762 flushpipe(pollfds[0].fd);
763
764 /* Copy the results back to the caller */
765 memcpy(fds, pollfds + 1, numfds * sizeof(*pollfds));
766 gw_free(pollfds);
767
768 return ret;
769 }
770
771
gwthread_sleep(double seconds)772 void gwthread_sleep(double seconds)
773 {
774 struct pollfd pollfd;
775 struct threadinfo *threadinfo;
776 int milliseconds;
777 int ret;
778
779 threadinfo = getthreadinfo();
780
781 pollfd.fd = threadinfo->wakefd_recv;
782 pollfd.events = POLLIN;
783
784 milliseconds = seconds * 1000;
785 if (milliseconds < 0)
786 milliseconds = POLL_NOTIMEOUT;
787
788 ret = poll(&pollfd, 1, milliseconds);
789 if (ret < 0) {
790 if (errno != EINTR && errno != EAGAIN) {
791 warning(errno, "gwthread_sleep: error in poll");
792 }
793 }
794 if (ret == 1) {
795 flushpipe(pollfd.fd);
796 }
797 }
798
799
gwthread_sleep_micro(double dseconds)800 void gwthread_sleep_micro(double dseconds)
801 {
802 fd_set fd_set_recv;
803 struct threadinfo *threadinfo;
804 int fd;
805 int ret;
806
807 threadinfo = getthreadinfo();
808 fd = threadinfo->wakefd_recv;
809
810 FD_ZERO(&fd_set_recv);
811 FD_SET(fd, &fd_set_recv);
812
813 if (dseconds < 0) {
814 ret = select(fd + 1, &fd_set_recv, NULL, NULL, NULL);
815 } else {
816 struct timeval timeout;
817 timeout.tv_sec = dseconds;
818 timeout.tv_usec = (dseconds - timeout.tv_sec) * 1000000;
819
820 ret = select(fd + 1, &fd_set_recv, NULL, NULL, &timeout);
821 }
822
823 if (ret < 0) {
824 if (errno != EINTR && errno != EAGAIN) {
825 warning(errno, "gwthread_sleep_micro: error in select()");
826 }
827 }
828
829 if (FD_ISSET(fd, &fd_set_recv)) {
830 flushpipe(fd);
831 }
832 }
833
834
gwthread_cancel(long thread)835 int gwthread_cancel(long thread)
836 {
837 struct threadinfo *threadinfo;
838 int ret;
839
840 gw_assert(thread >= 0);
841
842 lock();
843 threadinfo = THREAD(thread);
844 if (threadinfo == NULL || threadinfo->number != thread) {
845 ret = -1;
846 } else {
847 ret = pthread_cancel(threadinfo->self);
848 debug("gwlib.gwthread", 0, "Thread %ld (%s) canceled.",
849 threadinfo->number, threadinfo->name);
850 }
851 unlock();
852 return ret;
853 }
854
855
856 #ifndef BROKEN_PTHREADS
857
858 /* Working pthreads */
gwthread_shouldhandlesignal(int signal)859 int gwthread_shouldhandlesignal(int signal){
860 return 1;
861 }
862 #else
863
864 /* Somewhat broken pthreads */
gwthread_shouldhandlesignal(int signal)865 int gwthread_shouldhandlesignal(int signal){
866 return (gwthread_self() == MAIN_THREAD_ID);
867 }
868 #endif
869
gwthread_dumpsigmask(void)870 int gwthread_dumpsigmask(void) {
871 sigset_t signal_set;
872 int signum;
873
874 /* Grab the signal set data from our thread */
875 if (pthread_sigmask(SIG_BLOCK, NULL, &signal_set) != 0) {
876 warning(0, "gwthread_dumpsigmask: Couldn't get signal mask.");
877 return -1;
878 }
879
880 /* For each signal normally defined (there are usually only 32),
881 * print a message if we don't block it. */
882 for (signum = 1; signum <= 32; signum++) {
883 if (!sigismember(&signal_set, signum)) {
884 debug("gwlib", 0,
885 "gwthread_dumpsigmask: Signal Number %d will be caught.",
886 signum);
887 }
888 }
889 return 0;
890 }
891
892 /* DARWIN alias MacOS X doesnt have pthread_sigmask in its pthreads implementation */
893
894 #if defined(DARWIN_OLD)
pthread_sigmask()895 static int pthread_sigmask()
896 {
897 return 0;
898 }
899 #endif
900