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{ 623e7c40292141549eee08a9db6db60a6cf3195f91bart#ifdef VGO_darwin 638c7213fc97157614ca53f70353b9cd2d7a9326d9bart char name_and_pid[32]; 648c7213fc97157614ca53f70353b9cd2d7a9326d9bart snprintf(name_and_pid, sizeof(name_and_pid), "%s-%d", name, getpid()); 658c7213fc97157614ca53f70353b9cd2d7a9326d9bart sem_t* p = sem_open(name_and_pid, O_CREAT | O_EXCL, 0600, value); 668c7213fc97157614ca53f70353b9cd2d7a9326d9bart if (p == SEM_FAILED) { 678c7213fc97157614ca53f70353b9cd2d7a9326d9bart perror("sem_open"); 688c7213fc97157614ca53f70353b9cd2d7a9326d9bart return NULL; 698c7213fc97157614ca53f70353b9cd2d7a9326d9bart } 706e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart return p; 716e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#else 726e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_t* p = malloc(sizeof(*p)); 736e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart if (p) 746e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_init(p, 0, value); 756e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart return p; 766e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#endif 776e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart} 786e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart 796e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void destroy_semaphore(const char* const name, sem_t* p) 806e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart{ 813e7c40292141549eee08a9db6db60a6cf3195f91bart#ifdef VGO_darwin 826e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_close(p); 836e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_unlink(name); 846e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#else 856e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_destroy(p); 866e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart free(p); 876e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart#endif 886e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart} 896e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart 906e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_init(buffer_t * b) 916e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart{ 926e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart b->data = create_semaphore(DATA_SEMAPHORE_NAME, 0); 936e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart b->free = create_semaphore(FREE_SEMAPHORE_NAME, BUFFER_MAX); 946fd7d7488898e93aceabca60366166e679af9fd7bart 956fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_init(&b->mutex_in, NULL); 966fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_init(&b->mutex_out, NULL); 976fd7d7488898e93aceabca60366166e679af9fd7bart 986fd7d7488898e93aceabca60366166e679af9fd7bart b->in = 0; 996fd7d7488898e93aceabca60366166e679af9fd7bart b->out = 0; 1006fd7d7488898e93aceabca60366166e679af9fd7bart} 1016fd7d7488898e93aceabca60366166e679af9fd7bart 1026e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_recv(buffer_t* b, data_t* d) 1036fd7d7488898e93aceabca60366166e679af9fd7bart{ 104d94169a1f0259e2da5e6873d205e355248c3a550bart int out; 1056e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_wait(b->data); 10603225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 10703225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_lock(&b->mutex_out); 108d94169a1f0259e2da5e6873d205e355248c3a550bart out = fetch_and_add(&b->out, 1); 109d94169a1f0259e2da5e6873d205e355248c3a550bart if (out >= BUFFER_MAX) 110d94169a1f0259e2da5e6873d205e355248c3a550bart { 111d94169a1f0259e2da5e6873d205e355248c3a550bart fetch_and_add(&b->out, -BUFFER_MAX); 112d94169a1f0259e2da5e6873d205e355248c3a550bart out -= BUFFER_MAX; 113d94169a1f0259e2da5e6873d205e355248c3a550bart } 114d94169a1f0259e2da5e6873d205e355248c3a550bart *d = b->buffer[out]; 11503225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 11603225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_unlock(&b->mutex_out); 117d94169a1f0259e2da5e6873d205e355248c3a550bart if (! quiet) 118d94169a1f0259e2da5e6873d205e355248c3a550bart { 119d94169a1f0259e2da5e6873d205e355248c3a550bart printf("received %d from buffer[%d]\n", *d, out); 120d94169a1f0259e2da5e6873d205e355248c3a550bart fflush(stdout); 121d94169a1f0259e2da5e6873d205e355248c3a550bart } 1226e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_post(b->free); 1236fd7d7488898e93aceabca60366166e679af9fd7bart} 1246fd7d7488898e93aceabca60366166e679af9fd7bart 1256e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_send(buffer_t* b, data_t* d) 1266fd7d7488898e93aceabca60366166e679af9fd7bart{ 127d94169a1f0259e2da5e6873d205e355248c3a550bart int in; 1286e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_wait(b->free); 12903225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 13003225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_lock(&b->mutex_in); 131d94169a1f0259e2da5e6873d205e355248c3a550bart in = fetch_and_add(&b->in, 1); 132d94169a1f0259e2da5e6873d205e355248c3a550bart if (in >= BUFFER_MAX) 133d94169a1f0259e2da5e6873d205e355248c3a550bart { 134d94169a1f0259e2da5e6873d205e355248c3a550bart fetch_and_add(&b->in, -BUFFER_MAX); 135d94169a1f0259e2da5e6873d205e355248c3a550bart in -= BUFFER_MAX; 136d94169a1f0259e2da5e6873d205e355248c3a550bart } 137d94169a1f0259e2da5e6873d205e355248c3a550bart b->buffer[in] = *d; 13803225a834a0dd72d96afd20c6d8188450dd08726bart if (use_locking) 13903225a834a0dd72d96afd20c6d8188450dd08726bart pthread_mutex_unlock(&b->mutex_in); 140d94169a1f0259e2da5e6873d205e355248c3a550bart if (! quiet) 141d94169a1f0259e2da5e6873d205e355248c3a550bart { 142d94169a1f0259e2da5e6873d205e355248c3a550bart printf("sent %d to buffer[%d]\n", *d, in); 143d94169a1f0259e2da5e6873d205e355248c3a550bart fflush(stdout); 144d94169a1f0259e2da5e6873d205e355248c3a550bart } 1456e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart sem_post(b->data); 1466fd7d7488898e93aceabca60366166e679af9fd7bart} 1476fd7d7488898e93aceabca60366166e679af9fd7bart 1486e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void buffer_destroy(buffer_t* b) 1496fd7d7488898e93aceabca60366166e679af9fd7bart{ 1506e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart destroy_semaphore(DATA_SEMAPHORE_NAME, b->data); 1516e38cb2fe1aac8a8082c2b4139fb8202c95fad7abart destroy_semaphore(FREE_SEMAPHORE_NAME, b->free); 1526fd7d7488898e93aceabca60366166e679af9fd7bart 1536fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_destroy(&b->mutex_in); 1546fd7d7488898e93aceabca60366166e679af9fd7bart pthread_mutex_destroy(&b->mutex_out); 1556fd7d7488898e93aceabca60366166e679af9fd7bart} 1566fd7d7488898e93aceabca60366166e679af9fd7bart 1576e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic buffer_t b; 1586fd7d7488898e93aceabca60366166e679af9fd7bart 1596e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void producer(int* id) 1606fd7d7488898e93aceabca60366166e679af9fd7bart{ 1616fd7d7488898e93aceabca60366166e679af9fd7bart buffer_send(&b, id); 1626fd7d7488898e93aceabca60366166e679af9fd7bart pthread_exit(NULL); 1636fd7d7488898e93aceabca60366166e679af9fd7bart} 1646fd7d7488898e93aceabca60366166e679af9fd7bart 1656fd7d7488898e93aceabca60366166e679af9fd7bart#define MAXSLEEP (100 * 1000) 1666fd7d7488898e93aceabca60366166e679af9fd7bart 1676e38cb2fe1aac8a8082c2b4139fb8202c95fad7abartstatic void consumer(int* id) 1686fd7d7488898e93aceabca60366166e679af9fd7bart{ 1696fd7d7488898e93aceabca60366166e679af9fd7bart int d; 1706fd7d7488898e93aceabca60366166e679af9fd7bart usleep(rand() % MAXSLEEP); 1716fd7d7488898e93aceabca60366166e679af9fd7bart buffer_recv(&b, &d); 1726fd7d7488898e93aceabca60366166e679af9fd7bart if (! quiet) 173d94169a1f0259e2da5e6873d205e355248c3a550bart { 1746fd7d7488898e93aceabca60366166e679af9fd7bart printf("%i: %i\n", *id, d); 175d94169a1f0259e2da5e6873d205e355248c3a550bart fflush(stdout); 176d94169a1f0259e2da5e6873d205e355248c3a550bart } 1776fd7d7488898e93aceabca60366166e679af9fd7bart pthread_exit(NULL); 1786fd7d7488898e93aceabca60366166e679af9fd7bart} 1796fd7d7488898e93aceabca60366166e679af9fd7bart 1806fd7d7488898e93aceabca60366166e679af9fd7bart#define THREADS (10) 1816fd7d7488898e93aceabca60366166e679af9fd7bart 1826fd7d7488898e93aceabca60366166e679af9fd7bartint main(int argc, char** argv) 1836fd7d7488898e93aceabca60366166e679af9fd7bart{ 1846fd7d7488898e93aceabca60366166e679af9fd7bart pthread_t producers[THREADS]; 1856fd7d7488898e93aceabca60366166e679af9fd7bart pthread_t consumers[THREADS]; 1866fd7d7488898e93aceabca60366166e679af9fd7bart int thread_arg[THREADS]; 1876fd7d7488898e93aceabca60366166e679af9fd7bart int i; 1886fd7d7488898e93aceabca60366166e679af9fd7bart int optchar; 1896fd7d7488898e93aceabca60366166e679af9fd7bart 19003225a834a0dd72d96afd20c6d8188450dd08726bart while ((optchar = getopt(argc, argv, "nq")) != EOF) 1916fd7d7488898e93aceabca60366166e679af9fd7bart { 1926fd7d7488898e93aceabca60366166e679af9fd7bart switch (optchar) 1936fd7d7488898e93aceabca60366166e679af9fd7bart { 19403225a834a0dd72d96afd20c6d8188450dd08726bart case 'n': 19503225a834a0dd72d96afd20c6d8188450dd08726bart use_locking = 0; 19603225a834a0dd72d96afd20c6d8188450dd08726bart break; 1976fd7d7488898e93aceabca60366166e679af9fd7bart case 'q': 1986fd7d7488898e93aceabca60366166e679af9fd7bart quiet = 1; 1996fd7d7488898e93aceabca60366166e679af9fd7bart break; 2006fd7d7488898e93aceabca60366166e679af9fd7bart } 2016fd7d7488898e93aceabca60366166e679af9fd7bart } 2026fd7d7488898e93aceabca60366166e679af9fd7bart 2036fd7d7488898e93aceabca60366166e679af9fd7bart srand(time(NULL)); 2046fd7d7488898e93aceabca60366166e679af9fd7bart 2056fd7d7488898e93aceabca60366166e679af9fd7bart buffer_init(&b); 2066fd7d7488898e93aceabca60366166e679af9fd7bart 2076fd7d7488898e93aceabca60366166e679af9fd7bart for (i = 0; i < THREADS; ++i) 2086fd7d7488898e93aceabca60366166e679af9fd7bart { 2096fd7d7488898e93aceabca60366166e679af9fd7bart thread_arg[i] = i; 2106fd7d7488898e93aceabca60366166e679af9fd7bart pthread_create(producers + i, NULL, 2116fd7d7488898e93aceabca60366166e679af9fd7bart (void * (*)(void *)) producer, &thread_arg[i]); 2126fd7d7488898e93aceabca60366166e679af9fd7bart } 2136fd7d7488898e93aceabca60366166e679af9fd7bart 2146fd7d7488898e93aceabca60366166e679af9fd7bart for (i = 0; i < THREADS; ++i) 2156fd7d7488898e93aceabca60366166e679af9fd7bart pthread_create(consumers + i, NULL, 2166fd7d7488898e93aceabca60366166e679af9fd7bart (void * (*)(void *)) consumer, &thread_arg[i]); 2176fd7d7488898e93aceabca60366166e679af9fd7bart 2186fd7d7488898e93aceabca60366166e679af9fd7bart for (i = 0; i < THREADS; ++i) 2196fd7d7488898e93aceabca60366166e679af9fd7bart { 2206fd7d7488898e93aceabca60366166e679af9fd7bart pthread_join(producers[i], NULL); 2216fd7d7488898e93aceabca60366166e679af9fd7bart pthread_join(consumers[i], NULL); 2226fd7d7488898e93aceabca60366166e679af9fd7bart } 2236fd7d7488898e93aceabca60366166e679af9fd7bart 2246fd7d7488898e93aceabca60366166e679af9fd7bart buffer_destroy(&b); 2256fd7d7488898e93aceabca60366166e679af9fd7bart 2266fd7d7488898e93aceabca60366166e679af9fd7bart return 0; 2276fd7d7488898e93aceabca60366166e679af9fd7bart} 228