Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

gwthread-pthread.c File Reference

#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include "gwlib/gwlib.h"
#include <openssl/err.h>

Include dependency graph for gwthread-pthread.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  threadinfo
struct  new_thread_args

Defines

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

Functions

void lock (void)
void unlock (void)
void flushpipe (int fd)
long fill_threadinfo (pthread_t id, const char *name, gwthread_func_t *func, struct threadinfo *ti)
threadinfogetthreadinfo (void)
void alert_joiners (void)
void delete_threadinfo (void)
void gwthread_init (void)
void gwthread_shutdown (void)
void * new_thread (void *arg)
int block_user_signals (sigset_t *old_set_storage)
void restore_user_signals (sigset_t *old_set)
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

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


Define Documentation

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

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

Referenced by delete_threadinfo(), fill_threadinfo(), gwthread_cancel(), gwthread_join(), gwthread_join_all(), gwthread_join_every(), gwthread_wakeup(), and gwthread_wakeup_all().

#define THREADTABLE_SIZE   1024
 

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

Referenced by fill_threadinfo().


Function Documentation

void alert_joiners void   )  [static]
 

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

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

Referenced by new_thread().

00233 {
00234     struct threadinfo *threadinfo;
00235     pthread_cond_t *joiner_cond;
00236 
00237     threadinfo = getthreadinfo();
00238     if (!threadinfo->joiners)
00239         return;
00240     while ((joiner_cond = gwlist_extract_first(threadinfo->joiners))) {
00241         pthread_cond_broadcast(joiner_cond);
00242     }
00243 }

Here is the call graph for this function:

int block_user_signals sigset_t *  old_set_storage  )  [static]
 

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

References error().

Referenced by gwthread_create_real().

00398 {
00399     int ret;
00400     sigset_t block_signals;
00401 
00402     ret = sigemptyset(&block_signals);
00403     if (ret != 0) {
00404         error(errno, "gwthread-pthread: Couldn't initialize signal set");
00405         return -1;
00406     }
00407     ret = sigaddset(&block_signals, SIGHUP);
00408     ret |= sigaddset(&block_signals, SIGTERM);
00409     ret |= sigaddset(&block_signals, SIGQUIT);
00410     ret |= sigaddset(&block_signals, SIGINT);
00411     if (ret != 0) {
00412         error(0, "gwthread-pthread: Couldn't add signal to signal set");
00413         return -1;
00414     }
00415     ret = pthread_sigmask(SIG_BLOCK, &block_signals, old_set_storage);
00416     if (ret != 0) {
00417         error(ret, 
00418             "gwthread-pthread: Couldn't disable signals for thread creation");
00419         return -1;
00420     }
00421     return 0;
00422 }

Here is the call graph for this function:

void delete_threadinfo void   )  [static]
 

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

00246 {
00247     struct threadinfo *threadinfo;
00248 
00249     threadinfo = getthreadinfo();
00250     gwlist_destroy(threadinfo->joiners, NULL);
00251     if (threadinfo->wakefd_recv != -1)
00252         close(threadinfo->wakefd_recv);
00253     if (threadinfo->wakefd_send != -1)
00254         close(threadinfo->wakefd_send);
00255     if (threadinfo->number != -1) {
00256         THREAD(threadinfo->number) = NULL;
00257         active_threads--;
00258     }
00259     gw_assert(threadinfo != &mainthread);
00260     gw_free(threadinfo);
00261 }

Here is the call graph for this function:

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().

00170 {
00171     int pipefds[2];
00172     long first_try;
00173 
00174     gw_assert(active_threads < THREADTABLE_SIZE);
00175 
00176     /* initialize to default values */
00177     ti->self = id;
00178     ti->name = name;
00179     ti->func = func;
00180     ti->pid = -1;
00181     ti->wakefd_recv = -1;
00182     ti->wakefd_send = -1;
00183     ti->joiners = NULL;
00184     ti->number = -1;
00185 
00186     if (pipe(pipefds) < 0) {
00187         error(errno, "cannot allocate wakeup pipe for new thread");
00188         return -1;
00189     }
00190     ti->wakefd_recv = pipefds[0];
00191     ti->wakefd_send = pipefds[1];
00192     socket_set_blocking(ti->wakefd_recv, 0);
00193     socket_set_blocking(ti->wakefd_send, 0);
00194 
00195     /* Find a free table entry and claim it. */
00196     first_try = next_threadnumber;
00197     do {
00198         ti->number = next_threadnumber++;
00199         /* Check if we looped all the way around the thread table. */
00200         if (ti->number == first_try + THREADTABLE_SIZE) {
00201             error(0, "Cannot have more than %d active threads", THREADTABLE_SIZE);
00202             ti->number = -1;
00203             return -1;
00204         }
00205     } while (THREAD(ti->number) != NULL);
00206     THREAD(ti->number) = ti;
00207 
00208     active_threads++;
00209 
00210     return ti->number;
00211 }

Here is the call graph for this function:

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().

00154 {
00155     unsigned char buf[128];
00156     ssize_t bytes;
00157 
00158     do {
00159         bytes = read(fd, buf, sizeof(buf));
00160     } while (bytes > 0);
00161 }

struct threadinfo* getthreadinfo void   )  [static]
 

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

00215 {
00216     struct threadinfo *threadinfo;
00217 
00218     threadinfo = pthread_getspecific(tsd_key);
00219     if (threadinfo == NULL) {
00220         panic(0, "gwthread-pthread: pthread_getspecific failed");
00221     } else {
00222         gw_assert(pthread_equal(threadinfo->self, pthread_self()));
00223     }
00224     return threadinfo;
00225 }

int gwthread_cancel long  thread  ) 
 

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

References gw_assert, threadinfo::number, threadinfo::self, and THREAD.

Referenced by main().

00820 {
00821     struct threadinfo *threadinfo;
00822     
00823     gw_assert(thread >= 0);
00824     
00825     threadinfo = THREAD(thread);
00826     if (threadinfo == NULL || threadinfo->number != thread) {
00827         return -1;
00828     } else {
00829         return pthread_cancel(threadinfo->self);
00830     }
00831 }

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

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

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

00489 {
00490     int sigtrick = 0;
00491     sigset_t old_signal_set;
00492     long thread_id;
00493 
00494     /*
00495      * We want to make sure that only the main thread handles signals,
00496      * so that each signal is handled exactly once.  To do this, we
00497      * make sure that each new thread has all the signals that we
00498      * handle blocked.  To avoid race conditions, we block them in 
00499      * the spawning thread first, then create the new thread (which
00500      * inherits the settings), and then restore the old settings in
00501      * the spawning thread.  This means that there is a brief period
00502      * when no signals will be processed, but during that time they
00503      * should be queued by the operating system.
00504      */
00505     if (gwthread_self() == MAIN_THREAD_ID)
00506         sigtrick = block_user_signals(&old_signal_set) == 0;
00507 
00508     thread_id = spawn_thread(func, name, arg);
00509 
00510     /*
00511      * Restore the old signal mask.  The new thread will have
00512      * inherited the resticted one, but the main thread needs
00513      * the old one back.
00514      */
00515     if (sigtrick)
00516         restore_user_signals(&old_signal_set);
00517     
00518     return thread_id;
00519 }

Here is the call graph for this function:

int gwthread_dumpsigmask void   ) 
 

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

References debug(), and warning().

00848                                {
00849     sigset_t signal_set;
00850     int signum;
00851 
00852     /* Grab the signal set data from our thread */
00853     if (pthread_sigmask(SIG_BLOCK, NULL, &signal_set) != 0) {
00854         warning(0, "gwthread_dumpsigmask: Couldn't get signal mask.");
00855         return -1;
00856     }
00857     
00858     /* For each signal normally defined (there are usually only 32),
00859      * print a message if we don't block it. */
00860     for (signum = 1; signum <= 32; signum++) {
00861          if (!sigismember(&signal_set, signum)) {
00862              debug("gwlib", 0,
00863              "gwthread_dumpsigmask: Signal Number %d will be caught.", 
00864              signum);
00865          }
00866     }
00867     return 0;
00868 }

Here is the call graph for this function:

void gwthread_init void   ) 
 

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

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

Referenced by gwlib_init().

00264 {
00265     int ret;
00266     int i;
00267 
00268     pthread_mutex_init(&threadtable_lock, NULL);
00269 
00270     ret = pthread_key_create(&tsd_key, NULL);
00271     if (ret != 0) {
00272         panic(ret, "gwthread-pthread: pthread_key_create failed");
00273     }
00274 
00275     for (i = 0; i < THREADTABLE_SIZE; i++) {
00276         threadtable[i] = NULL;
00277     }
00278     active_threads = 0;
00279 
00280     /* create main thread info */
00281     if (fill_threadinfo(pthread_self(), "main", NULL, &mainthread) == -1)
00282         panic(0, "gwthread-pthread: unable to fill main threadinfo.");
00283 
00284     ret = pthread_setspecific(tsd_key, &mainthread);
00285     if (ret != 0)
00286         panic(ret, "gwthread-pthread: pthread_setspecific failed");
00287 }

Here is the call graph for this function:

void gwthread_join long  thread  ) 
 

Definition at line 521 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(), gwthread_join_all(), heartbeat_stop(), httpd_emu_destroy(), httpsmsc_send_cb(), 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().

00522 {
00523     struct threadinfo *threadinfo;
00524     pthread_cond_t exit_cond;
00525     int ret;
00526 
00527     gw_assert(thread >= 0);
00528 
00529     lock();
00530     threadinfo = THREAD(thread);
00531     if (threadinfo == NULL || threadinfo->number != thread) {
00532         /* The other thread has already exited */
00533         unlock();
00534         return;
00535     }
00536 
00537     /* Register our desire to be alerted when that thread exits,
00538      * and wait for it. */
00539 
00540     ret = pthread_cond_init(&exit_cond, NULL);
00541     if (ret != 0) {
00542         warning(ret, "gwthread_join: cannot create condition variable.");
00543         unlock();
00544         return;
00545     }
00546 
00547     if (!threadinfo->joiners)
00548         threadinfo->joiners = gwlist_create();
00549     gwlist_append(threadinfo->joiners, &exit_cond);
00550 
00551     /* The wait immediately releases the lock, and reacquires it
00552      * when the condition is satisfied.  So don't worry, we're not
00553      * blocking while keeping the table locked. */
00554     ret = pthread_cond_wait(&exit_cond, &threadtable_lock);
00555     unlock();
00556 
00557     if (ret != 0)
00558         warning(ret, "gwthread_join: error in pthread_cond_wait");
00559 
00560     pthread_cond_destroy(&exit_cond);
00561 }

Here is the call graph for this function:

void gwthread_join_all void   ) 
 

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

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

Referenced by main().

00564 {
00565     long i;
00566     long our_thread = gwthread_self();
00567 
00568     for (i = 0; i < THREADTABLE_SIZE; ++i) {
00569         if (THREAD(our_thread) != THREAD(i))
00570             gwthread_join(i);
00571     }
00572 }

Here is the call graph for this function:

void gwthread_join_every gwthread_func_t func  ) 
 

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

References debug(), threadinfo::func, gwlist_append(), gwlist_create, threadinfo::joiners, lock, threadinfo::name, threadinfo::number, THREAD, threadtable_lock, 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().

00586 {
00587     struct threadinfo *ti;
00588     pthread_cond_t exit_cond;
00589     int ret;
00590     long i;
00591 
00592     ret = pthread_cond_init(&exit_cond, NULL);
00593     if (ret != 0) {
00594         warning(ret, "gwthread_join_every: cannot create condition variable.");
00595         unlock();
00596         return;
00597     }
00598 
00599     /*
00600      * FIXME: To be really safe, this function should keep looping
00601      * over the table until it does a complete run without having
00602      * to call pthread_cond_wait.  Otherwise, new threads could
00603      * start while we wait, and we'll miss them.
00604      */
00605     lock();
00606     for (i = 0; i < THREADTABLE_SIZE; ++i) {
00607         ti = THREAD(i);
00608         if (ti == NULL || ti->func != func)
00609             continue;
00610         debug("gwlib.gwthread", 0,
00611               "Waiting for %ld (%s) to terminate",
00612               ti->number, ti->name);
00613         if (!ti->joiners)
00614             ti->joiners = gwlist_create();
00615         gwlist_append(ti->joiners, &exit_cond);
00616         ret = pthread_cond_wait(&exit_cond, &threadtable_lock);
00617         if (ret != 0)
00618             warning(ret, "gwthread_join_all: error in pthread_cond_wait");
00619     }
00620     unlock();
00621 
00622     pthread_cond_destroy(&exit_cond);
00623 }

Here is the call graph for this function:

int gwthread_poll struct pollfd fds,
long  numfds,
double  timeout
 

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

References error(), pollfd::fd, flushpipe(), getthreadinfo(), poll, and threadinfo::wakefd_recv.

Referenced by poller(), and server_thread().

00717 {
00718     struct pollfd *pollfds;
00719     struct threadinfo *threadinfo;
00720     int milliseconds;
00721     int ret;
00722 
00723     threadinfo = getthreadinfo();
00724 
00725     /* Create a new pollfd array with an extra element for the
00726      * thread wakeup fd. */
00727 
00728     pollfds = gw_malloc((numfds + 1) * sizeof(*pollfds));
00729     pollfds[0].fd = threadinfo->wakefd_recv;
00730     pollfds[0].events = POLLIN;
00731     pollfds[0].revents = 0;
00732     memcpy(pollfds + 1, fds, numfds * sizeof(*pollfds));
00733 
00734     milliseconds = timeout * 1000;
00735     if (milliseconds < 0)
00736         milliseconds = POLL_NOTIMEOUT;
00737 
00738     ret = poll(pollfds, numfds + 1, milliseconds);
00739     if (ret < 0) {
00740         if (errno != EINTR)
00741             error(errno, "gwthread_poll: error in poll");
00742         gw_free(pollfds);
00743         return -1;
00744     }
00745     if (pollfds[0].revents)
00746         flushpipe(pollfds[0].fd);
00747 
00748     /* Copy the results back to the caller */
00749     memcpy(fds, pollfds + 1, numfds * sizeof(*pollfds));
00750     gw_free(pollfds);
00751 
00752     return ret;
00753 }

Here is the call graph for this function:

int gwthread_pollfd int  fd,
int  events,
double  timeout
 

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

References error(), pollfd::events, pollfd::fd, flushpipe(), getthreadinfo(), poll, 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().

00683 {
00684     struct pollfd pollfd[2];
00685     struct threadinfo *threadinfo;
00686     int milliseconds;
00687     int ret;
00688 
00689     threadinfo = getthreadinfo();
00690 
00691     pollfd[0].fd = threadinfo->wakefd_recv;
00692     pollfd[0].events = POLLIN;
00693     pollfd[0].revents = 0;
00694 
00695     pollfd[1].fd = fd;
00696     pollfd[1].events = events;
00697     pollfd[1].revents = 0;
00698 
00699     milliseconds = timeout * 1000;
00700     if (milliseconds < 0)
00701         milliseconds = POLL_NOTIMEOUT;
00702 
00703     ret = poll(pollfd, 2, milliseconds);
00704     if (ret < 0) {
00705         if (errno != EINTR)
00706             error(errno, "gwthread_pollfd: error in poll");
00707         return -1;
00708     }
00709 
00710     if (pollfd[0].revents)
00711         flushpipe(pollfd[0].fd);
00712 
00713     return pollfd[1].revents;
00714 }

Here is the call graph for this function:

long gwthread_self void   ) 
 

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

References threadinfo::number, and tsd_key.

Referenced by client_thread(), conn_claim(), fdset_destroy(), fdset_listen(), fdset_register(), fdset_set_timeout(), fdset_unregister(), find_entry(), gw_prioqueue_consume(), gw_rwlock_unlock(), gw_rwlock_wrlock(), gwlist_consume(), gwlist_timed_consume(), gwlist_wait_until_nonempty(), gwthread_create_real(), gwthread_join_all(), gwthread_wakeup_all(), handle_action(), lock_in(), lock_out(), mutex_lock_real(), mutex_trylock_real(), new_thread(), openssl_init_locks(), producer(), and push_thread().

00627 {
00628     struct threadinfo *threadinfo;
00629     threadinfo = pthread_getspecific(tsd_key);
00630     if (threadinfo) 
00631         return threadinfo->number;
00632     else
00633         return -1;
00634 }

void gwthread_self_ids long *  tid,
long *  pid
 

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

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

Referenced by format().

00648 {
00649     struct threadinfo *threadinfo;
00650     threadinfo = pthread_getspecific(tsd_key);
00651     if (threadinfo) {
00652         *tid = threadinfo->number;
00653         *pid = (threadinfo->pid != -1) ? threadinfo->pid : getpid();
00654     } else {
00655         *tid = -1;
00656         *pid = getpid();
00657     }
00658 }

long gwthread_self_pid void   ) 
 

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

References threadinfo::pid, and tsd_key.

00638 {
00639     struct threadinfo *threadinfo;
00640     threadinfo = pthread_getspecific(tsd_key);
00641     if (threadinfo && threadinfo->pid != -1) 
00642         return (long) threadinfo->pid;
00643     else
00644         return (long) getpid();
00645 }

int gwthread_shouldhandlesignal int  signal  ) 
 

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

Referenced by signal_handler().

00837                                            {
00838     return 1;
00839 }

void gwthread_shutdown void   ) 
 

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

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

Referenced by gwlib_shutdown().

00293 {
00294     int ret;
00295     int running;
00296     int i;
00297 
00298     /* Main thread must not have disappeared */
00299     gw_assert(threadtable[0] != NULL);
00300     lock();
00301 
00302     running = 0;
00303     /* Start i at 1 to skip the main thread, which is supposed to be
00304      * still running. */
00305     for (i = 1; i < THREADTABLE_SIZE; i++) {
00306         if (threadtable[i] != NULL) {
00307             debug("gwlib", 0, "Thread %ld (%s) still running",
00308                   threadtable[i]->number,
00309                   threadtable[i]->name);
00310             running++;
00311         }
00312     }
00313     unlock();
00314 
00315     /* We can't do a full cleanup this way */
00316     if (running)
00317         return;
00318 
00319     ret = pthread_mutex_destroy(&threadtable_lock);
00320     if (ret != 0) {
00321         warning(ret, "cannot destroy threadtable lock");
00322     }
00323 
00324     /* We can't delete the tsd_key here, because gwthread_self()
00325      * still needs it to access the main thread's info. */
00326 }

Here is the call graph for this function:

void gwthread_sleep double  seconds  ) 
 

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

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

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

00757 {
00758     struct pollfd pollfd;
00759     struct threadinfo *threadinfo;
00760     int milliseconds;
00761     int ret;
00762 
00763     threadinfo = getthreadinfo();
00764 
00765     pollfd.fd = threadinfo->wakefd_recv;
00766     pollfd.events = POLLIN;
00767 
00768     milliseconds = seconds * 1000;
00769     if (milliseconds < 0)
00770         milliseconds = POLL_NOTIMEOUT;
00771 
00772     ret = poll(&pollfd, 1, milliseconds);
00773     if (ret < 0) {
00774         if (errno != EINTR && errno != EAGAIN) {
00775             warning(errno, "gwthread_sleep: error in poll");
00776         }
00777     }
00778     if (ret == 1) {
00779         flushpipe(pollfd.fd);
00780     }
00781 }

Here is the call graph for this function:

void gwthread_sleep_micro double  dseconds  ) 
 

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

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

00785 {
00786     fd_set fd_set_recv;
00787     struct threadinfo *threadinfo;
00788     int fd;
00789     int ret;
00790 
00791     threadinfo = getthreadinfo();
00792     fd = threadinfo->wakefd_recv;
00793 
00794     FD_ZERO(&fd_set_recv);
00795     FD_SET(fd, &fd_set_recv);
00796 
00797     if (dseconds < 0) {
00798         ret = select(fd + 1, &fd_set_recv, NULL, NULL, NULL);
00799     } else {
00800         struct timeval timeout;
00801         timeout.tv_sec = dseconds;
00802         timeout.tv_usec = (dseconds - timeout.tv_sec) * 1000000;
00803 
00804         ret = select(fd + 1, &fd_set_recv, NULL, NULL, &timeout);
00805     }
00806 
00807     if (ret < 0) {
00808         if (errno != EINTR && errno != EAGAIN) {
00809             warning(errno, "gwthread_sleep_micro: error in select()");
00810         }
00811     }
00812 
00813     if (FD_ISSET(fd, &fd_set_recv)) {
00814         flushpipe(fd);
00815     }
00816 }

Here is the call graph for this function:

void gwthread_wakeup long  thread  ) 
 

Definition at line 660 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(), emi2_idleprocessing(), emi2_listener(), emi2_sender(), gwthread_wakeup_all(), gwtimer_start(), heartbeat_stop(), http_close_all_ports(), http_close_port(), http_open_port_if(), httpd_shutdown(), 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_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().

00661 {
00662     unsigned char c = 0;
00663     struct threadinfo *threadinfo;
00664     int fd;
00665 
00666     gw_assert(thread >= 0);
00667 
00668     lock();
00669 
00670     threadinfo = THREAD(thread);
00671     if (threadinfo == NULL || threadinfo->number != thread) {
00672         unlock();
00673         return;
00674     }
00675 
00676     fd = threadinfo->wakefd_send;
00677     unlock();
00678 
00679     write(fd, &c, 1);
00680 }

void gwthread_wakeup_all void   ) 
 

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

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

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

00575 {
00576     long i;
00577     long our_thread = gwthread_self();
00578 
00579     for (i = 0; i < THREADTABLE_SIZE; ++i) {
00580         if (THREAD(our_thread) != THREAD(i))
00581             gwthread_wakeup(i);
00582     }
00583 }

Here is the call graph for this function:

void lock void   )  [inline, static]
 

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

References panic, and threadtable_lock.

00132 {
00133     int ret;
00134 
00135     ret = pthread_mutex_lock(&threadtable_lock);
00136     if (ret != 0) {
00137         panic(ret, "gwthread-pthread: could not lock thread table");
00138     }
00139 }

void* new_thread void *  arg  )  [static]
 

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

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

Referenced by spawn_thread().

00329 {
00330     int ret;
00331     struct new_thread_args *p = arg;
00332 
00333     /* Make sure we don't start until our parent has entered
00334      * our thread info in the thread table. */
00335     lock();
00336     /* check for initialization errors */
00337     if (p->failed) {
00338         /* Must free p before signaling our exit, otherwise there is
00339         * a race with gw_check_leaks at shutdown. */
00340         gw_free(p);
00341         delete_threadinfo();
00342         unlock();
00343         return NULL;
00344     }
00345     unlock();
00346 
00347     /* This has to be done here, because pthread_setspecific cannot
00348      * be called by our parent on our behalf.  That's why the ti
00349      * pointer is passed in the new_thread_args structure. */
00350     /* Synchronization is not a problem, because the only thread
00351      * that relies on this call having been made is this one --
00352      * no other thread can access our TSD anyway. */
00353     ret = pthread_setspecific(tsd_key, p->ti);
00354     if (ret != 0) {
00355         panic(ret, "gwthread-pthread: pthread_setspecific failed");
00356     }
00357 
00358     p->ti->pid = getpid();
00359     debug("gwlib.gwthread", 0, "Thread %ld (%s) maps to pid %ld.",
00360           p->ti->number, p->ti->name, (long) p->ti->pid);
00361 
00362     (p->func)(p->arg);
00363 
00364     lock();
00365     debug("gwlib.gwthread", 0, "Thread %ld (%s) terminates.",
00366           p->ti->number, p->ti->name);
00367     alert_joiners();
00368 #ifdef HAVE_LIBSSL
00369     /* Clear the OpenSSL thread-specific error queue to avoid
00370      * memory leaks. */
00371     ERR_remove_state(gwthread_self());
00372 #endif /* HAVE_LIBSSL */
00373     /* Must free p before signaling our exit, otherwise there is
00374      * a race with gw_check_leaks at shutdown. */
00375     gw_free(p);
00376     delete_threadinfo();
00377     unlock();
00378 
00379     return NULL;
00380 }

Here is the call graph for this function:

void restore_user_signals sigset_t *  old_set  )  [static]
 

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

References panic.

Referenced by gwthread_create_real().

00425 {
00426     int ret;
00427 
00428     ret = pthread_sigmask(SIG_SETMASK, old_set, NULL);
00429     if (ret != 0) {
00430         panic(ret, "gwthread-pthread: Couldn't restore signal set.");
00431     }
00432 }

long spawn_thread gwthread_func_t func,
const char *  name,
void *  arg
[static]
 

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

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

Referenced by gwthread_create_real().

00436 {
00437     int ret;
00438     pthread_t id;
00439     struct new_thread_args *p = NULL;
00440     long new_thread_id;
00441 
00442     /* We want to pass both these arguments to our wrapper function
00443      * new_thread, but the pthread_create interface will only let
00444      * us pass one pointer.  So we wrap them in a little struct. */
00445     p = gw_malloc(sizeof(*p));
00446     p->func = func;
00447     p->arg = arg;
00448     p->ti = gw_malloc(sizeof(*(p->ti)));
00449     p->failed = 0;
00450 
00451     /* Lock the thread table here, so that new_thread can block
00452      * on that lock.  That way, the new thread won't start until
00453      * we have entered it in the thread table. */
00454     lock();
00455 
00456     if (active_threads >= THREADTABLE_SIZE) {
00457         unlock();
00458         warning(0, "Too many threads, could not create new thread.");
00459         gw_free(p);
00460         return -1;
00461     }
00462 
00463     ret = pthread_create(&id, NULL, &new_thread, p);
00464     if (ret != 0) {
00465         unlock();
00466         error(ret, "Could not create new thread.");
00467         gw_free(p);
00468         return -1;
00469     }
00470     ret = pthread_detach(id);
00471     if (ret != 0) {
00472         error(ret, "Could not detach new thread.");
00473     }
00474 
00475     new_thread_id = fill_threadinfo(id, name, func, p->ti);
00476     if (new_thread_id == -1)
00477         p->failed = 1;
00478     unlock();
00479     
00480     if (new_thread_id != -1)
00481         debug("gwlib.gwthread", 0, "Started thread %ld (%s)", new_thread_id, name);
00482     else
00483         debug("gwlib.gwthread", 0, "Failed to start thread (%s)", name);
00484 
00485     return new_thread_id;
00486 }

Here is the call graph for this function:

void unlock void   )  [inline, static]
 

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

References panic, and threadtable_lock.

00142 {
00143     int ret;
00144 
00145     ret = pthread_mutex_unlock(&threadtable_lock);
00146     if (ret != 0) {
00147         panic(ret, "gwthread-pthread: could not unlock thread table");
00148     }
00149 }


Variable Documentation

long active_threads = 0 [static]
 

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

Referenced by delete_threadinfo(), fill_threadinfo(), gwthread_init(), and spawn_thread().

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.

Referenced by gwthread_init(), and gwthread_shutdown().

pthread_mutex_t threadtable_lock [static]
 

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

Referenced by gwthread_init(), gwthread_join(), gwthread_join_every(), gwthread_shutdown(), lock(), and unlock().

pthread_key_t tsd_key [static]
 

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

Referenced by getthreadinfo(), gwthread_init(), gwthread_self(), gwthread_self_ids(), gwthread_self_pid(), and new_thread().

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