Real World Example
#include <pthreadutil.h>
#include <sys/param.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void *netfinger();
void usage(int eval)
{
fprintf(stderr,
"usage: finger [-lps] [-c ] [-t|T ] [-f ] [login ...]\n");
exit(eval);
}
/*
* These globals are set initialy and then are only read.
* They do not need mutexes.
*/
int thread_time = 0, program_timeout = 0, lflag = 0;
pthread_tad_t parse_file_tad;
pthread_tad_t netfinger_tad;
void * timeout_thread(void * arg)
{
sleep(program_timeout);
exit(0);
}
void * parse_file(void * arg)
{
char hostname[MAXHOSTNAMELEN];
char * filename = arg;
pthread_atexit_t atexit_id;
pthread_attr_t attr;
pthread_t thread_id;
char * thread_arg;
FILE * fp;
int len;
netsetupwait();
/* Parse the file and create a thread per connection */
if ((fp = fopen(filename, "r")) == NULL) {
fprintf(stderr, "Can't open file %s\n", filename);
pthread_exit(NULL);
}
pthread_cleanup_push(fclose, fp);
if (pthread_attr_init(&attr)) {
fprintf(stderr, "Error: Can't initialize thread attributes\n");
exit(2);
}
pthread_cleanup_push(pthread_attr_destroy, &attr);
while (fgets(hostname, MAXHOSTNAMELEN, fp)) {
if ((thread_arg = (char *)malloc(len = strlen(hostname))) == NULL) {
fprintf(stderr, "Error: out of memory\n");
exit(2);
}
hostname[len - 1] = '\0';
strcpy(thread_arg, hostname);
pthread_attr_setcleanup(&attr, free, thread_arg);
if (pthread_tad_create(&netfinger_tad, &thread_id, NULL,
netfinger, thread_arg)) {
fprintf(stderr, "Error: pthread_tad_create() netfinger_tad.\n");
exit(2);
}
}
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_exit(NULL);
}
main(int argc, char **argv)
{
pthread_atexit_t atexit_id;
pthread_t thread_id;
int max_count = 0;
char ch;
/* getopt variables */
extern char *optarg;
extern int optind;
/* Setup tad for parse_file() threads */
if (pthread_tad_init(&parse_file_tad, max_count)) {
fprintf(stderr,"Error: couldn't create parse_file() TAD.\n");
exit(1);
}
while ((ch = getopt(argc, argv, "c:f:t:T:ls")) != (char)EOF)
switch(ch) {
case 't': /* Time to let each thread run */
if ((thread_time = atoi(optarg)) <= 0) {
usage(1);
}
break;
case 'T': /* Time to let entire program run */
if ((program_timeout = atoi(optarg)) <= 0) {
usage(1);
}
break;
case 'f': /* Parse file for list of places to finger */
if (pthread_tad_create(&parse_file_tad, &thread_id, NULL,
parse_file, optarg)) {
fprintf(stderr,"Error: pthread_tad_create() parse_file_tad.\n");
exit(1);
}
break;
case 'c':
max_count = atoi(optarg);
break;
case 'l': /* long format */
lflag = 1;
break;
case 's': /* short format */
lflag = 0;
break;
case '?':
usage(0);
default:
usage(1);
}
/* The rest of the argumants are hosts */
argc -= optind;
argv += optind;
/* Setup timeout thread, if there is one */
if (program_timeout) {
if (pthread_create(&thread_id, NULL, timeout_thread, NULL)) {
fprintf(stderr,"Error: couldn't create program_timeout() thread\n");
exit(1);
}
}
/* Setup tad for netfinger() threads */
if (pthread_tad_init(&netfinger_tad, max_count)) {
fprintf(stderr,"Error: couldn't create netfinger() TAD.\n");
exit(1);
}
/* Setup the net and let everyone run */
netsetup();
while (*argv) {
if (pthread_tad_create(&netfinger_tad, &thread_id, NULL,
netfinger, *argv)) {
fprintf(stderr, "Error: pthread_tad_create() netfinger_tad.\n");
exit(2);
}
argv++;
}
pthread_tad_wait(&parse_file_tad, 0);
pthread_tad_wait(&netfinger_tad, 0);
exit(0);
}