Real World Example


Multi-Threaded Finger


#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);
}


[TOP] [BACK] [FORWARD]


Prepared by Chris Provenzano (proven@mit.edu)