1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker *
4*b9df5ad1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker *
8*b9df5ad1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker *
10*b9df5ad1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker */
16*b9df5ad1SAndroid Build Coastguard Worker
17*b9df5ad1SAndroid Build Coastguard Worker #include <errno.h>
18*b9df5ad1SAndroid Build Coastguard Worker #include <stdio.h>
19*b9df5ad1SAndroid Build Coastguard Worker #include <string>
20*b9df5ad1SAndroid Build Coastguard Worker #include <sys/mman.h>
21*b9df5ad1SAndroid Build Coastguard Worker #include <sys/types.h>
22*b9df5ad1SAndroid Build Coastguard Worker #include <sys/wait.h>
23*b9df5ad1SAndroid Build Coastguard Worker #include <unistd.h>
24*b9df5ad1SAndroid Build Coastguard Worker
25*b9df5ad1SAndroid Build Coastguard Worker #include <new>
26*b9df5ad1SAndroid Build Coastguard Worker
27*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/fifo.h>
28*b9df5ad1SAndroid Build Coastguard Worker #include <cutils/ashmem.h>
29*b9df5ad1SAndroid Build Coastguard Worker
30*b9df5ad1SAndroid Build Coastguard Worker #define FRAME_COUNT 2048
31*b9df5ad1SAndroid Build Coastguard Worker #define FRAME_SIZE sizeof(int16_t)
32*b9df5ad1SAndroid Build Coastguard Worker #define BUFFER_SIZE (FRAME_COUNT * FRAME_SIZE)
33*b9df5ad1SAndroid Build Coastguard Worker
main(int argc,char ** argv)34*b9df5ad1SAndroid Build Coastguard Worker int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
35*b9df5ad1SAndroid Build Coastguard Worker {
36*b9df5ad1SAndroid Build Coastguard Worker // TODO Add error checking for ashmem_create_region and mmap
37*b9df5ad1SAndroid Build Coastguard Worker
38*b9df5ad1SAndroid Build Coastguard Worker const int frontFd = ashmem_create_region("front", sizeof(audio_utils_fifo_index));
39*b9df5ad1SAndroid Build Coastguard Worker printf("frontFd=%d\n", frontFd);
40*b9df5ad1SAndroid Build Coastguard Worker
41*b9df5ad1SAndroid Build Coastguard Worker const int rearFd = ashmem_create_region("rear", sizeof(audio_utils_fifo_index));
42*b9df5ad1SAndroid Build Coastguard Worker printf("rearFd=%d\n", rearFd);
43*b9df5ad1SAndroid Build Coastguard Worker
44*b9df5ad1SAndroid Build Coastguard Worker const int dataFd = ashmem_create_region("buffer", BUFFER_SIZE);
45*b9df5ad1SAndroid Build Coastguard Worker printf("dataFd=%d\n", dataFd);
46*b9df5ad1SAndroid Build Coastguard Worker
47*b9df5ad1SAndroid Build Coastguard Worker // next two index constructors must execute exactly once, so we do it in the parent
48*b9df5ad1SAndroid Build Coastguard Worker
49*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_index *frontIndex = (audio_utils_fifo_index *) mmap(NULL,
50*b9df5ad1SAndroid Build Coastguard Worker sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE, MAP_SHARED, frontFd, (off_t) 0);
51*b9df5ad1SAndroid Build Coastguard Worker printf("parent frontIndex=%p\n", frontIndex);
52*b9df5ad1SAndroid Build Coastguard Worker (void) new(frontIndex) audio_utils_fifo_index();
53*b9df5ad1SAndroid Build Coastguard Worker
54*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_index *rearIndex = (audio_utils_fifo_index *) mmap(NULL,
55*b9df5ad1SAndroid Build Coastguard Worker sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE, MAP_SHARED, rearFd, (off_t) 0);
56*b9df5ad1SAndroid Build Coastguard Worker printf("parent rearIndex=%p\n", rearIndex);
57*b9df5ad1SAndroid Build Coastguard Worker (void) new(rearIndex) audio_utils_fifo_index();
58*b9df5ad1SAndroid Build Coastguard Worker
59*b9df5ad1SAndroid Build Coastguard Worker int16_t *data = (int16_t *) mmap(NULL, sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE,
60*b9df5ad1SAndroid Build Coastguard Worker MAP_SHARED, dataFd, (off_t) 0);
61*b9df5ad1SAndroid Build Coastguard Worker printf("parent data=%p\n", data);
62*b9df5ad1SAndroid Build Coastguard Worker memset(data, 0, BUFFER_SIZE);
63*b9df5ad1SAndroid Build Coastguard Worker
64*b9df5ad1SAndroid Build Coastguard Worker const int pageSize = getpagesize();
65*b9df5ad1SAndroid Build Coastguard Worker printf("page size=%d\n", pageSize);
66*b9df5ad1SAndroid Build Coastguard Worker
67*b9df5ad1SAndroid Build Coastguard Worker // create writer
68*b9df5ad1SAndroid Build Coastguard Worker
69*b9df5ad1SAndroid Build Coastguard Worker printf("fork writer:\n");
70*b9df5ad1SAndroid Build Coastguard Worker const pid_t pidWriter = fork();
71*b9df5ad1SAndroid Build Coastguard Worker // TODO check if pidWriter < 0
72*b9df5ad1SAndroid Build Coastguard Worker if (!pidWriter) {
73*b9df5ad1SAndroid Build Coastguard Worker
74*b9df5ad1SAndroid Build Coastguard Worker // Child inherits the parent's read/write mapping of front index.
75*b9df5ad1SAndroid Build Coastguard Worker // To confirm that there are no attempts to write to the front index,
76*b9df5ad1SAndroid Build Coastguard Worker // unmap it and then re-map it as read-only.
77*b9df5ad1SAndroid Build Coastguard Worker int ok = munmap(frontIndex, sizeof(audio_utils_fifo_index));
78*b9df5ad1SAndroid Build Coastguard Worker printf("writer unmap front ok=%d\n", ok);
79*b9df5ad1SAndroid Build Coastguard Worker ok = ashmem_set_prot_region(frontFd, PROT_READ);
80*b9df5ad1SAndroid Build Coastguard Worker printf("writer prot read front ok=%d\n", ok);
81*b9df5ad1SAndroid Build Coastguard Worker // The pagesize * 4 offset confirms that we don't assume identical mapping in both processes
82*b9df5ad1SAndroid Build Coastguard Worker frontIndex = (audio_utils_fifo_index *) mmap((char *) frontIndex + pageSize * 4,
83*b9df5ad1SAndroid Build Coastguard Worker sizeof(audio_utils_fifo_index), PROT_READ, MAP_SHARED | MAP_FIXED, frontFd,
84*b9df5ad1SAndroid Build Coastguard Worker (off_t) 0);
85*b9df5ad1SAndroid Build Coastguard Worker printf("writer frontIndex=%p\n", frontIndex);
86*b9df5ad1SAndroid Build Coastguard Worker
87*b9df5ad1SAndroid Build Coastguard Worker // Retain our read/write mapping of rear index and data
88*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo fifo(FRAME_COUNT, FRAME_SIZE, data, *rearIndex, frontIndex);
89*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_writer writer(fifo);
90*b9df5ad1SAndroid Build Coastguard Worker
91*b9df5ad1SAndroid Build Coastguard Worker sleep(2);
92*b9df5ad1SAndroid Build Coastguard Worker
93*b9df5ad1SAndroid Build Coastguard Worker for (int16_t value = 1; value <= 20; value++) {
94*b9df5ad1SAndroid Build Coastguard Worker printf("writing %d\n", value);
95*b9df5ad1SAndroid Build Coastguard Worker const ssize_t actual = writer.write(&value, 1);
96*b9df5ad1SAndroid Build Coastguard Worker if (actual != 1) {
97*b9df5ad1SAndroid Build Coastguard Worker printf("wrote unexpected actual = %zd\n", actual);
98*b9df5ad1SAndroid Build Coastguard Worker break;
99*b9df5ad1SAndroid Build Coastguard Worker }
100*b9df5ad1SAndroid Build Coastguard Worker // TODO needs a lot of work
101*b9df5ad1SAndroid Build Coastguard Worker switch (value) {
102*b9df5ad1SAndroid Build Coastguard Worker case 10:
103*b9df5ad1SAndroid Build Coastguard Worker sleep(2);
104*b9df5ad1SAndroid Build Coastguard Worker break;
105*b9df5ad1SAndroid Build Coastguard Worker case 14:
106*b9df5ad1SAndroid Build Coastguard Worker sleep(4);
107*b9df5ad1SAndroid Build Coastguard Worker break;
108*b9df5ad1SAndroid Build Coastguard Worker default:
109*b9df5ad1SAndroid Build Coastguard Worker usleep(500000);
110*b9df5ad1SAndroid Build Coastguard Worker break;
111*b9df5ad1SAndroid Build Coastguard Worker }
112*b9df5ad1SAndroid Build Coastguard Worker }
113*b9df5ad1SAndroid Build Coastguard Worker
114*b9df5ad1SAndroid Build Coastguard Worker (void) close(frontFd);
115*b9df5ad1SAndroid Build Coastguard Worker (void) close(rearFd);
116*b9df5ad1SAndroid Build Coastguard Worker (void) close(dataFd);
117*b9df5ad1SAndroid Build Coastguard Worker
118*b9df5ad1SAndroid Build Coastguard Worker return EXIT_SUCCESS;
119*b9df5ad1SAndroid Build Coastguard Worker }
120*b9df5ad1SAndroid Build Coastguard Worker
121*b9df5ad1SAndroid Build Coastguard Worker // The sleep(2) above and sleep(1) here ensure that the order is:
122*b9df5ad1SAndroid Build Coastguard Worker // a. writer initializes
123*b9df5ad1SAndroid Build Coastguard Worker // b. reader initializes
124*b9df5ad1SAndroid Build Coastguard Worker // c. reader starts the read loop
125*b9df5ad1SAndroid Build Coastguard Worker // d. writer starts the write loop
126*b9df5ad1SAndroid Build Coastguard Worker // Actually, as long as (a) precedes (d) and (b) precedes (c), the order does not matter.
127*b9df5ad1SAndroid Build Coastguard Worker // TODO test all valid sequences.
128*b9df5ad1SAndroid Build Coastguard Worker sleep(1);
129*b9df5ad1SAndroid Build Coastguard Worker
130*b9df5ad1SAndroid Build Coastguard Worker // create reader
131*b9df5ad1SAndroid Build Coastguard Worker
132*b9df5ad1SAndroid Build Coastguard Worker printf("fork reader:\n");
133*b9df5ad1SAndroid Build Coastguard Worker const pid_t pidReader = fork();
134*b9df5ad1SAndroid Build Coastguard Worker // TODO check if pidReader < 0
135*b9df5ad1SAndroid Build Coastguard Worker if (!pidReader) {
136*b9df5ad1SAndroid Build Coastguard Worker
137*b9df5ad1SAndroid Build Coastguard Worker // Child inherits the parent's read/write mapping of rear index.
138*b9df5ad1SAndroid Build Coastguard Worker // To confirm that there are no attempts to write to the rear index,
139*b9df5ad1SAndroid Build Coastguard Worker // unmap it and then re-map it as read-only.
140*b9df5ad1SAndroid Build Coastguard Worker int ok = munmap(rearIndex, sizeof(audio_utils_fifo_index));
141*b9df5ad1SAndroid Build Coastguard Worker printf("reader unmap rear ok=%d\n", ok);
142*b9df5ad1SAndroid Build Coastguard Worker ok = ashmem_set_prot_region(rearFd, PROT_READ);
143*b9df5ad1SAndroid Build Coastguard Worker printf("reader prot read rear ok=%d\n", ok);
144*b9df5ad1SAndroid Build Coastguard Worker // The pagesize * 4 offset confirms that we don't assume identical mapping in both processes
145*b9df5ad1SAndroid Build Coastguard Worker rearIndex = (audio_utils_fifo_index *) mmap((char *) rearIndex + pageSize * 4,
146*b9df5ad1SAndroid Build Coastguard Worker sizeof(audio_utils_fifo_index), PROT_READ, MAP_SHARED | MAP_FIXED, rearFd,
147*b9df5ad1SAndroid Build Coastguard Worker (off_t) 0);
148*b9df5ad1SAndroid Build Coastguard Worker printf("reader rearIndex=%p\n", rearIndex);
149*b9df5ad1SAndroid Build Coastguard Worker
150*b9df5ad1SAndroid Build Coastguard Worker // Similarly for the data
151*b9df5ad1SAndroid Build Coastguard Worker ok = munmap(data, BUFFER_SIZE);
152*b9df5ad1SAndroid Build Coastguard Worker printf("reader unmap data ok=%d\n", ok);
153*b9df5ad1SAndroid Build Coastguard Worker ok = ashmem_set_prot_region(dataFd, PROT_READ);
154*b9df5ad1SAndroid Build Coastguard Worker printf("reader prot read data ok=%d\n", ok);
155*b9df5ad1SAndroid Build Coastguard Worker // The pagesize * 8 offset confirms that we don't assume identical mapping in both processes
156*b9df5ad1SAndroid Build Coastguard Worker data = (int16_t *) mmap((char *) data + pageSize * 8, BUFFER_SIZE, PROT_READ,
157*b9df5ad1SAndroid Build Coastguard Worker MAP_SHARED | MAP_FIXED, dataFd, (off_t) 0);
158*b9df5ad1SAndroid Build Coastguard Worker printf("reader data=%p\n", data);
159*b9df5ad1SAndroid Build Coastguard Worker
160*b9df5ad1SAndroid Build Coastguard Worker // Retain our read/write mapping of front index
161*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo fifo(FRAME_COUNT, FRAME_SIZE, data, *rearIndex, frontIndex);
162*b9df5ad1SAndroid Build Coastguard Worker audio_utils_fifo_reader reader(fifo);
163*b9df5ad1SAndroid Build Coastguard Worker
164*b9df5ad1SAndroid Build Coastguard Worker for (;;) {
165*b9df5ad1SAndroid Build Coastguard Worker int16_t value;
166*b9df5ad1SAndroid Build Coastguard Worker struct timespec timeout = {
167*b9df5ad1SAndroid Build Coastguard Worker .tv_sec = 1,
168*b9df5ad1SAndroid Build Coastguard Worker .tv_nsec = 0
169*b9df5ad1SAndroid Build Coastguard Worker };
170*b9df5ad1SAndroid Build Coastguard Worker const ssize_t actual = reader.read(&value, 1, &timeout);
171*b9df5ad1SAndroid Build Coastguard Worker switch (actual) {
172*b9df5ad1SAndroid Build Coastguard Worker case 0:
173*b9df5ad1SAndroid Build Coastguard Worker break;
174*b9df5ad1SAndroid Build Coastguard Worker case 1:
175*b9df5ad1SAndroid Build Coastguard Worker printf("read %d\n", value);
176*b9df5ad1SAndroid Build Coastguard Worker if (value == 20) {
177*b9df5ad1SAndroid Build Coastguard Worker goto out;
178*b9df5ad1SAndroid Build Coastguard Worker }
179*b9df5ad1SAndroid Build Coastguard Worker break;
180*b9df5ad1SAndroid Build Coastguard Worker case -ETIMEDOUT:
181*b9df5ad1SAndroid Build Coastguard Worker printf("read timed out\n");
182*b9df5ad1SAndroid Build Coastguard Worker break;
183*b9df5ad1SAndroid Build Coastguard Worker default:
184*b9df5ad1SAndroid Build Coastguard Worker printf("read unexpected actual = %zd\n", actual);
185*b9df5ad1SAndroid Build Coastguard Worker goto out;
186*b9df5ad1SAndroid Build Coastguard Worker }
187*b9df5ad1SAndroid Build Coastguard Worker }
188*b9df5ad1SAndroid Build Coastguard Worker out:
189*b9df5ad1SAndroid Build Coastguard Worker
190*b9df5ad1SAndroid Build Coastguard Worker (void) close(frontFd);
191*b9df5ad1SAndroid Build Coastguard Worker (void) close(rearFd);
192*b9df5ad1SAndroid Build Coastguard Worker (void) close(dataFd);
193*b9df5ad1SAndroid Build Coastguard Worker
194*b9df5ad1SAndroid Build Coastguard Worker return EXIT_SUCCESS;
195*b9df5ad1SAndroid Build Coastguard Worker }
196*b9df5ad1SAndroid Build Coastguard Worker
197*b9df5ad1SAndroid Build Coastguard Worker int status;
198*b9df5ad1SAndroid Build Coastguard Worker pid_t pid = waitpid(pidWriter, &status, 0);
199*b9df5ad1SAndroid Build Coastguard Worker if (pid == pidWriter) {
200*b9df5ad1SAndroid Build Coastguard Worker printf("writer exited with status %d\n", status);
201*b9df5ad1SAndroid Build Coastguard Worker } else {
202*b9df5ad1SAndroid Build Coastguard Worker printf("waitpid on writer = %d\n", pid);
203*b9df5ad1SAndroid Build Coastguard Worker }
204*b9df5ad1SAndroid Build Coastguard Worker pid = waitpid(pidReader, &status, 0);
205*b9df5ad1SAndroid Build Coastguard Worker if (pid == pidReader) {
206*b9df5ad1SAndroid Build Coastguard Worker printf("reader exited with status %d\n", status);
207*b9df5ad1SAndroid Build Coastguard Worker } else {
208*b9df5ad1SAndroid Build Coastguard Worker printf("waitpid on reader = %d\n", pid);
209*b9df5ad1SAndroid Build Coastguard Worker }
210*b9df5ad1SAndroid Build Coastguard Worker
211*b9df5ad1SAndroid Build Coastguard Worker // next two index destructors must execute exactly once, so we do it in the parent
212*b9df5ad1SAndroid Build Coastguard Worker frontIndex->~audio_utils_fifo_index();
213*b9df5ad1SAndroid Build Coastguard Worker rearIndex->~audio_utils_fifo_index();
214*b9df5ad1SAndroid Build Coastguard Worker
215*b9df5ad1SAndroid Build Coastguard Worker int ok = munmap(frontIndex, sizeof(audio_utils_fifo_index));
216*b9df5ad1SAndroid Build Coastguard Worker printf("parent unmap front ok=%d\n", ok);
217*b9df5ad1SAndroid Build Coastguard Worker ok = munmap(rearIndex, sizeof(audio_utils_fifo_index));
218*b9df5ad1SAndroid Build Coastguard Worker printf("parent unmap rear ok=%d\n", ok);
219*b9df5ad1SAndroid Build Coastguard Worker ok = munmap(data, BUFFER_SIZE);
220*b9df5ad1SAndroid Build Coastguard Worker printf("parent unmap data ok=%d\n", ok);
221*b9df5ad1SAndroid Build Coastguard Worker
222*b9df5ad1SAndroid Build Coastguard Worker (void) close(frontFd);
223*b9df5ad1SAndroid Build Coastguard Worker (void) close(rearFd);
224*b9df5ad1SAndroid Build Coastguard Worker (void) close(dataFd);
225*b9df5ad1SAndroid Build Coastguard Worker
226*b9df5ad1SAndroid Build Coastguard Worker return EXIT_SUCCESS;
227*b9df5ad1SAndroid Build Coastguard Worker }
228