• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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