modules/th/thread.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. log_print
  2. TH_acquire_read_lock
  3. TH_release_read_lock
  4. TH_acquire_write_lock
  5. TH_release_write_lock
  6. TH_init_read_write_lock
  7. TH_get_id
  8. TH_to_string
  9. TH_do_whois
  10. TH_do_config
  11. main_thread
  12. TH_run

/***************************************
  $Revision: 1.6 $

  Example code: A thread.

  Status: NOT REVUED, NOT TESTED

 Authors:       Chris Ottrey
                Joao Damas

  +html+ <DL COMPACT>
  +html+ <DT>Online References:
  +html+ <DD><UL>
  +html+ </UL>
  +html+ </DL>
 
  ******************/ /******************
  Modification History:
        ottrey (02/03/1999) Created.
        ottrey (08/03/1999) Modified.
        ottrey (17/06/1999) Stripped down.
        joao   (22/06/1999) Redid thread startup
  ******************/ /******************
  Copyright (c) 1999                              RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  ***************************************/
#include "thread.h"
#include <stdio.h>
#include "protocol_config.h"
#include "constants.h"

/*+ String sizes +*/
#define STR_S   63
#define STR_M   255
#define STR_L   1023
#define STR_XL  4095
#define STR_XXL 16383

/*+ Mutex lock.  Used for synchronizing changes. +*/
pthread_mutex_t   Whois_thread_count_lock;
pthread_mutex_t   Config_thread_count_lock;
pthread_mutex_t   Mirror_thread_count_lock;

/*+ The number of threads. +*/
int       Whois_thread_count;
int       Config_thread_count;
int       Mirror_thread_count;

typedef struct th_args {
        void * function;
        int sock;
        } th_args;

static void log_print(const char *arg) {
/* [<][>][^][v][top][bottom][index][help] */
  FILE *logf;
  char *str;

  if (CO_get_thread_logging() == 1) {
    if (strcmp(CO_get_thread_logfile(), "stdout") == 0) {
      printf(arg);
    }
    else {
      logf = fopen(CO_get_thread_logfile(), "a");
      fprintf(logf, arg);
      fclose(logf);
    }
  }

} /* log_print() */
 
/* TH_acquire_read_lock() */
/*++++++++++++++++++++++++++++++++++++++

  Aquire a readers lock.

  rw_lock_t *prw_lock Readers writers lock.

  Reference: "Multithreaded Programming Techniques - Prasad p.192"
  More:
  +html+ <PRE>
  Author:
        ottrey
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_acquire_read_lock(rw_lock_t *prw_lock) { 
/* [<][>][^][v][top][bottom][index][help] */
  pthread_mutex_lock(&prw_lock->rw_mutex);

  while (prw_lock->rw_count < 0) {
    pthread_cond_wait(&prw_lock->rw_cond, &prw_lock->rw_mutex);
  }

  ++prw_lock->rw_count;
  pthread_mutex_unlock(&prw_lock->rw_mutex);

} /* TH_acquire_read_lock() */

/* TH_release_read_lock() */
/*++++++++++++++++++++++++++++++++++++++

  Release a readers lock.

  rw_lock_t *prw_lock Readers writers lock.

  Reference: "Multithreaded Programming Techniques - Prasad p.192"
  More:
  +html+ <PRE>
  Author:
        ottrey
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_release_read_lock(rw_lock_t *prw_lock) { 
/* [<][>][^][v][top][bottom][index][help] */
  pthread_mutex_lock(&prw_lock->rw_mutex);

  --prw_lock->rw_count;

  if (!prw_lock->rw_count) {
    pthread_cond_signal(&prw_lock->rw_cond);
  }

  pthread_mutex_unlock(&prw_lock->rw_mutex);

} /* TH_release_read_lock() */

/* TH_acquire_write_lock() */
/*++++++++++++++++++++++++++++++++++++++

  Aquire a writers lock.

  rw_lock_t *prw_lock Readers writers lock.

  Reference: "Multithreaded Programming Techniques - Prasad p.192"
  More:
  +html+ <PRE>
  Author:
        ottrey
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_acquire_write_lock(rw_lock_t *prw_lock) { 
/* [<][>][^][v][top][bottom][index][help] */
  pthread_mutex_lock(&prw_lock->rw_mutex);

  while (prw_lock->rw_count != 0) {
    pthread_cond_wait(&prw_lock->rw_cond, &prw_lock->rw_mutex);
  }

  prw_lock->rw_count = -1;
  pthread_mutex_unlock(&prw_lock->rw_mutex);

} /* TH_acquire_write_lock() */

/* TH_release_write_lock() */
/*++++++++++++++++++++++++++++++++++++++

  Release a writers lock.

  rw_lock_t *prw_lock Readers writers lock.

  Reference: "Multithreaded Programming Techniques - Prasad p.192"
  More:
  +html+ <PRE>
  Author:
        ottrey
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_release_write_lock(rw_lock_t *prw_lock) { 
/* [<][>][^][v][top][bottom][index][help] */
  pthread_mutex_lock(&prw_lock->rw_mutex);
  prw_lock->rw_count = 0;
  pthread_mutex_unlock(&prw_lock->rw_mutex);
  pthread_cond_broadcast(&prw_lock->rw_cond);

} /* TH_release_write_lock() */

/* TH_init_read_write_lock() */
/*++++++++++++++++++++++++++++++++++++++

  Initialize a readers/writers lock.

  rw_lock_t *prw_lock Readers writers lock.

  Reference: "Multithreaded Programming Techniques - Prasad p.192"
  More:
  +html+ <PRE>
  Author:
        ottrey
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_init_read_write_lock(rw_lock_t *prw_lock) { 
/* [<][>][^][v][top][bottom][index][help] */
  mutex_init(&prw_lock->rw_mutex, NULL);
  cond_init(&prw_lock->rw_cond, NULL);
  prw_lock->rw_count = 0;

} /* TH_init_read_write_lock() */

int TH_get_id(void) {
/* [<][>][^][v][top][bottom][index][help] */

  return (int)pthread_self();

} /* TH_get_id() */

/* TH_to_string() */
char *TH_to_string(void) {
/* [<][>][^][v][top][bottom][index][help] */
  char *thread_info;
  char tmp[STR_L];
  char thread_info_buffer[STR_XL];
  char *thread_name;

  strcpy(thread_info_buffer, "Thread = { ");

  sprintf(tmp, "[pthread_self] = \"%d\" ", pthread_self());
  strcat(thread_info_buffer, tmp);
  
  /*
  thread_name = (char *)pthread_getspecific(Name);

  if (thread_name == NULL ) {
    sprintf(tmp, "[Name] = \"%s\" ", "didn't work!");
  }
  else {
    sprintf(tmp, "[Name] = \"%s\" ", thread_name);
  }
  strcat(thread_info_buffer, tmp);
  */
  
  strcat(thread_info_buffer, "}");
  
  thread_info = (char *)calloc(1, strlen(thread_info_buffer)+1);
  strcpy(thread_info, thread_info_buffer);

  return thread_info;
} /* TH_to_string() */

/* TH_do_whois() */
/*++++++++++++++++++++++++++++++++++++++

  Handle whois connections.

  void *arg The socket to connect to. (It has to be passed in this way for this thread routine.)

  More:
  +html+ <PRE>
  Author:
        joao
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_do_whois(void *arg) { 
/* [<][>][^][v][top][bottom][index][help] */
  int sock = (int)arg;
  char print_buf[STR_M];

  sprintf(print_buf, "Whois: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, "");

  /* Use a mutex to update the global whois thread counter. */
  pthread_mutex_lock(&Whois_thread_count_lock);
  Whois_thread_count++;
  sprintf(print_buf, "Whois_thread_count++=%d\n", Whois_thread_count); log_print(print_buf); strcpy(print_buf, "");
  pthread_mutex_unlock(&Whois_thread_count_lock);

  PW_interact(sock);

  /* Use a mutex to update the global whois thread counter. */
  pthread_mutex_lock(&Whois_thread_count_lock);
  Whois_thread_count--;
  sprintf(print_buf, "Whois_thread_count--=%d\n", Whois_thread_count); log_print(print_buf); strcpy(print_buf, "");
  pthread_mutex_unlock(&Whois_thread_count_lock);

  pthread_exit((void *)0);

} /* TH_do_whois() */

/* TH_do_config() */
/*++++++++++++++++++++++++++++++++++++++

  Handle config connections.

  void *arg The socket to connect to. (It has to be passed in this way for this
thread routine.)

  More:
  +html+ <PRE>
  Author:
        joao
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_do_config(void *arg) {
/* [<][>][^][v][top][bottom][index][help] */
  int sock = (int)arg;
  char print_buf[STR_M];

  sprintf(print_buf, "Config: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, "");

/*
  printf("Hi there, there is nothing to configure yet\nBye..... :-)\n");
  fflush(NULL);

  SK_close(sock);
*/
  PC_interact(sock);

  pthread_exit((void *)0);

} /* TH_do_config() */

/* main_thread() */
/*++++++++++++++++++++++++++++++++++++++

  Waits for an incoming connection on the and spawns a new thread to handle it.

  void *arg Pointer to a struct containing the socket to talk to the client and
            the function to call depending on the incoming connection.

  More:
  +html+ <PRE>
  Author:
        ottrey
        joao
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
static void  *main_thread(void *arg) {
/* [<][>][^][v][top][bottom][index][help] */
  th_args *args = (th_args *)arg;
  pthread_t tid;
  pthread_attr_t attr;
  int connected_socket;

  while(1) {

    connected_socket = SK_accept_connection(args->sock);

    /* Start a new thread. */

    pthread_attr_init(&attr);    /* initialize attr with default attributes */
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&tid, &attr, (void *(*)(void *))(args->function), (void *)connected_socket); 
  }

} /* main_thread() */

/* TH_run() */
/*++++++++++++++++++++++++++++++++++++++

  This is the routine that creates the main threads. 

  int     sock        The socket to connect to.
  void *  do_function The function to call for each type of service

  More:
  +html+ <PRE>
  Author:
        ottrey
        joao
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
void TH_run(int sock, void *do_function) {
/* [<][>][^][v][top][bottom][index][help] */
  th_args *args;
  pthread_t tid;
  pthread_attr_t attr;
  char print_buf[STR_M];

  int connected_socket;

  args = (th_args *)calloc(1,sizeof(th_args));
  args->function=do_function;
  args->sock=sock;

/*  pthread_mutex_init(&Whois_thread_count_lock,NULL); */

  if ( CO_get_max_threads() == 0 ) {
    sprintf(print_buf, "Running with no threads\n"); log_print(print_buf); strcpy(print_buf, "");
    connected_socket = SK_accept_connection(sock);
    PW_interact(connected_socket);
  }
  else {
    /* Start a new thread. */
    pthread_attr_init(&attr);     /* initialize attr with default attributes */
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&tid, &attr, main_thread, (void *)args);
  }

} /* TH_run() */

/* [<][>][^][v][top][bottom][index][help] */