circular_buffer.c revision d759a835bd647cc543c41cd349aefb181dac5868
16fd7d7488898e93aceabca60366166e679af9fd7bart/* Test program that performs producer-consumer style communication through 26fd7d7488898e93aceabca60366166e679af9fd7bart * a circular buffer. This test program is a slightly modified version of the 36fd7d7488898e93aceabca60366166e679af9fd7bart * test program made available by Miguel Ojeda 46fd7d7488898e93aceabca60366166e679af9fd7bart * -- see also http://article.gmane.org/gmane.comp.debugging.valgrind/8782. 56fd7d7488898e93aceabca60366166e679af9fd7bart */ 66fd7d7488898e93aceabca60366166e679af9fd7bart 76fd7d7488898e93aceabca60366166e679af9fd7bart 86fd7d7488898e93aceabca60366166e679af9fd7bart#include <stdio.h> 96fd7d7488898e93aceabca60366166e679af9fd7bart#include <string.h> 106fd7d7488898e93aceabca60366166e679af9fd7bart#include <stdlib.h> 116fd7d7488898e93aceabca60366166e679af9fd7bart#include <unistd.h> 126fd7d7488898e93aceabca60366166e679af9fd7bart#include <time.h> 136fd7d7488898e93aceabca60366166e679af9fd7bart#include <pthread.h> 146fd7d7488898e93aceabca60366166e679af9fd7bart#include <semaphore.h> 15d759a835bd647cc543c41cd349aefb181dac5868tom#include <fcntl.h> 16d94169a1f0259e2da5e6873d205e355248c3a550bart#include "../../config.h" 17d94169a1f0259e2da5e6873d205e355248c3a550bart 18d94169a1f0259e2da5e6873d205e355248c3a550bart 19d94169a1f0259e2da5e6873d205e355248c3a550bart/** gcc versions 4.1.0 and later have support for atomic builtins. */ 20d45d99553c15a361bb797d21ec6afb9bad22d2d4bart 21d45d99553c15a361bb797d21ec6afb9bad22d2d4bart#ifndef HAVE_BUILTIN_ATOMIC 22d45d99553c15a361bb797d21ec6afb9bad22d2d4bart#error Sorry, but this test program can only be compiled by a compiler that\ 23d45d99553c15a361bb797d21ec6afb9bad22d2d4barthas built-in functions for atomic memory access. 24d45d99553c15a361bb797d21ec6afb9bad22d2d4bart#endif 25d94169a1f0259e2da5e6873d205e355248c3a550bart 266fd7d7488898e93aceabca60366166e679af9fd7bart 276fd7d7488898e93aceabca60366166e679af9fd7bart#define BUFFER_MAX (2) 286e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#define DATA_SEMAPHORE_NAME "cb-data-semaphore" 296e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#define FREE_SEMAPHORE_NAME "cb-free-semaphore" 306fd7d7488898e93aceabca60366166e679af9fd7bart 31d94169a1f0259e2da5e6873d205e355248c3a550bart 326fd7d7488898e93aceabca60366166e679af9fd7barttypedef int data_t; 336fd7d7488898e93aceabca60366166e679af9fd7bart 346fd7d7488898e93aceabca60366166e679af9fd7barttypedef struct { 356fd7d7488898e93aceabca60366166e679af9fd7bart /* Counting semaphore representing the number of data items in the buffer. */ 366e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_t* data; 376fd7d7488898e93aceabca60366166e679af9fd7bart /* Counting semaphore representing the number of free elements. */ 386e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_t* free; 396fd7d7488898e93aceabca60366166e679af9fd7bart /* Position where a new elements should be written. */ 40d94169a1f0259e2da5e6873d205e355248c3a550bart int in; 416fd7d7488898e93aceabca60366166e679af9fd7bart /* Position from where an element can be removed. */ 42d94169a1f0259e2da5e6873d205e355248c3a550bart int out; 436fd7d7488898e93aceabca60366166e679af9fd7bart /* Mutex that protects 'in'. */ 446fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_t mutex_in; 456fd7d7488898e93aceabca60366166e679af9fd7bart /* Mutex that protects 'out'. */ 466fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_t mutex_out; 476fd7d7488898e93aceabca60366166e679af9fd7bart /* Data buffer. */ 486fd7d7488898e93aceabca60366166e679af9fd7bart data_t buffer[BUFFER_MAX]; 496fd7d7488898e93aceabca60366166e679af9fd7bart} buffer_t; 506fd7d7488898e93aceabca60366166e679af9fd7bart 516fd7d7488898e93aceabca60366166e679af9fd7bartstatic int quiet = 0; 5203225a834a0dd72d96afd20c6d8188450dd08726bartstatic int use_locking = 1; 536fd7d7488898e93aceabca60366166e679af9fd7bart 54d94169a1f0259e2da5e6873d205e355248c3a550bartstatic __inline__ 55d94169a1f0259e2da5e6873d205e355248c3a550bartint fetch_and_add(int* p, int i) 56d94169a1f0259e2da5e6873d205e355248c3a550bart{ 57d94169a1f0259e2da5e6873d205e355248c3a550bart return __sync_fetch_and_add(p, i); 58d94169a1f0259e2da5e6873d205e355248c3a550bart} 59d94169a1f0259e2da5e6873d205e355248c3a550bart 606e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic sem_t* create_semaphore(const char* const name, const int value) 616fd7d7488898e93aceabca60366166e679af9fd7bart{ 620ccdc4a1e148ce89d99a4593b777c0fd9192bce0bart#ifndef HAVE_SEM_INIT 636e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_t* p = sem_open(name, O_CREAT, 0600, value); 646e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart return p; 656e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#else 666e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_t* p = malloc(sizeof(*p)); 676e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart if (p) 686e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_init(p, 0, value); 696e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart return p; 706e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#endif 716e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart} 726e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart 736e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void destroy_semaphore(const char* const name, sem_t* p) 746e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart{ 750ccdc4a1e148ce89d99a4593b777c0fd9192bce0bart#ifndef HAVE_SEM_INIT 766e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_close(p); 776e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_unlink(name); 786e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#else 796e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_destroy(p); 806e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart free(p); 816e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#endif 826e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart} 836e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart 846e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_init(buffer_t * b) 856e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart{ 866e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart b->data = create_semaphore(DATA_SEMAPHORE_NAME, 0); 876e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart b->free = create_semaphore(FREE_SEMAPHORE_NAME, BUFFER_MAX); 886fd7d7488898e93aceabca60366166e679af9fd7bart 896fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_init(&b->mutex_in, NULL); 906fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_init(&b->mutex_out, NULL); 916fd7d7488898e93aceabca60366166e679af9fd7bart 926fd7d7488898e93aceabca60366166e679af9fd7bart b->in = 0; 936fd7d7488898e93aceabca60366166e679af9fd7bart b->out = 0; 946fd7d7488898e93aceabca60366166e679af9fd7bart} 956fd7d7488898e93aceabca60366166e679af9fd7bart 966e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_recv(buffer_t* b, data_t* d) 976fd7d7488898e93aceabca60366166e679af9fd7bart{ 98d94169a1f0259e2da5e6873d205e355248c3a550bart int out; 996e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_wait(b->data); 10003225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 10103225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_lock(&b->mutex_out); 102d94169a1f0259e2da5e6873d205e355248c3a550bart out = fetch_and_add(&b->out, 1); 103d94169a1f0259e2da5e6873d205e355248c3a550bart if (out >= BUFFER_MAX) 104d94169a1f0259e2da5e6873d205e355248c3a550bart { 105d94169a1f0259e2da5e6873d205e355248c3a550bart fetch_and_add(&b->out, -BUFFER_MAX); 106d94169a1f0259e2da5e6873d205e355248c3a550bart out -= BUFFER_MAX; 107d94169a1f0259e2da5e6873d205e355248c3a550bart } 108d94169a1f0259e2da5e6873d205e355248c3a550bart *d = b->buffer[out]; 10903225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 11003225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_unlock(&b->mutex_out); 111d94169a1f0259e2da5e6873d205e355248c3a550bart if (! quiet) 112d94169a1f0259e2da5e6873d205e355248c3a550bart { 113d94169a1f0259e2da5e6873d205e355248c3a550bart printf("received %d from buffer[%d]\n", *d, out); 114d94169a1f0259e2da5e6873d205e355248c3a550bart fflush(stdout); 115d94169a1f0259e2da5e6873d205e355248c3a550bart } 1166e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_post(b->free); 1176fd7d7488898e93aceabca60366166e679af9fd7bart} 1186fd7d7488898e93aceabca60366166e679af9fd7bart 1196e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_send(buffer_t* b, data_t* d) 1206fd7d7488898e93aceabca60366166e679af9fd7bart{ 121d94169a1f0259e2da5e6873d205e355248c3a550bart int in; 1226e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_wait(b->free); 12303225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 12403225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_lock(&b->mutex_in); 125d94169a1f0259e2da5e6873d205e355248c3a550bart in = fetch_and_add(&b->in, 1); 126d94169a1f0259e2da5e6873d205e355248c3a550bart if (in >= BUFFER_MAX) 127d94169a1f0259e2da5e6873d205e355248c3a550bart { 128d94169a1f0259e2da5e6873d205e355248c3a550bart fetch_and_add(&b->in, -BUFFER_MAX); 129d94169a1f0259e2da5e6873d205e355248c3a550bart in -= BUFFER_MAX; 130d94169a1f0259e2da5e6873d205e355248c3a550bart } 131d94169a1f0259e2da5e6873d205e355248c3a550bart b->buffer[in] = *d; 13203225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 13303225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_unlock(&b->mutex_in); 134d94169a1f0259e2da5e6873d205e355248c3a550bart if (! quiet) 135d94169a1f0259e2da5e6873d205e355248c3a550bart { 136d94169a1f0259e2da5e6873d205e355248c3a550bart printf("sent %d to buffer[%d]\n", *d, in); 137d94169a1f0259e2da5e6873d205e355248c3a550bart fflush(stdout); 138d94169a1f0259e2da5e6873d205e355248c3a550bart } 1396e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_post(b->data); 1406fd7d7488898e93aceabca60366166e679af9fd7bart} 1416fd7d7488898e93aceabca60366166e679af9fd7bart 1426e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_destroy(buffer_t* b) 1436fd7d7488898e93aceabca60366166e679af9fd7bart{ 1446e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart destroy_semaphore(DATA_SEMAPHORE_NAME, b->data); 1456e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart destroy_semaphore(FREE_SEMAPHORE_NAME, b->free); 1466fd7d7488898e93aceabca60366166e679af9fd7bart 1476fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_destroy(&b->mutex_in); 1486fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_destroy(&b->mutex_out); 1496fd7d7488898e93aceabca60366166e679af9fd7bart} 1506fd7d7488898e93aceabca60366166e679af9fd7bart 1516e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic buffer_t b; 1526fd7d7488898e93aceabca60366166e679af9fd7bart 1536e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void producer(int* id) 1546fd7d7488898e93aceabca60366166e679af9fd7bart{ 1556fd7d7488898e93aceabca60366166e679af9fd7bart buffer_send(&b, id); 1566fd7d7488898e93aceabca60366166e679af9fd7bart pthread_exit(NULL); 1576fd7d7488898e93aceabca60366166e679af9fd7bart} 1586fd7d7488898e93aceabca60366166e679af9fd7bart 1596fd7d7488898e93aceabca60366166e679af9fd7bart#define MAXSLEEP (100 * 1000) 1606fd7d7488898e93aceabca60366166e679af9fd7bart 1616e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void consumer(int* id) 1626fd7d7488898e93aceabca60366166e679af9fd7bart{ 1636fd7d7488898e93aceabca60366166e679af9fd7bart int d; 1646fd7d7488898e93aceabca60366166e679af9fd7bart usleep(rand() % MAXSLEEP); 1656fd7d7488898e93aceabca60366166e679af9fd7bart buffer_recv(&b, &d); 1666fd7d7488898e93aceabca60366166e679af9fd7bart if (! quiet) 167d94169a1f0259e2da5e6873d205e355248c3a550bart { 1686fd7d7488898e93aceabca60366166e679af9fd7bart printf("%i: %i\n", *id, d); 169d94169a1f0259e2da5e6873d205e355248c3a550bart fflush(stdout); 170d94169a1f0259e2da5e6873d205e355248c3a550bart } 1716fd7d7488898e93aceabca60366166e679af9fd7bart pthread_exit(NULL); 1726fd7d7488898e93aceabca60366166e679af9fd7bart} 1736fd7d7488898e93aceabca60366166e679af9fd7bart 1746fd7d7488898e93aceabca60366166e679af9fd7bart#define THREADS (10) 1756fd7d7488898e93aceabca60366166e679af9fd7bart 1766fd7d7488898e93aceabca60366166e679af9fd7bartint main(int argc, char** argv) 1776fd7d7488898e93aceabca60366166e679af9fd7bart{ 1786fd7d7488898e93aceabca60366166e679af9fd7bart pthread_t producers[THREADS]; 1796fd7d7488898e93aceabca60366166e679af9fd7bart pthread_t consumers[THREADS]; 1806fd7d7488898e93aceabca60366166e679af9fd7bart int thread_arg[THREADS]; 1816fd7d7488898e93aceabca60366166e679af9fd7bart int i; 1826fd7d7488898e93aceabca60366166e679af9fd7bart int optchar; 1836fd7d7488898e93aceabca60366166e679af9fd7bart 18403225a834a0dd72d96afd20c6d8188450dd08726bart while ((optchar = getopt(argc, argv, "nq")) != EOF) 1856fd7d7488898e93aceabca60366166e679af9fd7bart { 1866fd7d7488898e93aceabca60366166e679af9fd7bart switch (optchar) 1876fd7d7488898e93aceabca60366166e679af9fd7bart { 18803225a834a0dd72d96afd20c6d8188450dd08726bart case 'n': 18903225a834a0dd72d96afd20c6d8188450dd08726bart use_locking = 0; 19003225a834a0dd72d96afd20c6d8188450dd08726bart break; 1916fd7d7488898e93aceabca60366166e679af9fd7bart case 'q': 1926fd7d7488898e93aceabca60366166e679af9fd7bart quiet = 1; 1936fd7d7488898e93aceabca60366166e679af9fd7bart break; 1946fd7d7488898e93aceabca60366166e679af9fd7bart } 1956fd7d7488898e93aceabca60366166e679af9fd7bart } 1966fd7d7488898e93aceabca60366166e679af9fd7bart 1976fd7d7488898e93aceabca60366166e679af9fd7bart srand(time(NULL)); 1986fd7d7488898e93aceabca60366166e679af9fd7bart 1996fd7d7488898e93aceabca60366166e679af9fd7bart buffer_init(&b); 2006fd7d7488898e93aceabca60366166e679af9fd7bart 2016fd7d7488898e93aceabca60366166e679af9fd7bart for (i = 0; i < THREADS; ++i) 2026fd7d7488898e93aceabca60366166e679af9fd7bart { 2036fd7d7488898e93aceabca60366166e679af9fd7bart thread_arg[i] = i; 2046fd7d7488898e93aceabca60366166e679af9fd7bart pthread_create(producers + i, NULL, 2056fd7d7488898e93aceabca60366166e679af9fd7bart (void * (*)(void *)) producer, &thread_arg[i]); 2066fd7d7488898e93aceabca60366166e679af9fd7bart } 2076fd7d7488898e93aceabca60366166e679af9fd7bart 2086fd7d7488898e93aceabca60366166e679af9fd7bart for (i = 0; i < THREADS; ++i) 2096fd7d7488898e93aceabca60366166e679af9fd7bart pthread_create(consumers + i, NULL, 2106fd7d7488898e93aceabca60366166e679af9fd7bart (void * (*)(void *)) consumer, &thread_arg[i]); 2116fd7d7488898e93aceabca60366166e679af9fd7bart 2126fd7d7488898e93aceabca60366166e679af9fd7bart for (i = 0; i < THREADS; ++i) 2136fd7d7488898e93aceabca60366166e679af9fd7bart { 2146fd7d7488898e93aceabca60366166e679af9fd7bart pthread_join(producers[i], NULL); 2156fd7d7488898e93aceabca60366166e679af9fd7bart pthread_join(consumers[i], NULL); 2166fd7d7488898e93aceabca60366166e679af9fd7bart } 2176fd7d7488898e93aceabca60366166e679af9fd7bart 2186fd7d7488898e93aceabca60366166e679af9fd7bart buffer_destroy(&b); 2196fd7d7488898e93aceabca60366166e679af9fd7bart 2206fd7d7488898e93aceabca60366166e679af9fd7bart return 0; 2216fd7d7488898e93aceabca60366166e679af9fd7bart} 222