Kannel: Open Source WAP and SMS gateway  svn-r5262
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

◆ THREAD

◆ THREADTABLE_SIZE

#define THREADTABLE_SIZE   1024

Function Documentation

◆ alert_joiners()

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)

◆ block_user_signals()

static int block_user_signals ( sigset_t *  old_set_storage)
static

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

References error().

Referenced by gwthread_create_real().

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

◆ delete_threadinfo()

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 }
gw_assert(wtls_machine->packet_to_send !=NULL)
static long active_threads
static struct threadinfo * getthreadinfo(void)
static struct threadinfo mainthread
#define THREAD(t)
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145

◆ fill_threadinfo()

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, 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:648
int socket_set_blocking(int fd, int blocking)
Definition: socket.c:368
gw_assert(wtls_machine->packet_to_send !=NULL)
const char * name
static long next_threadnumber
gwthread_func_t * func
static long active_threads
char * name
Definition: smsc_cimd2.c:212
#define THREAD(t)
pthread_t self

◆ flushpipe()

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 }

◆ getthreadinfo()

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

◆ gwthread_cancel()

int gwthread_cancel ( long  thread)

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

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

Referenced by main().

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

◆ gwthread_create_real()

long gwthread_create_real ( gwthread_func_t func,
const char *  name,
void *  arg 
)

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

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

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

◆ gwthread_dumpsigmask()

int gwthread_dumpsigmask ( void  )

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

References debug(), and warning().

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

◆ gwthread_init()

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

◆ gwthread_join()

void gwthread_join ( long  thread)

Definition at line 541 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_smppbox(), run_smsbox(), run_sqlbox(), 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().

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

◆ gwthread_join_all()

void gwthread_join_all ( void  )

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

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

Referenced by main().

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

◆ gwthread_join_every()

void gwthread_join_every ( gwthread_func_t func)

Definition at line 607 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().

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

◆ gwthread_poll()

int gwthread_poll ( struct pollfd fds,
long  numfds,
double  timeout 
)

Definition at line 740 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().

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

◆ gwthread_pollfd()

int gwthread_pollfd ( int  fd,
int  events,
double  timeout 
)

Definition at line 706 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().

707 {
708  struct pollfd pollfd[2];
709  struct threadinfo *threadinfo;
710  int milliseconds;
711  int ret;
712 
713  threadinfo = getthreadinfo();
714 
715  pollfd[0].fd = threadinfo->wakefd_recv;
716  pollfd[0].events = POLLIN;
717  pollfd[0].revents = 0;
718 
719  pollfd[1].fd = fd;
720  pollfd[1].events = events;
721  pollfd[1].revents = 0;
722 
723  milliseconds = timeout * 1000;
724  if (milliseconds < 0)
725  milliseconds = POLL_NOTIMEOUT;
726 
727  ret = poll(pollfd, 2, milliseconds);
728  if (ret < 0) {
729  if (errno != EINTR)
730  error(errno, "gwthread_pollfd: error in poll");
731  return -1;
732  }
733 
734  if (pollfd[0].revents)
735  flushpipe(pollfd[0].fd);
736 
737  return pollfd[1].revents;
738 }
void error(int err, const char *fmt,...)
Definition: log.c:648
#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)

◆ gwthread_self()

◆ gwthread_self_ids()

void gwthread_self_ids ( long *  tid,
long *  pid 
)

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

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

Referenced by format().

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

◆ gwthread_self_pid()

long gwthread_self_pid ( void  )

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

References threadinfo::pid, and tsd_key.

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

◆ gwthread_shouldhandlesignal()

int gwthread_shouldhandlesignal ( int  signal)

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

References gwthread_self(), gwthread_shouldhandlesignal(), and MAIN_THREAD_ID.

Referenced by gwthread_shouldhandlesignal(), and signal_handler().

867  {
868  return 1;
869 }

◆ gwthread_shutdown()

void gwthread_shutdown ( void  )

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

References debug(), gw_assert(), lock(), threadinfo::name, threadinfo::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]
gw_assert(wtls_machine->packet_to_send !=NULL)
Definition: shared.h:81
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:660
static void unlock(void)
static pthread_mutex_t threadtable_lock
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static void lock(void)

◆ gwthread_sleep()

void gwthread_sleep ( double  seconds)

Definition at line 780 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(), smpp_to_bearerbox(), sms_router(), sms_to_smsboxes(), smsbox_thread(), smsboxc_run(), smsc2_graceful_restart(), soap_listener(), soap_server(), sql_list(), sql_single(), store_dumper(), thread1(), thread2(), wait_for_connections(), wapboxc_run(), watch_timers(), and wrapper_receiver().

781 {
782  struct pollfd pollfd;
783  struct threadinfo *threadinfo;
784  int milliseconds;
785  int ret;
786 
787  threadinfo = getthreadinfo();
788 
789  pollfd.fd = threadinfo->wakefd_recv;
790  pollfd.events = POLLIN;
791 
792  milliseconds = seconds * 1000;
793  if (milliseconds < 0)
794  milliseconds = POLL_NOTIMEOUT;
795 
796  ret = poll(&pollfd, 1, milliseconds);
797  if (ret < 0) {
798  if (errno != EINTR && errno != EAGAIN) {
799  warning(errno, "gwthread_sleep: error in poll");
800  }
801  }
802  if (ret == 1) {
804  }
805 }
#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:660
Definition: gwpoll.h:84
int fd
Definition: gwpoll.h:85
static void flushpipe(int fd)

◆ gwthread_sleep_micro()

void gwthread_sleep_micro ( double  dseconds)

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

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

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

◆ gwthread_wakeup()

void gwthread_wakeup ( long  thread)

Definition at line 684 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().

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

◆ gwthread_wakeup_all()

void gwthread_wakeup_all ( void  )

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

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

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

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

◆ lock()

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

◆ new_thread()

static void* new_thread ( void *  arg)
static

Definition at line 354 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().

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

◆ new_thread_cleanup()

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 #if OPENSSL_VERSION_NUMBER < 0x10100000L
342  /* Clear the OpenSSL thread-specific error queue to avoid
343  * memory leaks. */
344  ERR_remove_state(gwthread_self());
345 #endif
346 #endif /* HAVE_LIBSSL */
347  /* Must free p before signaling our exit, otherwise there is
348  * a race with gw_check_leaks at shutdown. */
349  gw_free(p);
351  unlock();
352 }
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:726
static void lock(void)

◆ restore_user_signals()

static void restore_user_signals ( sigset_t *  old_set)
static

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

References panic.

Referenced by gwthread_create_real().

443 {
444  int ret;
445 
446  ret = pthread_sigmask(SIG_SETMASK, old_set, NULL);
447  if (ret != 0) {
448  panic(ret, "gwthread-pthread: Couldn't restore signal set.");
449  }
450 }
#define panic
Definition: log.h:87

◆ spawn_thread()

static long spawn_thread ( gwthread_func_t func,
const char *  name,
void *  arg 
)
static

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

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

Referenced by gwthread_create_real().

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

◆ unlock()

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

◆ active_threads

long active_threads = 0
static

◆ mainthread

struct threadinfo mainthread
static

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

Referenced by delete_threadinfo(), and gwthread_init().

◆ next_threadnumber

long next_threadnumber
static

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

Referenced by fill_threadinfo().

◆ threadtable

struct threadinfo* threadtable[THREADTABLE_SIZE]
static

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

◆ threadtable_lock

pthread_mutex_t threadtable_lock
static

◆ tsd_key

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.