librfn
An ad-hoc utility library
ringbuftest.c
Go to the documentation of this file.
1 /*
2  * ringbuftest.c
3  *
4  * Part of librfn (a general utility library from redfelineninja.org.uk)
5  *
6  * Copyright (C) 2014 Daniel Thompson <daniel@redfelineninja.org.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #undef NDEBUG
15 
16 #include <assert.h>
17 #include <pthread.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include <librfn.h>
24 
25 uint8_t smallbuf[4];
27 
28 uint8_t largebuf[4096];
29 ringbuf_t largering = RINGBUF_VAR_INIT(largebuf, sizeof(largebuf));
30 
31 void *producer(void *p)
32 {
33  ringbuf_t *rb = p;
34  uint32_t seed = RAND31_VAR_INIT;
35 
36  uint32_t endtime = time_now() + 2000000; // 2s
37  while (time_now() < endtime) {
38  uint32_t r = rand31_r(&seed);
39  if ((r & 0xffff) == 0x1111)
40  usleep(1000);
41  while (!ringbuf_put(rb, r))
42  ;
43  }
44 
45  return NULL;
46 }
47 
48 void *consumer(void *p)
49 {
50  ringbuf_t *rb = p;
51  uint32_t seed = RAND31_VAR_INIT;
52 
53  for (long long int c=0; ; c++) {
54  uint32_t r = rand31_r(&seed);
55  int d;
56 
57  if ((r & 0xffff) == 0x2222)
58  usleep(1000);
59 
60  uint32_t endtime = time_now() + 100000; // 100ms
61  while (-1 == (d = ringbuf_get(rb))) {
62  if (cyclecmp32(time_now(), endtime) > 0) {
63  fprintf(stderr, "Existing after %lld bytes\n",
64  c);
65  return NULL; // timeout
66  }
67  }
68 
69  d &= 0xff;
70  r &= 0xff;
71  if (d != r) {
72  fprintf(stderr, "MISMATCH after %lld bytes "
73  "(exp %02x got %02x)\n", c, r, d);
74  assert(0);
75  }
76  }
77 }
78 
79 int main()
80 {
81  ringbuf_t myring;
82 
83  /* prove the equivalence of the initializer and the init fn */
84  ringbuf_init(&myring, smallbuf, sizeof(smallbuf));
85  verify(0 == memcmp(&smallring, &myring, sizeof(smallring)));
86 
87  /* initially empty */
88  verify(-1 == ringbuf_get(&smallring) && ringbuf_empty(&smallring));
89 
90  /* becomes full after three puts */
91  verify(ringbuf_put(&smallring, 0));
92  verify(ringbuf_put(&smallring, 1));
93  verify(ringbuf_put(&smallring, 2));
94  verify(!ringbuf_put(&smallring, 3));
95 
96  /* get/put/still full (for all possible read/write indices */
97  verify(0 == ringbuf_get(&smallring));
98  verify(ringbuf_put(&smallring, 3));
99  verify(!ringbuf_put(&smallring, 4));
100  verify(1 == ringbuf_get(&smallring));
101  verify(ringbuf_put(&smallring, 4));
102  verify(!ringbuf_put(&smallring, 5));
103  verify(2 == ringbuf_get(&smallring));
104  verify(ringbuf_put(&smallring, 5));
105  verify(!ringbuf_put(&smallring, 6));
106  verify(3 == ringbuf_get(&smallring));
107  verify(ringbuf_put(&smallring, 6));
108  verify(!ringbuf_put(&smallring, 7));
109 
110  /* empty the ring */
111  verify(4 == ringbuf_get(&smallring));
112  verify(5 == ringbuf_get(&smallring));
113  verify(6 == ringbuf_get(&smallring));
114  verify(-1 == ringbuf_get(&smallring) && ringbuf_empty(&smallring));
115 
116  /* put/get/still empty (for all possible read/write indices */
117  verify(ringbuf_put(&smallring, 7));
118  verify(7 == ringbuf_get(&smallring));
119  verify(-1 == ringbuf_get(&smallring) && ringbuf_empty(&smallring));
120  verify(ringbuf_put(&smallring, 8));
121  verify(8 == ringbuf_get(&smallring));
122  verify(-1 == ringbuf_get(&smallring) && ringbuf_empty(&smallring));
123  verify(ringbuf_put(&smallring, 9));
124  verify(9 == ringbuf_get(&smallring));
125  verify(-1 == ringbuf_get(&smallring) && ringbuf_empty(&smallring));
126  verify(ringbuf_put(&smallring, 10));
127  verify(10 == ringbuf_get(&smallring));
128  verify(-1 == ringbuf_get(&smallring) && ringbuf_empty(&smallring));
129 
130  /* correct sign handling for all data */
131  for (int i=0; i<0x100; i++) {
132  verify(ringbuf_put(&smallring, i));
133  verify(i == ringbuf_get(&smallring));
134  }
135 
136  /* producer/consumer soak test (pretty pointless on strongly ordered
137  * x86 but even on ARM/MIPS the runtime is pretty short)
138  */
139  pthread_t pt, ct;
140  verify(0 == pthread_create(&pt, NULL, producer, &largering));
141  verify(0 == pthread_create(&ct, NULL, consumer, &largering));
142  verify(0 == pthread_join(pt, NULL));
143  verify(0 == pthread_join(ct, NULL));
144 
145  return 0;
146 }
struct charlie c
#define RINGBUF_VAR_INIT(bufp, buf_len)
Static initializer for a ring buffer descriptor.
Definition: ringbuf.h:48
Ring buffer descriptor.
Definition: ringbuf.h:38
uint8_t smallbuf[4]
Definition: ringbuftest.c:25
int ringbuf_get(ringbuf_t *rb)
Extract a byte from the ring buffer.
Definition: ringbuf.c:31
uint8_t largebuf[4096]
Definition: ringbuftest.c:28
int32_t cyclecmp32(uint32_t a, uint32_t b)
Compares values that may be subject to overflow.
Definition: util.c:19
#define verify(x)
Definition: util.h:55
void * producer(void *p)
Definition: ringbuftest.c:31
int main()
Definition: ringbuftest.c:79
uint32_t time_now(void)
bool ringbuf_empty(ringbuf_t *rb)
Test whether the ring buffer contains any data.
Definition: ringbuf.c:52
ringbuf_t largering
Definition: ringbuftest.c:29
bool ringbuf_put(ringbuf_t *rb, uint8_t d)
Insert a byte into the ring buffer.
Definition: ringbuf.c:58
void ringbuf_init(ringbuf_t *rb, void *bufp, size_t buf_len)
Runtime initializer for a ring buffer descriptor.
Definition: ringbuf.c:22
#define RAND31_VAR_INIT
Definition: rand.h:38
void * consumer(void *p)
Definition: ringbuftest.c:48
uint32_t rand31_r(uint32_t *seedp)
Definition: rand.c:23
ringbuf_t smallring
Definition: ringbuftest.c:26