Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
gwthread-pthread.c File Reference
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include "gwlib/gwlib.h"

Go to the source code of this file.

Data Structures

struct  threadinfo
 
struct  new_thread_args
 

Macros

#define THREADTABLE_SIZE   1024
 
#define THREAD(t)   (threadtable[(t) % THREADTABLE_SIZE])
 

Functions

static void lock (void)
 
static void unlock (void)
 
static void flushpipe (int fd)
 
static long fill_threadinfo (pthread_t id, const char *name, gwthread_func_t *func, struct threadinfo *ti)
 
static struct threadinfogetthreadinfo (void)
 
static void alert_joiners (void)
 
static void delete_threadinfo (void)
 
void gwthread_init (void)
 
void gwthread_shutdown (void)
 
static void new_thread_cleanup (void *arg)
 
static void * new_thread (void *arg)
 
static int block_user_signals (sigset_t *old_set_storage)
 
static void restore_user_signals (sigset_t *old_set)
 
static long spawn_thread (gwthread_func_t *func, const char *name, void *arg)
 
long gwthread_create_real (gwthread_func_t *func, const char *name, void *arg)
 
void gwthread_join (long thread)
 
void gwthread_join_all (void)
 
void gwthread_wakeup_all (void)
 
void gwthread_join_every (gwthread_func_t *func)
 
long gwthread_self (void)
 
long gwthread_self_pid (void)
 
void gwthread_self_ids (long *tid, long *pid)
 
void gwthread_wakeup (long thread)
 
int gwthread_pollfd (int fd, int events, double timeout)
 
int gwthread_poll (struct pollfd *fds, long numfds, double timeout)
 
void gwthread_sleep (double seconds)
 
void gwthread_sleep_micro (double dseconds)
 
int gwthread_cancel (long thread)
 
int gwthread_shouldhandlesignal (int signal)
 
int gwthread_dumpsigmask (void)
 

Variables

static struct threadinfothreadtable [THREADTABLE_SIZE]
 
static long active_threads = 0
 
static long next_threadnumber
 
static struct threadinfo mainthread
 
static pthread_key_t tsd_key
 
static pthread_mutex_t threadtable_lock
 

Macro Definition Documentation

#define THREADTABLE_SIZE   1024

Function Documentation

static void alert_joiners ( void  )
static

Definition at line 236 of file gwthread-pthread.c.

References getthreadinfo(), gwlist_extract_first(), and threadinfo::joiners.

Referenced by new_thread_cleanup().

237 {
238  struct threadinfo *threadinfo;
239  pthread_cond_t *joiner_cond;
240 
241  threadinfo = getthreadinfo();
242  if (!threadinfo->joiners)
243  return;
244  while ((joiner_cond = gwlist_extract_first(threadinfo->joiners))) {
245  pthread_cond_broadcast(joiner_cond);
246  }
247 }
void * gwlist_extract_first(List *list)
Definition: list.c:305
static struct threadinfo * getthreadinfo(void)
static int block_user_signals ( sigset_t *  old_set_storage)
static

Definition at line 413 of file gwthread-pthread.c.

References error().

Referenced by gwthread_create_real().

414 {
415  int ret;
416  sigset_t block_signals;
417 
418  ret = sigemptyset(&block_signals);
419  if (ret != 0) {
420  error(errno, "gwthread-pthread: Couldn't initialize signal set");
421  return -1;
422  }
423  ret = sigaddset(&block_signals, SIGHUP);
424  ret |= sigaddset(&block_signals, SIGTERM);
425  ret |= sigaddset(&block_signals, SIGQUIT);
426  ret |= sigaddset(&block_signals, SIGINT);
427  if (ret != 0) {
428  error(0, "gwthread-pthread: Couldn't add signal to signal set");
429  return -1;
430  }
431  ret = pthread_sigmask(SIG_BLOCK, &block_signals, old_set_storage);
432  if (ret != 0) {
433  error(ret,
434  "gwthread-pthread: Couldn't disable signals for thread creation");
435  return -1;
436  }
437  return 0;
438 }
void error(int err, const char *fmt,...)
Definition: log.c:612
static void delete_threadinfo ( void  )
static

Definition at line 249 of file gwthread-pthread.c.

References active_threads, getthreadinfo(), gw_assert(), gwlist_destroy(), threadinfo::joiners, mainthread, threadinfo::number, THREAD, threadinfo::wakefd_recv, and threadinfo::wakefd_send.

Referenced by new_thread_cleanup().

250 {
251  struct threadinfo *threadinfo;
252 
253  threadinfo = getthreadinfo();
254  gwlist_destroy(threadinfo->joiners, NULL);
255  if (threadinfo->wakefd_recv != -1)
256  close(threadinfo->wakefd_recv);
257  if (threadinfo->wakefd_send != -1)
258  close(threadinfo->wakefd_send);
259  if (threadinfo->number != -1) {
260  THREAD(threadinfo->number) = NULL;
261  active_threads--;
262  }
263  gw_assert(threadinfo != &mainthread);
264  gw_free(threadinfo);
265 }
static long active_threads
static struct threadinfo * getthreadinfo(void)
gw_assert(wtls_machine->packet_to_send!=NULL)
static struct threadinfo mainthread
#define THREAD(t)
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
static long fill_threadinfo ( pthread_t  id,
const char *  name,
gwthread_func_t func,
struct threadinfo ti 
)
static

Definition at line 167 of file gwthread-pthread.c.

References active_threads, error(), threadinfo::func, gw_assert(), threadinfo::joiners, threadinfo::name, name, next_threadnumber, threadinfo::number, threadinfo::pid, threadinfo::self, socket_set_blocking(), THREAD, THREADTABLE_SIZE, threadinfo::wakefd_recv, and threadinfo::wakefd_send.

Referenced by gwthread_init(), and spawn_thread().

170 {
171  int pipefds[2];
172  long first_try;
173 
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];
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  close(ti->wakefd_recv);
204  ti->wakefd_recv = -1;
205  close(ti->wakefd_send);
206  ti->wakefd_send = -1;
207  return -1;
208  }
209  } while (THREAD(ti->number) != NULL);
210  THREAD(ti->number) = ti;
211 
212  active_threads++;
213 
214  return ti->number;
215 }
#define THREADTABLE_SIZE
void error(int err, const char *fmt,...)
Definition: log.c:612
int socket_set_blocking(int fd, int blocking)
Definition: socket.c:368
const char * name
static long next_threadnumber
gwthread_func_t * func
static long active_threads
char * name
Definition: smsc_cimd2.c:212
gw_assert(wtls_machine->packet_to_send!=NULL)
#define THREAD(t)
pthread_t self
static void flushpipe ( int  fd)
static

Definition at line 153 of file gwthread-pthread.c.

Referenced by gwthread_poll(), gwthread_pollfd(), gwthread_sleep(), and gwthread_sleep_micro().

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 }
static struct threadinfo* getthreadinfo ( void  )
static

Definition at line 218 of file gwthread-pthread.c.

References gw_assert(), panic, threadinfo::self, and tsd_key.

Referenced by alert_joiners(), delete_threadinfo(), gwthread_poll(), gwthread_pollfd(), gwthread_sleep(), and gwthread_sleep_micro().

219 {
220  struct threadinfo *threadinfo;
221 
222  threadinfo = pthread_getspecific(tsd_key);
223  if (threadinfo == NULL) {
224  panic(0, "gwthread-pthread: pthread_getspecific failed");
225  } else {
226  gw_assert(pthread_equal(threadinfo->self, pthread_self()));
227  }
228  return threadinfo;
229 }
gw_assert(wtls_machine->packet_to_send!=NULL)
#define panic
Definition: log.h:87
static pthread_key_t tsd_key
pthread_t self
int gwthread_cancel ( long  thread)

Definition at line 841 of file gwthread-pthread.c.

References debug(), gw_assert(), lock(), threadinfo::name, threadinfo::number, threadinfo::self, THREAD, and unlock().

Referenced by main().

842 {
843  struct threadinfo *threadinfo;
844  int ret;
845 
846  gw_assert(thread >= 0);
847 
848  lock();
849  threadinfo = THREAD(thread);
850  if (threadinfo == NULL || threadinfo->number != thread) {
851  ret = -1;
852  } else {
853  ret = pthread_cancel(threadinfo->self);
854  debug("gwlib.gwthread", 0, "Thread %ld (%s) canceled.",
855  threadinfo->number, threadinfo->name);
856  }
857  unlock();
858  return ret;
859 }
const char * name
gw_assert(wtls_machine->packet_to_send!=NULL)
static void unlock(void)
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define THREAD(t)
static void lock(void)
pthread_t self
long gwthread_create_real ( gwthread_func_t func,
const char *  name,
void *  arg 
)

Definition at line 506 of file gwthread-pthread.c.

References block_user_signals(), gwthread_self(), MAIN_THREAD_ID, restore_user_signals(), and spawn_thread().

507 {
508  int sigtrick = 0;
509  sigset_t old_signal_set;
510  long thread_id;
511 
512  /*
513  * We want to make sure that only the main thread handles signals,
514  * so that each signal is handled exactly once. To do this, we
515  * make sure that each new thread has all the signals that we
516  * handle blocked. To avoid race conditions, we block them in
517  * the spawning thread first, then create the new thread (which
518  * inherits the settings), and then restore the old settings in
519  * the spawning thread. This means that there is a brief period
520  * when no signals will be processed, but during that time they
521  * should be queued by the operating system.
522  */
523  if (gwthread_self() == MAIN_THREAD_ID)
524  sigtrick = block_user_signals(&old_signal_set) == 0;
525 
526  thread_id = spawn_thread(func, name, arg);
527 
528  /*
529  * Restore the old signal mask. The new thread will have
530  * inherited the resticted one, but the main thread needs
531  * the old one back.
532  */
533  if (sigtrick)
534  restore_user_signals(&old_signal_set);
535 
536  return thread_id;
537 }
long gwthread_self(void)
gwthread_func_t * func
char * name
Definition: smsc_cimd2.c:212
#define MAIN_THREAD_ID
Definition: gwthread.h:77
static long spawn_thread(gwthread_func_t *func, const char *name, void *arg)
static void restore_user_signals(sigset_t *old_set)
static int block_user_signals(sigset_t *old_set_storage)
int gwthread_dumpsigmask ( void  )

Definition at line 876 of file gwthread-pthread.c.

References debug(), and warning().

876  {
877  sigset_t signal_set;
878  int signum;
879 
880  /* Grab the signal set data from our thread */
881  if (pthread_sigmask(SIG_BLOCK, NULL, &signal_set) != 0) {
882  warning(0, "gwthread_dumpsigmask: Couldn't get signal mask.");
883  return -1;
884  }
885 
886  /* For each signal normally defined (there are usually only 32),
887  * print a message if we don't block it. */
888  for (signum = 1; signum <= 32; signum++) {
889  if (!sigismember(&signal_set, signum)) {
890  debug("gwlib", 0,
891  "gwthread_dumpsigmask: Signal Number %d will be caught.",
892  signum);
893  }
894  }
895  return 0;
896 }
void warning(int err, const char *fmt,...)
Definition: log.c:624
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void gwthread_init ( void  )

Definition at line 267 of file gwthread-pthread.c.

References active_threads, fill_threadinfo(), mainthread, panic, threadtable_lock, THREADTABLE_SIZE, and tsd_key.

Referenced by gwlib_init().

268 {
269  int ret;
270  int i;
271 
272  pthread_mutex_init(&threadtable_lock, NULL);
273 
274  ret = pthread_key_create(&tsd_key, NULL);
275  if (ret != 0) {
276  panic(ret, "gwthread-pthread: pthread_key_create failed");
277  }
278 
279  for (i = 0; i < THREADTABLE_SIZE; i++) {
280  threadtable[i] = NULL;
281  }
282  active_threads = 0;
283 
284  /* create main thread info */
285  if (fill_threadinfo(pthread_self(), "main", NULL, &mainthread) == -1)
286  panic(0, "gwthread-pthread: unable to fill main threadinfo.");
287 
288  ret = pthread_setspecific(tsd_key, &mainthread);
289  if (ret != 0)
290  panic(ret, "gwthread-pthread: pthread_setspecific failed");
291 }
#define THREADTABLE_SIZE
static struct threadinfo * threadtable[THREADTABLE_SIZE]
static long active_threads
static long fill_threadinfo(pthread_t id, const char *name, gwthread_func_t *func, struct threadinfo *ti)
static struct threadinfo mainthread
static pthread_mutex_t threadtable_lock
#define panic
Definition: log.h:87
static pthread_key_t tsd_key
void gwthread_join ( long  thread)

Definition at line 539 of file gwthread-pthread.c.

References gw_assert(), gwlist_append(), gwlist_create, threadinfo::joiners, lock(), threadinfo::number, THREAD, threadtable_lock, unlock(), and warning().

Referenced by cimd2_shutdown_cb(), emi2_sender(), fdset_destroy(), gw_timerset_destroy(), gwthread_join_all(), heartbeat_stop(), httpd_emu_destroy(), httpsmsc_receiver(), httpsmsc_sender(), io_thread(), main(), oisd_shutdown_cb(), receive_smpp_thread(), run_smsbox(), run_wapbox(), shutdown_cb(), smpp_emu(), smpp_emu_reader(), smsboxc_run(), smsc_cimd2_create(), smsc_emi2_create(), smsc_emu_destroy(), smsc_oisd_create(), smsc_smpp_create(), soap_server_stop(), soap_shutdown_cb(), store_file_shutdown(), timers_shutdown(), udp_sender(), and wrapper_sender().

540 {
541  struct threadinfo *threadinfo;
542  pthread_cond_t exit_cond;
543  int ret;
544 
545  gw_assert(thread >= 0);
546 
547  lock();
548  threadinfo = THREAD(thread);
549  if (threadinfo == NULL || threadinfo->number != thread) {
550  /* The other thread has already exited */
551  unlock();
552  return;
553  }
554 
555  /* Register our desire to be alerted when that thread exits,
556  * and wait for it. */
557 
558  ret = pthread_cond_init(&exit_cond, NULL);
559  if (ret != 0) {
560  warning(ret, "gwthread_join: cannot create condition variable.");
561  unlock();
562  return;
563  }
564 
565  if (!threadinfo->joiners)
566  threadinfo->joiners = gwlist_create();
567  gwlist_append(threadinfo->joiners, &exit_cond);
568 
569  /* The wait immediately releases the lock, and reacquires it
570  * when the condition is satisfied. So don't worry, we're not
571  * blocking while keeping the table locked. */
572  pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &threadtable_lock);
573  ret = pthread_cond_wait(&exit_cond, &threadtable_lock);
574  pthread_cleanup_pop(0);
575  unlock();
576 
577  if (ret != 0)
578  warning(ret, "gwthread_join: error in pthread_cond_wait");
579 
580  pthread_cond_destroy(&exit_cond);
581 }
void gwlist_append(List *list, void *item)
Definition: list.c:179
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
static void unlock(void)
static pthread_mutex_t threadtable_lock
#define THREAD(t)
#define gwlist_create()
Definition: list.h:136
static void lock(void)
void gwthread_join_all ( void  )

Definition at line 583 of file gwthread-pthread.c.

References gwthread_join(), gwthread_self(), THREAD, and THREADTABLE_SIZE.

Referenced by main().

584 {
585  long i;
586  long our_thread = gwthread_self();
587 
588  for (i = 0; i < THREADTABLE_SIZE; ++i) {
589  if (THREAD(our_thread) != THREAD(i))
590  gwthread_join(i);
591  }
592 }
#define THREADTABLE_SIZE
long gwthread_self(void)
void gwthread_join(long thread)
#define THREAD(t)
void gwthread_join_every ( gwthread_func_t func)

Definition at line 605 of file gwthread-pthread.c.

References debug(), threadinfo::func, gwlist_append(), gwlist_create, threadinfo::joiners, lock(), threadinfo::name, threadinfo::number, THREAD, threadtable_lock, THREADTABLE_SIZE, unlock(), and warning().

Referenced by client_shutdown(), http_close_all_ports(), httpadmin_stop(), main(), main_for_producer_and_consumer(), radius_acct_shutdown(), server_shutdown(), wap_appl_shutdown(), wap_push_ota_shutdown(), wap_push_ppg_shutdown(), wsp_push_client_shutdown(), wsp_session_shutdown(), wsp_unit_shutdown(), wtp_initiator_shutdown(), and wtp_resp_shutdown().

606 {
607  struct threadinfo *ti;
608  pthread_cond_t exit_cond;
609  int ret;
610  long i;
611 
612  ret = pthread_cond_init(&exit_cond, NULL);
613  if (ret != 0) {
614  warning(ret, "gwthread_join_every: cannot create condition variable.");
615  unlock();
616  return;
617  }
618 
619  /*
620  * FIXME: To be really safe, this function should keep looping
621  * over the table until it does a complete run without having
622  * to call pthread_cond_wait. Otherwise, new threads could
623  * start while we wait, and we'll miss them.
624  */
625  lock();
626  for (i = 0; i < THREADTABLE_SIZE; ++i) {
627  ti = THREAD(i);
628  if (ti == NULL || ti->func != func)
629  continue;
630  debug("gwlib.gwthread", 0,
631  "Waiting for %ld (%s) to terminate",
632  ti->number, ti->name);
633  if (!ti->joiners)
634  ti->joiners = gwlist_create();
635  gwlist_append(ti->joiners, &exit_cond);
636  pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &threadtable_lock);
637  ret = pthread_cond_wait(&exit_cond, &threadtable_lock);
638  pthread_cleanup_pop(0);
639  if (ret != 0)
640  warning(ret, "gwthread_join_all: error in pthread_cond_wait");
641  }
642  unlock();
643 
644  pthread_cond_destroy(&exit_cond);
645 }
#define THREADTABLE_SIZE
void gwlist_append(List *list, void *item)
Definition: list.c:179
const char * name
gwthread_func_t * func
void warning(int err, const char *fmt,...)
Definition: log.c:624
static void unlock(void)
static pthread_mutex_t threadtable_lock
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define THREAD(t)
#define gwlist_create()
Definition: list.h:136
static void lock(void)
int gwthread_poll ( struct pollfd fds,
long  numfds,
double  timeout 
)

Definition at line 738 of file gwthread-pthread.c.

References error(), pollfd::events, pollfd::fd, flushpipe(), getthreadinfo(), poll, POLL_NOTIMEOUT, POLLIN, pollfd::revents, and threadinfo::wakefd_recv.

Referenced by poller(), and server_thread().

739 {
740  struct pollfd *pollfds;
741  struct threadinfo *threadinfo;
742  int milliseconds;
743  int ret;
744 
745  threadinfo = getthreadinfo();
746 
747  /* Create a new pollfd array with an extra element for the
748  * thread wakeup fd. */
749 
750  pollfds = gw_malloc((numfds + 1) * sizeof(*pollfds));
751  pollfds[0].fd = threadinfo->wakefd_recv;
752  pollfds[0].events = POLLIN;
753  pollfds[0].revents = 0;
754  memcpy(pollfds + 1, fds, numfds * sizeof(*pollfds));
755 
756  milliseconds = timeout * 1000;
757  if (milliseconds < 0)
758  milliseconds = POLL_NOTIMEOUT;
759 
760  ret = poll(pollfds, numfds + 1, milliseconds);
761  if (ret < 0) {
762  if (errno != EINTR)
763  error(errno, "gwthread_poll: error in poll");
764  gw_free(pollfds);
765  return -1;
766  }
767  if (pollfds[0].revents)
768  flushpipe(pollfds[0].fd);
769 
770  /* Copy the results back to the caller */
771  memcpy(fds, pollfds + 1, numfds * sizeof(*pollfds));
772  gw_free(pollfds);
773 
774  return ret;
775 }
void error(int err, const char *fmt,...)
Definition: log.c:612
#define poll(fdarray, numfds, timeout)
Definition: gwpoll.h:104
#define POLL_NOTIMEOUT
Definition: gwpoll.h:100
short events
Definition: gwpoll.h:86
#define POLLIN
Definition: gwpoll.h:91
static struct threadinfo * getthreadinfo(void)
Definition: gwpoll.h:84
int fd
Definition: gwpoll.h:85
short revents
Definition: gwpoll.h:87
static void flushpipe(int fd)
int gwthread_pollfd ( int  fd,
int  events,
double  timeout 
)

Definition at line 704 of file gwthread-pthread.c.

References error(), pollfd::events, pollfd::fd, flushpipe(), getthreadinfo(), poll, POLL_NOTIMEOUT, POLLIN, pollfd::revents, and threadinfo::wakefd_recv.

Referenced by accept_thread(), cgw_listener(), cgw_wait_command(), conn_flush(), conn_wait(), emi2_listener(), fake_listener(), gw_accept(), and wait_for_connections().

705 {
706  struct pollfd pollfd[2];
707  struct threadinfo *threadinfo;
708  int milliseconds;
709  int ret;
710 
711  threadinfo = getthreadinfo();
712 
713  pollfd[0].fd = threadinfo->wakefd_recv;
714  pollfd[0].events = POLLIN;
715  pollfd[0].revents = 0;
716 
717  pollfd[1].fd = fd;
718  pollfd[1].events = events;
719  pollfd[1].revents = 0;
720 
721  milliseconds = timeout * 1000;
722  if (milliseconds < 0)
723  milliseconds = POLL_NOTIMEOUT;
724 
725  ret = poll(pollfd, 2, milliseconds);
726  if (ret < 0) {
727  if (errno != EINTR)
728  error(errno, "gwthread_pollfd: error in poll");
729  return -1;
730  }
731 
732  if (pollfd[0].revents)
733  flushpipe(pollfd[0].fd);
734 
735  return pollfd[1].revents;
736 }
void error(int err, const char *fmt,...)
Definition: log.c:612
#define poll(fdarray, numfds, timeout)
Definition: gwpoll.h:104
#define POLL_NOTIMEOUT
Definition: gwpoll.h:100
short events
Definition: gwpoll.h:86
#define POLLIN
Definition: gwpoll.h:91
static struct threadinfo * getthreadinfo(void)
Definition: gwpoll.h:84
int fd
Definition: gwpoll.h:85
short revents
Definition: gwpoll.h:87
static void flushpipe(int fd)
void gwthread_self_ids ( long *  tid,
long *  pid 
)

Definition at line 669 of file gwthread-pthread.c.

References threadinfo::number, threadinfo::pid, and tsd_key.

Referenced by format().

670 {
671  struct threadinfo *threadinfo;
672  threadinfo = pthread_getspecific(tsd_key);
673  if (threadinfo) {
674  *tid = threadinfo->number;
675  *pid = (threadinfo->pid != -1) ? threadinfo->pid : getpid();
676  } else {
677  *tid = -1;
678  *pid = getpid();
679  }
680 }
static pthread_key_t tsd_key
long gwthread_self_pid ( void  )

Definition at line 659 of file gwthread-pthread.c.

References threadinfo::pid, and tsd_key.

660 {
661  struct threadinfo *threadinfo;
662  threadinfo = pthread_getspecific(tsd_key);
663  if (threadinfo && threadinfo->pid != -1)
664  return (long) threadinfo->pid;
665  else
666  return (long) getpid();
667 }
static pthread_key_t tsd_key
int gwthread_shouldhandlesignal ( int  signal)

Definition at line 865 of file gwthread-pthread.c.

Referenced by signal_handler().

865  {
866  return 1;
867 }
void gwthread_shutdown ( void  )

Definition at line 296 of file gwthread-pthread.c.

References debug(), gw_assert(), lock(), name, number, running, threadtable_lock, THREADTABLE_SIZE, unlock(), and warning().

Referenced by gwlib_shutdown().

297 {
298  int ret;
299  int running;
300  int i;
301 
302  /* Main thread must not have disappeared */
303  gw_assert(threadtable[0] != NULL);
304  lock();
305 
306  running = 0;
307  /* Start i at 1 to skip the main thread, which is supposed to be
308  * still running. */
309  for (i = 1; i < THREADTABLE_SIZE; i++) {
310  if (threadtable[i] != NULL) {
311  debug("gwlib", 0, "Thread %ld (%s) still running",
312  threadtable[i]->number,
313  threadtable[i]->name);
314  running++;
315  }
316  }
317  unlock();
318 
319  /* We can't do a full cleanup this way */
320  if (running)
321  return;
322 
323  ret = pthread_mutex_destroy(&threadtable_lock);
324  if (ret != 0) {
325  warning(ret, "cannot destroy threadtable lock");
326  }
327 
328  /* We can't delete the tsd_key here, because gwthread_self()
329  * still needs it to access the main thread's info. */
330 }
#define THREADTABLE_SIZE
int number
Definition: smsc_cimd2.c:213
static struct threadinfo * threadtable[THREADTABLE_SIZE]
Definition: shared.h:81
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:624
gw_assert(wtls_machine->packet_to_send!=NULL)
static void unlock(void)
static pthread_mutex_t threadtable_lock
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static void lock(void)
void gwthread_sleep ( double  seconds)

Definition at line 778 of file gwthread-pthread.c.

References pollfd::events, pollfd::fd, flushpipe(), getthreadinfo(), poll, POLL_NOTIMEOUT, POLLIN, threadinfo::wakefd_recv, and warning().

Referenced by at2_detect_modem_type(), at2_device_thread(), at2_init_device(), at2_login_device(), at2_send_one_message(), at2_write(), at2_write_ctrlz(), at2_write_line(), bb_smscconn_receive_internal(), cgw_open_send_connection(), client_thread(), emi2_do_send(), emi2_wait(), heartbeat_thread(), httpd_check_authorization(), httpsmsc_send_cb(), httpsmsc_sender(), io_thread(), main(), main_connection_loop(), open_send_connection(), parachute_start(), poller(), port_remove(), push_thread(), reconnect(), restart_box(), send_message(), send_messages(), send_smpp_thread(), server_thread(), smasi_thread(), sms_router(), sms_to_smsboxes(), smsbox_thread(), smsboxc_run(), smsc2_graceful_restart(), soap_listener(), soap_server(), store_dumper(), thread1(), thread2(), wait_for_connections(), wapboxc_run(), watch_timers(), and wrapper_receiver().

779 {
780  struct pollfd pollfd;
781  struct threadinfo *threadinfo;
782  int milliseconds;
783  int ret;
784 
785  threadinfo = getthreadinfo();
786 
787  pollfd.fd = threadinfo->wakefd_recv;
788  pollfd.events = POLLIN;
789 
790  milliseconds = seconds * 1000;
791  if (milliseconds < 0)
792  milliseconds = POLL_NOTIMEOUT;
793 
794  ret = poll(&pollfd, 1, milliseconds);
795  if (ret < 0) {
796  if (errno != EINTR && errno != EAGAIN) {
797  warning(errno, "gwthread_sleep: error in poll");
798  }
799  }
800  if (ret == 1) {
802  }
803 }
#define poll(fdarray, numfds, timeout)
Definition: gwpoll.h:104
#define POLL_NOTIMEOUT
Definition: gwpoll.h:100
short events
Definition: gwpoll.h:86
#define POLLIN
Definition: gwpoll.h:91
static struct threadinfo * getthreadinfo(void)
void warning(int err, const char *fmt,...)
Definition: log.c:624
Definition: gwpoll.h:84
int fd
Definition: gwpoll.h:85
static void flushpipe(int fd)
void gwthread_sleep_micro ( double  dseconds)

Definition at line 806 of file gwthread-pthread.c.

References flushpipe(), getthreadinfo(), threadinfo::wakefd_recv, and warning().

807 {
808  fd_set fd_set_recv;
809  struct threadinfo *threadinfo;
810  int fd;
811  int ret;
812 
813  threadinfo = getthreadinfo();
814  fd = threadinfo->wakefd_recv;
815 
816  FD_ZERO(&fd_set_recv);
817  FD_SET(fd, &fd_set_recv);
818 
819  if (dseconds < 0) {
820  ret = select(fd + 1, &fd_set_recv, NULL, NULL, NULL);
821  } else {
822  struct timeval timeout;
823  timeout.tv_sec = dseconds;
824  timeout.tv_usec = (dseconds - timeout.tv_sec) * 1000000;
825 
826  ret = select(fd + 1, &fd_set_recv, NULL, NULL, &timeout);
827  }
828 
829  if (ret < 0) {
830  if (errno != EINTR && errno != EAGAIN) {
831  warning(errno, "gwthread_sleep_micro: error in select()");
832  }
833  }
834 
835  if (FD_ISSET(fd, &fd_set_recv)) {
836  flushpipe(fd);
837  }
838 }
static struct threadinfo * getthreadinfo(void)
void warning(int err, const char *fmt,...)
Definition: log.c:624
static void flushpipe(int fd)
void gwthread_wakeup ( long  thread)

Definition at line 682 of file gwthread-pthread.c.

References gw_assert(), lock(), threadinfo::number, THREAD, unlock(), and threadinfo::wakefd_send.

Referenced by add_msg_cb(), at2_add_msg_cb(), at2_shutdown_cb(), at2_start_cb(), bb_smscconn_connected(), boxc_receiver(), cgw_add_msg_cb(), cgw_listener(), cgw_shutdown_cb(), cgw_start_cb(), cimd2_add_msg_cb(), cimd2_shutdown_cb(), cimd2_start_cb(), client_destroy(), emi2_idleprocessing(), emi2_listener(), emi2_sender(), gw_timer_elapsed_start(), gw_timer_start(), gw_timerset_destroy(), gwthread_wakeup_all(), gwtimer_start(), heartbeat_stop(), http_close_all_ports(), http_close_port(), http_open_port_if(), httpd_shutdown(), httpsmsc_receiver(), httpsmsc_sender(), httpsmsc_shutdown(), io_thread(), main(), oisd_add_msg_cb(), oisd_shutdown_cb(), oisd_start_cb(), run_smsbox(), send_msg_cb(), server_shutdown(), shutdown_cb(), smpp_emu(), sms_router(), smsboxc_run(), smsc2_graceful_restart(), smsc2_restart_smsc(), smsc2_resume(), smsc2_shutdown(), smsc_cimd2_create(), smsc_emi2_create(), smsc_emu_destroy(), smsc_oisd_create(), smsc_smpp_create(), soap_add_msg_cb(), soap_server_stop(), soap_shutdown_cb(), start_cb(), store_file_shutdown(), submit_action(), submit_action_nosync(), timers_shutdown(), udp_receiver(), wapboxc_run(), wrapper_sender(), and wrapper_shutdown().

683 {
684  unsigned char c = 0;
685  struct threadinfo *threadinfo;
686  int fd;
687 
688  gw_assert(thread >= 0);
689 
690  lock();
691 
692  threadinfo = THREAD(thread);
693  if (threadinfo == NULL || threadinfo->number != thread) {
694  unlock();
695  return;
696  }
697 
698  fd = threadinfo->wakefd_send;
699  unlock();
700 
701  write(fd, &c, 1);
702 }
gw_assert(wtls_machine->packet_to_send!=NULL)
static void unlock(void)
#define THREAD(t)
static void lock(void)
void gwthread_wakeup_all ( void  )

Definition at line 594 of file gwthread-pthread.c.

References gwthread_self(), gwthread_wakeup(), THREAD, and THREADTABLE_SIZE.

Referenced by httpd_restart(), main(), and quit().

595 {
596  long i;
597  long our_thread = gwthread_self();
598 
599  for (i = 0; i < THREADTABLE_SIZE; ++i) {
600  if (THREAD(our_thread) != THREAD(i))
601  gwthread_wakeup(i);
602  }
603 }
#define THREADTABLE_SIZE
long gwthread_self(void)
#define THREAD(t)
void gwthread_wakeup(long thread)
static void lock ( void  )
inlinestatic

Definition at line 131 of file gwthread-pthread.c.

References panic, and threadtable_lock.

Referenced by gwthread_cancel(), gwthread_join(), gwthread_join_every(), gwthread_shutdown(), gwthread_wakeup(), new_thread(), new_thread_cleanup(), and spawn_thread().

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 }
static pthread_mutex_t threadtable_lock
#define panic
Definition: log.h:87
static void* new_thread ( void *  arg)
static

Definition at line 352 of file gwthread-pthread.c.

References new_thread_args::arg, debug(), new_thread_args::failed, new_thread_args::func, lock(), threadinfo::name, new_thread_cleanup(), threadinfo::number, panic, threadinfo::pid, new_thread_args::ti, tsd_key, and unlock().

Referenced by spawn_thread().

353 {
354  int ret;
355  struct new_thread_args *p = arg;
356 
357  /* Make sure we don't start until our parent has entered
358  * our thread info in the thread table. */
359  lock();
360  /* check for initialization errors */
361  if (p->failed) {
362  /* Must free p before signaling our exit, otherwise there is
363  * a race with gw_check_leaks at shutdown. */
364  gw_free(p->ti);
365  gw_free(p);
366  unlock();
367  return NULL;
368  }
369  unlock();
370 
371  /* This has to be done here, because pthread_setspecific cannot
372  * be called by our parent on our behalf. That's why the ti
373  * pointer is passed in the new_thread_args structure. */
374  /* Synchronization is not a problem, because the only thread
375  * that relies on this call having been made is this one --
376  * no other thread can access our TSD anyway. */
377  ret = pthread_setspecific(tsd_key, p->ti);
378  if (ret != 0) {
379  panic(ret, "gwthread-pthread: pthread_setspecific failed");
380  }
381 
382  p->ti->pid = getpid();
383  debug("gwlib.gwthread", 0, "Thread %ld (%s) maps to pid %ld.",
384  p->ti->number, p->ti->name, (long) p->ti->pid);
385 
386  /* set cancel cleanup function */
387  pthread_cleanup_push(new_thread_cleanup, p);
388 
389  (p->func)(p->arg);
390 
391  pthread_cleanup_pop(0);
392 
394 
395  return NULL;
396 }
gwthread_func_t * func
struct threadinfo * ti
static void new_thread_cleanup(void *arg)
const char * name
static void unlock(void)
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define panic
Definition: log.h:87
static pthread_key_t tsd_key
static void lock(void)
static void new_thread_cleanup ( void *  arg)
static

Definition at line 332 of file gwthread-pthread.c.

References alert_joiners(), new_thread_args::arg, debug(), delete_threadinfo(), gwthread_self(), lock(), threadinfo::name, threadinfo::number, new_thread_args::ti, and unlock().

Referenced by new_thread().

333 {
334  struct new_thread_args *p = arg;
335 
336  lock();
337  debug("gwlib.gwthread", 0, "Thread %ld (%s) terminates.",
338  p->ti->number, p->ti->name);
339  alert_joiners();
340 #ifdef HAVE_LIBSSL
341  /* Clear the OpenSSL thread-specific error queue to avoid
342  * memory leaks. */
343  ERR_remove_state(gwthread_self());
344 #endif /* HAVE_LIBSSL */
345  /* Must free p before signaling our exit, otherwise there is
346  * a race with gw_check_leaks at shutdown. */
347  gw_free(p);
349  unlock();
350 }
long gwthread_self(void)
struct threadinfo * ti
const char * name
static void delete_threadinfo(void)
static void alert_joiners(void)
static void unlock(void)
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static void lock(void)
static void restore_user_signals ( sigset_t *  old_set)
static

Definition at line 440 of file gwthread-pthread.c.

References panic.

Referenced by gwthread_create_real().

441 {
442  int ret;
443 
444  ret = pthread_sigmask(SIG_SETMASK, old_set, NULL);
445  if (ret != 0) {
446  panic(ret, "gwthread-pthread: Couldn't restore signal set.");
447  }
448 }
#define panic
Definition: log.h:87
static long spawn_thread ( gwthread_func_t func,
const char *  name,
void *  arg 
)
static

Definition at line 451 of file gwthread-pthread.c.

References active_threads, new_thread_args::arg, debug(), error(), new_thread_args::failed, fill_threadinfo(), new_thread_args::func, lock(), new_thread(), THREADTABLE_SIZE, new_thread_args::ti, unlock(), and warning().

Referenced by gwthread_create_real().

452 {
453  int ret;
454  pthread_t id;
455  struct new_thread_args *p = NULL;
456  long new_thread_id;
457 
458  /* We want to pass both these arguments to our wrapper function
459  * new_thread, but the pthread_create interface will only let
460  * us pass one pointer. So we wrap them in a little struct. */
461  p = gw_malloc(sizeof(*p));
462  p->func = func;
463  p->arg = arg;
464  p->ti = gw_malloc(sizeof(*(p->ti)));
465  p->failed = 0;
466 
467  /* Lock the thread table here, so that new_thread can block
468  * on that lock. That way, the new thread won't start until
469  * we have entered it in the thread table. */
470  lock();
471 
473  unlock();
474  warning(0, "Too many threads, could not create new thread.");
475  gw_free(p->ti);
476  gw_free(p);
477  return -1;
478  }
479 
480  ret = pthread_create(&id, NULL, &new_thread, p);
481  if (ret != 0) {
482  unlock();
483  error(ret, "Could not create new thread.");
484  gw_free(p->ti);
485  gw_free(p);
486  return -1;
487  }
488  ret = pthread_detach(id);
489  if (ret != 0) {
490  error(ret, "Could not detach new thread.");
491  }
492 
493  new_thread_id = fill_threadinfo(id, name, func, p->ti);
494  if (new_thread_id == -1)
495  p->failed = 1;
496  unlock();
497 
498  if (new_thread_id != -1)
499  debug("gwlib.gwthread", 0, "Started thread %ld (%s)", new_thread_id, name);
500  else
501  debug("gwlib.gwthread", 0, "Failed to start thread (%s)", name);
502 
503  return new_thread_id;
504 }
#define THREADTABLE_SIZE
void error(int err, const char *fmt,...)
Definition: log.c:612
gwthread_func_t * func
struct threadinfo * ti
static long active_threads
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:624
static long fill_threadinfo(pthread_t id, const char *name, gwthread_func_t *func, struct threadinfo *ti)
static void unlock(void)
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static void lock(void)
static void * new_thread(void *arg)
static void unlock ( void  )
inlinestatic

Definition at line 141 of file gwthread-pthread.c.

References panic, and threadtable_lock.

Referenced by gwthread_cancel(), gwthread_join(), gwthread_join_every(), gwthread_shutdown(), gwthread_wakeup(), new_thread(), new_thread_cleanup(), and spawn_thread().

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 }
static pthread_mutex_t threadtable_lock
#define panic
Definition: log.h:87

Variable Documentation

long active_threads = 0
static
struct threadinfo mainthread
static

Definition at line 122 of file gwthread-pthread.c.

Referenced by delete_threadinfo(), and gwthread_init().

long next_threadnumber
static

Definition at line 116 of file gwthread-pthread.c.

Referenced by fill_threadinfo().

struct threadinfo* threadtable[THREADTABLE_SIZE]
static

Definition at line 106 of file gwthread-pthread.c.

pthread_mutex_t threadtable_lock
static
pthread_key_t tsd_key
static
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.