severe problems with NGPT 2.0.4

"Dr. Uwe Girlich" <[email protected]>
Newsgroups gmane.linux.ngpt.devel
Message-ID <[email protected]>
Hello!

I just found out, that a new NGPT 2.0.4 library is available. Good! 4 out of my
8 private patch files are gone. Even better.

But my test program (attached) does not work anymore.
I may have posted this simple consumer&producer example already but the fact
is now, that it works with 2.0.3 but not with 2.0.4. I simply set
LD_LIBRARY_PATH to the old (2.0.3) lib directory and all was well.

I started simply 
./pc
which acts as the consumer. It forks 1 producer and establishes a simply
queue. The consumer prints out all received charactes, so a working program
should print lots and lots (without end, you have to press Ctrl-C) of
characters on the screen. All producers (default 1) fill the queue with
random characters. The queue itself is locked with a mutex, both sides wake
the other side up, if it is needed (consumer->producers, when queue is empty,
producers->consumer, when queue is full).

pthread_cond_signal() (-s1) is a bit better than pthread_cond_broadcast() 
(-s0, default) but in the end I often get EAGAIN as result of
pthread_mutex_unlock(). Really strange!

The test was made on a 2 processor machine (PIII 1GHz) with SuSE Linux 8.1 on
the SuSE Linux kernel 2.4.19, which contains (after some requests by me) the
current futex patch. The ngpt test program test_str03 works.

Bye, Uwe

-- 
Dr. Uwe Girlich              email: [email protected]
Philosys Software GmbH       www: www.philosys.de
Edisonstrasse 6              phone: +49 89 321407-44
D-85716 Unterschleissheim    fax: +49 89 321407-12
pc.c (text/plain, 6.6 KB)
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifndef BSIZE
#define BSIZE 10
#endif

typedef struct {
	char buf[BSIZE];
	int occupied;
	int nextin;
	int nextout;
	pthread_mutex_t		mutex;
	pthread_cond_t		more;
	pthread_cond_t		less;
} buffer_t;

void producer_driver(buffer_t *b);
void consumer_driver(buffer_t *b);

int	opt_use_signal		= 0;
int	opt_use_keys		= 0;
int	opt_num_producer	= 1;

#define error_check(x) if (error != 0) { \
	int	myerrno = errno; \
	fprintf(stderr,"pid %d file %s line %d\n%s()=%d, errno=%d, %s\n", \
		getpid(), __FILE__, __LINE__, \
		x, error, myerrno, strerror(myerrno)); \
	abort(); \
}


void
usage(char *progname)
{
	fprintf(stderr,"%s: Producer+Consumer example\n", progname);
	fprintf(stderr,"-s<num>\tuse signal (num!=0) or broadcast (default)\n");
	fprintf(stderr,"-k<num>\tuse keyboard (num!=0) or self-made input (default)\n");
	fprintf(stderr,"-p<num>\tuse num producers (default 1)\n");
	fprintf(stderr,"-h\tthis help\n");
	exit(1);
}

int
main(int argc, char **argv) {
	buffer_t		*buffer;
	pthread_mutexattr_t	mattr;
	pthread_condattr_t	cvattr_less, cvattr_more;
	int			error;
	int			c;
	int			i;
	int			buffer_id;

	while ((c = getopt(argc, argv, "s:k:p:h")) != -1) {
		switch (c) {
			case 's':
				opt_use_signal = atoi(optarg);
			break;
			case 'k':
				opt_use_keys = atoi(optarg);
			break;
			case 'p':
				opt_num_producer = atoi(optarg);
			break;
			case 'h':
				usage(argv[0]);
			break;
			case ':':
				fprintf(stderr,"Option -%c requires an operand\n", optopt);
				usage(argv[0]);
			break;
			case '?':
				fprintf(stderr, "Unrecognized option: -%c\n", optopt);
				usage(argv[0]);
			break;
		}
	}
	fprintf(stderr,"use signal: %s\n", opt_use_signal ? "yes" : "no");
	fprintf(stderr,"use keys  : %s\n", opt_use_keys   ? "yes" : "no");
	fprintf(stderr,"#producers: %d\n", opt_num_producer);

	fprintf(stderr,"init...\n");

	if ((buffer_id=shmget(IPC_PRIVATE, sizeof(buffer_t),
		IPC_CREAT | S_IRUSR | S_IWUSR))==-1) {
		perror("shmget");
		exit(1);
	}
	if ((buffer=(buffer_t*)shmat(buffer_id,0,0)) == (buffer_t*)-1) {
		perror("shmat");
		exit(1);
	}
	if (shmctl(buffer_id,IPC_RMID,(struct shmid_ds*) 0) == -1) {
		perror("shmctl (remove shm)");
		exit(1);
	}
	buffer->occupied = buffer->nextin = buffer->nextout = 0;

	/* Mutex */
	fprintf(stderr,"pthread_mutexattr_init\n");
	error = pthread_mutexattr_init(&mattr);
	error_check("pthread_mutexattr_init");

	fprintf(stderr,"pthread_mutexattr_setpshared\n");
	error = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
	error_check("pthread_mutexattr_setpshared");

	fprintf(stderr,"pthread_mutex_init\n");
	error = pthread_mutex_init(&buffer->mutex, &mattr);
	error_check("pthread_mutex_init");

	/* cond var 1 */
	fprintf(stderr,"pthread_condattr_init(less)\n") ;
	error = pthread_condattr_init(&cvattr_less);
	error_check("pthread_condattr_init");

	fprintf(stderr,"pthread_condattr_setpshared(less)\n");
	error = pthread_condattr_setpshared(&cvattr_less, PTHREAD_PROCESS_SHARED);
	error_check("pthread_condattr_setpshared");

	fprintf(stderr,"pthread_cond_init(less)\n");
	error = pthread_cond_init(&buffer->less, &cvattr_less);
	error_check("pthread_cond_init");

	/* cond var 2 */
	fprintf(stderr,"pthread_condattr_init(more)\n");
	error = pthread_condattr_init(&cvattr_more);
	error_check("pthread_condattr_init");

	fprintf(stderr,"pthread_condattr_setpshared(more)\n");
	error = pthread_condattr_setpshared(&cvattr_more, PTHREAD_PROCESS_SHARED);
	error_check("pthread_condattr_setpshared");

	fprintf(stderr,"pthread_cond_init(more)\n");
	error = pthread_cond_init(&buffer->more, &cvattr_more);
	error_check("pthread_cond_init");

	fprintf(stderr,"init finished\n");

	/* make sure the childs don't use too much CPU yet */
	error = pthread_mutex_lock(&buffer->mutex);
	error_check("pthread_mutex_lock");

	for (i=0;i<opt_num_producer;i++) {
		pid_t	pid;

		pid = fork();
		switch(pid) {
			case 0: /* child */
				producer_driver(buffer);
				exit(0);
			break;
			case -1: /* error */
				perror("could not fork()");
				exit(1);
			break;
			default: /* parent */
				/* do nothing */
			break;
		}
	}

	/* enable all the waiting childs */
	error = pthread_mutex_unlock(&buffer->mutex);
	error_check("pthread_mutex_unlock");

	consumer_driver(buffer);

	return(0);
}

void producer(buffer_t *b, char item)
{
	int	error = 0;

	error = pthread_mutex_lock(&b->mutex);
	error_check("pthread_mutex_lock");

	while (b->occupied >= BSIZE) {
		error = pthread_cond_wait(&b->less, &b->mutex);
		error_check("pthread_cond_wait");
	}

	assert(b->occupied < BSIZE);

	b->buf[b->nextin++] = item;

	b->nextin %= BSIZE;
	b->occupied++;

	/* now: either b->occupied < BSIZE and b->nextin is the index
	of the next empty slot in the buffer, or
	b->occupied == BSIZE and b->nextin is the index of the
	next (occupied) slot that will be emptied by a consumer
	(such as b->nextin == b->nextout) */

	if (opt_use_signal) {
		error = pthread_cond_signal(&b->more);
		error_check("pthread_cond_signal");
	}
	else {
		error = pthread_cond_broadcast(&b->more);
		error_check("pthread_cond_broadcast");
	}

	error = pthread_mutex_unlock(&b->mutex);
	error_check("pthread_mutex_unlock");
}

void producer_driver(buffer_t *b)
{
	int item;

	fprintf(stderr,"producer: pid=%d\n", getpid());

	while (1) {
		if (opt_use_keys) {
			item = getchar();
		}
		else {
			item = 32 + rand() % 64;
		}
		producer(b, (char)item);
	}
}

char consumer(buffer_t *b)
{
	int	error;
	char	item;

	error = pthread_mutex_lock(&b->mutex);
	error_check("pthread_mutex_lock");

	while(b->occupied <= 0) {
		error = pthread_cond_wait(&b->more, &b->mutex);
		error_check("pthread_cond_wait");
	}

	assert(b->occupied > 0);

	item = b->buf[b->nextout++];
	b->nextout %= BSIZE;
	b->occupied--;

	/* now: either b->occupied > 0 and b->nextout is the index
	of the next occupied slot in the buffer, or
	b->occupied == 0 and b->nextout is the index of the next
	(empty) slot that will be filled by a producer (such as
	b->nextout == b->nextin) */

	if (opt_use_signal) {
		error = pthread_cond_signal(&b->less);
		error_check("pthread_cond_signal");
	}
	else {
		error = pthread_cond_broadcast(&b->less);
		error_check("pthread_cond_broadcast");
	}

	error = pthread_mutex_unlock(&b->mutex);
	error_check("pthread_mutex_unlock");

	return(item);
}

void consumer_driver(buffer_t *b)
{
	char item;

	fprintf(stderr,"consumer: pid=%d\n", getpid());

	while (1) {
		if ((item = consumer(b)) == '\0')
			break;
		putchar(item);
		fflush(stdout);
	}
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.