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 31int 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 } 185out: 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