OSDN Git Service

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