#include <pthread.h>
BM_PATTERN *bm_pat;		/* the global target read only after main */
PATTERN *pm_pat[MAXREGEXP];	/* global targets read only for pmatch */
void pthread_setconcurrency_np (int con);
int pthread_getconcurrency_np (void);
void pthread_yield_np (void);
/*pthread_attr_t detached_attr; @@ */
pthread_mutex_t output_print_lk;
pthread_mutex_t global_count_lk;
pthread_cond_t work_q_cv;
pthread_mutex_t work_q_lk;
pthread_mutex_t debug_lock;
pthread_mutex_t search_q_lk;
pthread_cond_t search_q_cv;
pthread_mutex_t cascade_q_lk;
pthread_cond_t cascade_q_cv;
pthread_mutex_t running_lk;
pthread_mutex_t stat_lk;
				   threads */
  pthread_t tid;
	  /* locklint complains here, but there are no other threads */
  pthread_attr_init (&detached_attr);
  pthread_attr_setdetachstate (&detached_attr,
  pthread_mutex_init (&global_count_lk, NULL);
  pthread_mutex_init (&output_print_lk, NULL);
  pthread_mutex_init (&work_q_lk, NULL);
  pthread_mutex_init (&running_lk, NULL);
  pthread_cond_init (&work_q_cv, NULL);
  pthread_mutex_init (&search_q_lk, NULL);
  pthread_cond_init (&search_q_cv, NULL);
  pthread_mutex_init (&cascade_q_lk, NULL);
  pthread_cond_init (&cascade_q_cv, NULL);
  pthread_setconcurrency_np (3);
	  pthread_mutex_lock (&global_count_lk);
	  pthread_mutex_unlock (&global_count_lk);
  pthread_mutex_lock (&work_q_lk);
  pthread_mutex_unlock (&work_q_lk);
      pthread_mutex_lock (&work_q_lk);
	      pthread_mutex_lock (&stat_lk);
	      pthread_mutex_unlock (&stat_lk);
	  pthread_cond_wait (&work_q_cv, &work_q_lk);
	  pthread_mutex_unlock (&work_q_lk);
      pthread_mutex_unlock (&work_q_lk);
	  pthread_mutex_lock (&cascade_q_lk);
		  pthread_mutex_lock (&stat_lk);
		  pthread_mutex_unlock (&stat_lk);
	      pthread_cond_signal (&cascade_q_cv);
	      pthread_mutex_unlock (&cascade_q_lk);
	      DP (DLEVEL2, ("Sent work to cascade pool thread\n"));
	      pthread_mutex_unlock (&cascade_q_lk);
	      err = pthread_create (&tid, NULL, cascade, (void *) work);
	      DP (DLEVEL2, ("Sent work to new cascade thread\n"));
		  pthread_mutex_lock (&stat_lk);
		  pthread_mutex_unlock (&stat_lk);
	  pthread_mutex_lock (&search_q_lk);
		  pthread_mutex_lock (&stat_lk);
		  pthread_mutex_unlock (&stat_lk);
	      pthread_cond_signal (&search_q_cv);
	      pthread_mutex_unlock (&search_q_lk);
	      DP (DLEVEL2, ("Sent work to search pool thread\n"));
	      pthread_mutex_unlock (&search_q_lk);
	      err = pthread_create (&tid, NULL,
	      pthread_setconcurrency_np (pthread_getconcurrency_np () + 1);
	      DP (DLEVEL2, ("Sent work to new search thread\n"));
		  pthread_mutex_lock (&stat_lk);
		  pthread_mutex_unlock (&stat_lk);
	  fprintf_r (stderr, "Could not create new thread!\n");
  /* we are done, print the stuff. All other threads ar parked */
      pthread_mutex_lock (&global_count_lk);
      pthread_mutex_unlock (&global_count_lk);
 * Add_Work: Called from the main thread, and cascade threads to add file 
      pthread_mutex_lock (&stat_lk);
      pthread_mutex_unlock (&stat_lk);
  pthread_mutex_lock (&work_q_lk);
  pthread_cond_signal (&work_q_cv);
  pthread_mutex_unlock (&work_q_lk);
 * Search thread: Started by the main thread when a file name is found
 * on the work Q to be serached. If all the needed resources are ready
 * a new search thread will be created.
  out_t *out = NULL;		/* this threads output list */
  pthread_yield( NULL );
    {				/* reuse the search threads */
      pthread_mutex_lock (&running_lk);
      pthread_mutex_unlock (&running_lk);
      pthread_mutex_lock (&work_q_lk);
      pthread_mutex_unlock (&work_q_lk);
      DP (DLEVEL5, ("Search thread has opened file %s\n", wt->path));
	      pthread_mutex_lock (&stat_lk);
	      pthread_mutex_unlock (&stat_lk);
	     ** If the uncase flag is set, copy the read in line (rline)
         ** and park this thread in the search thread pool, print the
      pthread_mutex_lock (&search_q_lk);
	  pthread_mutex_unlock (&search_q_lk);
	  DP (DLEVEL5, ("Search thread exiting\n"));
	      pthread_mutex_lock (&stat_lk);
	      pthread_mutex_unlock (&stat_lk);
	    pthread_cond_wait (&search_q_cv, &search_q_lk);
	  pthread_mutex_unlock (&search_q_lk);
 * cascade: This thread is started by the main thread when directory names
 * are found on the work Q. The thread reads all the new file, and directory
  pthread_yield( NULL );		/* try toi give control back to main thread */
      pthread_mutex_lock (&running_lk);
      pthread_mutex_unlock (&running_lk);
      pthread_mutex_lock (&work_q_lk);
      pthread_mutex_unlock (&work_q_lk);
      while((dent = readdir_r (dp)) != NULL)
      pthread_mutex_lock (&cascade_q_lk);
	  pthread_mutex_unlock (&cascade_q_lk);
	  DP (DLEVEL5, ("Cascade thread exiting\n"));
	      pthread_mutex_lock (&stat_lk);
	      pthread_mutex_unlock (&stat_lk);
	  return (0);		/* pthread_exit */
	  DP (DLEVEL5, ("Cascade thread waiting in pool\n"));
	    pthread_cond_wait (&cascade_q_cv, &cascade_q_lk);
	  pthread_mutex_unlock (&cascade_q_lk);
 * Print Local Output: Called by the search thread after it is done searching
  pthread_mutex_lock (&output_print_lk);
  pthread_mutex_unlock (&output_print_lk);
  pthread_mutex_lock (&global_count_lk);
  pthread_mutex_unlock (&global_count_lk);
 * add output local: is called by a search thread as it finds matching lines. 
 * search thread is done searching the file, then the lines are printed as 
 * main thread calls this function to print the stats it keeps on how the
  printf_r ("Number of cascade threads created:        %d\n", st_cascade);
  printf_r ("Number of cascade threads from pool:      %d\n", st_cascade_pool);
  printf_r ("Cascade thread pool hit rate:             %3.2f%%\n", ((a / b) * 100));
  printf_r ("Number of cascade threads destroyed:      %d\n", st_cascade_destroy);
  printf_r ("Number of search threads created:         %d\n", st_search);
  printf_r ("Number of search threads from pool:       %d\n", st_pool);
  printf_r ("Search thread pool hit rate:              %3.2f%%\n", ((a / b) * 100));
  printf_r ("Number of search threads destroyed:       %d\n", st_destroy);
  printf_r ("Max # of threads running concurrenly:     %d\n", st_maxrun);
    pthread_lock_global_np();
    pthread_unlock_global_np();
 * not running: A glue function to track if any search threads or cascade 
 * threads are running. When the count is zero, and the work Q is NULL,
  pthread_mutex_lock (&work_q_lk);
  pthread_mutex_lock (&running_lk);
      pthread_mutex_lock (&stat_lk);
      pthread_mutex_unlock (&stat_lk);
  pthread_mutex_unlock (&running_lk);
  pthread_cond_signal (&work_q_cv);
  pthread_mutex_unlock (&work_q_lk);
 * target strng and the read in line is converted to lower case before
   pthread_lock_global_np();
  fprintf (stderr, "          -B = limit the number of threads to TGLIMIT\n");
  fprintf (stderr, "          -S = Print thread stats when done.\n");
   pthread_unlock_global_np();
   pthread_lock_global_np();
   pthread_unlock_global_np();
 * how to get tgrep to print debug info on different threads.
   pthread_lock_global_np();
   pthread_unlock_global_np();
/* Pthreads NP functions */
pthread_setconcurrency_np (int con)
pthread_getconcurrency_np (void)
pthread_yield_np (void)
pthread_setconcurrency_np (int con)
pthread_getconcurrency_np (void)
pthread_yield_np (void)
