fifo_multiprocess.cpp 7.9 KB

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