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