1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test program that performs producer-consumer style communication through 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * a circular buffer. This test program is a slightly modified version of the 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * test program made available by Miguel Ojeda 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * -- see also http://article.gmane.org/gmane.comp.debugging.valgrind/8782. 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h> 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h> 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h> 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h> 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <time.h> 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h> 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <semaphore.h> 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <fcntl.h> 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "../../config.h" 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** gcc versions 4.1.0 and later have support for atomic builtins. */ 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef HAVE_BUILTIN_ATOMIC 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#error Sorry, but this test program can only be compiled by a compiler that\ 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownhas built-in functions for atomic memory access. 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BUFFER_MAX (2) 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DATA_SEMAPHORE_NAME "cb-data-semaphore" 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define FREE_SEMAPHORE_NAME "cb-free-semaphore" 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef int data_t; 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef struct { 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Counting semaphore representing the number of data items in the buffer. */ 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_t* data; 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Counting semaphore representing the number of free elements. */ 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_t* free; 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Position where a new elements should be written. */ 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int in; 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Position from where an element can be removed. */ 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int out; 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Mutex that protects 'in'. */ 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_t mutex_in; 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Mutex that protects 'out'. */ 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_t mutex_out; 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Data buffer. */ 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown data_t buffer[BUFFER_MAX]; 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} buffer_t; 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int quiet = 0; 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int use_locking = 1; 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic __inline__ 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint fetch_and_add(int* p, int i) 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return __sync_fetch_and_add(p, i); 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic sem_t* create_semaphore(const char* const name, const int value) 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#ifdef VGO_darwin 63b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov char name_and_pid[32]; 64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov snprintf(name_and_pid, sizeof(name_and_pid), "%s-%d", name, getpid()); 65b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov sem_t* p = sem_open(name_and_pid, O_CREAT | O_EXCL, 0600, value); 66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (p == SEM_FAILED) { 67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov perror("sem_open"); 68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return NULL; 69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return p; 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_t* p = malloc(sizeof(*p)); 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p) 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_init(p, 0, value); 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return p; 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void destroy_semaphore(const char* const name, sem_t* p) 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#ifdef VGO_darwin 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_close(p); 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_unlink(name); 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_destroy(p); 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown free(p); 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void buffer_init(buffer_t * b) 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown b->data = create_semaphore(DATA_SEMAPHORE_NAME, 0); 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown b->free = create_semaphore(FREE_SEMAPHORE_NAME, BUFFER_MAX); 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_init(&b->mutex_in, NULL); 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_init(&b->mutex_out, NULL); 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown b->in = 0; 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown b->out = 0; 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void buffer_recv(buffer_t* b, data_t* d) 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int out; 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_wait(b->data); 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (use_locking) 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_lock(&b->mutex_out); 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown out = fetch_and_add(&b->out, 1); 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (out >= BUFFER_MAX) 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fetch_and_add(&b->out, -BUFFER_MAX); 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown out -= BUFFER_MAX; 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *d = b->buffer[out]; 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (use_locking) 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_unlock(&b->mutex_out); 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (! quiet) 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf("received %d from buffer[%d]\n", *d, out); 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fflush(stdout); 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_post(b->free); 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void buffer_send(buffer_t* b, data_t* d) 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int in; 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_wait(b->free); 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (use_locking) 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_lock(&b->mutex_in); 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in = fetch_and_add(&b->in, 1); 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (in >= BUFFER_MAX) 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fetch_and_add(&b->in, -BUFFER_MAX); 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown in -= BUFFER_MAX; 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown b->buffer[in] = *d; 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (use_locking) 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_unlock(&b->mutex_in); 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (! quiet) 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf("sent %d to buffer[%d]\n", *d, in); 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fflush(stdout); 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sem_post(b->data); 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void buffer_destroy(buffer_t* b) 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown destroy_semaphore(DATA_SEMAPHORE_NAME, b->data); 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown destroy_semaphore(FREE_SEMAPHORE_NAME, b->free); 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_destroy(&b->mutex_in); 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_destroy(&b->mutex_out); 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic buffer_t b; 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void producer(int* id) 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buffer_send(&b, id); 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_exit(NULL); 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MAXSLEEP (100 * 1000) 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void consumer(int* id) 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int d; 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown usleep(rand() % MAXSLEEP); 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buffer_recv(&b, &d); 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (! quiet) 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf("%i: %i\n", *id, d); 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fflush(stdout); 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_exit(NULL); 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define THREADS (10) 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int argc, char** argv) 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t producers[THREADS]; 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t consumers[THREADS]; 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int thread_arg[THREADS]; 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int i; 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int optchar; 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ((optchar = getopt(argc, argv, "nq")) != EOF) 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (optchar) 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 'n': 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown use_locking = 0; 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 'q': 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown quiet = 1; 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown srand(time(NULL)); 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buffer_init(&b); 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < THREADS; ++i) 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_arg[i] = i; 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_create(producers + i, NULL, 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void * (*)(void *)) producer, &thread_arg[i]); 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < THREADS; ++i) 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_create(consumers + i, NULL, 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void * (*)(void *)) consumer, &thread_arg[i]); 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < THREADS; ++i) 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_join(producers[i], NULL); 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_join(consumers[i], NULL); 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buffer_destroy(&b); 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 228