1 /*
2  * Copyright (c) 2002, Intel Corporation. All rights reserved.
3  * Created by:  crystal.xiong REMOVE-THIS AT intel DOT com
4  * This file is licensed under the GPL license.  For the full content
5  * of this license, see the COPYING file at the top level of this
6  * source tree.
7  *
8  * This is a test about multiple producers and consumers. Producers send data
9  * to a buffer. Consumers keeps reading data from the buffer.
10  */
11 
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <sys/wait.h>
17 #include <sys/mman.h>
18 #include <string.h>
19 #include <getopt.h>
20 #include <errno.h>
21 #include <pthread.h>
22 
23 #include <semaphore.h>
24 #include "posixtest.h"
25 
26 #define BUF_SIZE	5
27 #define Max_Num		5
28 #define Max_Threads	127
29 
30 typedef struct {
31 	int buffer[BUF_SIZE];
32 	sem_t full;
33 	sem_t empty;
34 	sem_t lock;
35 }buf_t;
36 
37 buf_t *buf;
38 int in, out;
39 
producer(void * ID)40 int *producer(void *ID)
41 {
42 	int data;
43 	int i;
44 	int ThreadID = *(int *)ID;
45 	int full_value;
46 
47 	printf("Enter into Producer Thread %d... \n", ThreadID);
48 	for (i = 0; i< Max_Num - 1; i++) {
49 		if (-1 == sem_wait(&buf->full)) {
50 			perror("sem_wait didn't return success \n");
51 			pthread_exit((void *)1);
52 		}
53 		if (-1 == sem_getvalue(&buf->full, &full_value)) {
54 			perror("sem_getvalue didn't return success \n");
55 			pthread_exit((void *)1);
56 		}
57 		printf("The value of the full semaphore is %d \n", full_value);
58 		if (-1 == sem_wait(&buf->lock)) {
59 			perror("sem_wait didn't return success \n");
60 			pthread_exit((void *)1);
61 		}
62 		data = 100*ThreadID + i;
63 		buf->buffer[in] = data;
64 		printf("[%d] producer has added %d to the buffer[%d] \n", ThreadID, data, in);
65 		in = (in + 1) % BUF_SIZE;
66 		if (-1 == sem_post(&buf->lock)) {
67 			perror("sem_wait didn't return success \n");
68 			pthread_exit((void *)1);
69 		}
70 		if (-1 == sem_post(&buf->empty)) {
71 			perror("sem_wait didn't return success \n");
72 			pthread_exit((void *)1);
73 		}
74 	}
75 	if (-1 == sem_wait(&buf->full)) {
76 		perror("sem_wait didn't return success \n");
77 		pthread_exit((void *)1);
78 	}
79 	if (-1 == sem_getvalue(&buf->full, &full_value)) {
80 		perror("sem_getvalue didn't return success \n");
81 		pthread_exit((void *)1);
82 	}
83 	printf("The value of the full is %d \n", full_value);
84 	if (-1 == sem_wait(&buf->lock)) {
85 		perror("sem_wait didn't return success \n");
86 		pthread_exit((void *)1);
87 	}
88 	data = -1;
89 	buf->buffer[in] = data;
90 	printf("[%d] producer has added %d to the buffer[%d] \n", ThreadID, data, in);
91 	in = (in + 1) % BUF_SIZE;
92 	if (-1 == sem_post(&buf->lock)) {
93 		perror("sem_wait didn't return success \n");
94 		pthread_exit((void *)1);
95 	}
96 	if (-1 == sem_post(&buf->empty)) {
97 		perror("sem_wait didn't return success \n");
98 		pthread_exit((void *)1);
99 	}
100 	printf("Producer %d exit... \n", ThreadID);
101 	pthread_exit((void *)0);
102 }
consumer(void * ID)103 int *consumer(void *ID)
104 {
105 	int data;
106 	int ThreadID = *(int *)ID;
107 	int full_value;
108 
109 	printf("Enter into Consumer Thread %d... \n", ThreadID);
110 	do
111 	{
112 		if (-1 == sem_wait(&buf->empty)) {
113 			perror("sem_wait didn't return success \n");
114 			pthread_exit((void *)1);
115 		}
116 		if (-1 == sem_wait(&buf->lock)) {
117 			perror("sem_wait didn't return success \n");
118 			pthread_exit((void *)1);
119 		}
120 		data = buf->buffer[out];
121 		printf("[%d] consumer has taken %d from buffer[%d] \n", ThreadID, data, out);
122 		out = (out + 1) % BUF_SIZE;
123 		if (-1 == sem_post(&buf->lock)) {
124 			perror("sem_wait didn't return success \n");
125 			pthread_exit((void *)1);
126 		}
127 		if (-1 == sem_post(&buf->full)) {
128 			perror("sem_wait didn't return success \n");
129 			pthread_exit((void *)1);
130 		}
131 		if (-1 == sem_getvalue(&buf->full, &full_value)) {
132 			perror("sem_getvalue didn't return success \n");
133 			pthread_exit((void *)1);
134 		}
135 		printf("The value of the full semaphore is %d \n", full_value);
136 	}
137 	while (data != -1);
138 
139 	printf("Consumer %d exit... \n", ThreadID);
140 	pthread_exit((void *)0);
141 }
main(int argc,char * argv[])142 int main(int argc, char *argv[])
143 {
144 	int shared = 1;
145 	int full_value = BUF_SIZE;
146 	int empty_value = 0;
147 	int lock_value=1;
148 	int num;
149 	int i;
150 	pthread_t con[Max_Threads], pro[Max_Threads];
151 	int ThreadID[Max_Threads];
152 
153 
154 #ifndef	_POSIX_SEMAPHORES
155 	printf("_POSIX_SEMAPHORES is not defined \n");
156 	return PTS_UNRESOLVED;
157 #endif
158 
159 	buf = (buf_t *)malloc(sizeof(buf_t));
160 
161 	if ( (2 != argc) || (( num = atoi(argv[1])) <= 0)) {
162 		fprintf(stderr, "Usage: %s number_of_threads\n", argv[0]);
163                 return PTS_FAIL;
164         }
165 	if (num > Max_Threads) {
166         	printf("The num of producers/consumers threads are too large.  Reset to %d\n", Max_Threads);
167         	num = Max_Threads;
168 	}
169 
170 	if (-1 == sem_init(&buf->full, shared, full_value)) {
171 		perror("sem_init didn't return success \n");
172 		return PTS_UNRESOLVED;
173 	}
174 	if (-1 == sem_getvalue(&buf->full, &full_value)) {
175 		perror("sem_getvalue didn't return success \n");
176 		return PTS_UNRESOLVED;
177 	}
178 	printf("The initial value of the full semaphore is %d \n", full_value);
179 	if (-1 == sem_init(&buf->empty, shared, empty_value)) {
180 		perror("sem_init didn't return success \n");
181 		return PTS_UNRESOLVED;
182 	}
183 	if (-1 == sem_init(&buf->lock, shared, lock_value)) {
184 		perror("sem_init didn't return success \n");
185 		return PTS_UNRESOLVED;
186 	}
187 	in = out = 0;
188 
189 	for (i = 0; i < num; i++) {
190 		ThreadID[i] = i;
191 		pthread_create(&con[i], NULL, (void *)consumer, (void *)&ThreadID[i]);
192 	}
193 	for (i = 0; i < num; i++) {
194 		ThreadID[i] = i;
195 		pthread_create(&pro[i], NULL, (void *)producer, (void *)&ThreadID[i]);
196 	}
197 	for (i = 0; i < num; i++)
198 		pthread_join(con[i], NULL);
199 	for (i = 0; i < num; i++)
200 		pthread_join(pro[i], NULL);
201 
202 	sem_destroy(&buf->full);
203 	sem_destroy(&buf->empty);
204 	sem_destroy(&buf->lock);
205 	return PTS_PASS;
206 }
207