aiotest.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*++
  2. Copyright (c) 2016 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. aiotest.c
  5. Abstract:
  6. This module implements the asynchronous I/O test suite.
  7. Author:
  8. Evan Green 27-Jun-2016
  9. Environment:
  10. User
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <assert.h>
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <poll.h>
  19. #include <signal.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/socket.h>
  24. #include <sys/types.h>
  25. #include <minoca/lib/types.h>
  26. //
  27. // --------------------------------------------------------------------- Macros
  28. //
  29. #define ERROR(...) fprintf(stderr, __VA_ARGS__)
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. //
  37. // ----------------------------------------------- Internal Function Prototypes
  38. //
  39. ULONG
  40. TestAioRun (
  41. VOID
  42. );
  43. ULONG
  44. TestAioExecute (
  45. int Pipe[2]
  46. );
  47. void
  48. TestAioSigioHandler (
  49. int Signal,
  50. siginfo_t *Information,
  51. void *Context
  52. );
  53. //
  54. // -------------------------------------------------------------------- Globals
  55. //
  56. ULONG TestAioSignalCount;
  57. //
  58. // ------------------------------------------------------------------ Functions
  59. //
  60. int
  61. main (
  62. int ArgumentCount,
  63. char **Arguments
  64. )
  65. /*++
  66. Routine Description:
  67. This routine implements the signal test program.
  68. Arguments:
  69. ArgumentCount - Supplies the number of elements in the arguments array.
  70. Arguments - Supplies an array of strings. The array count is bounded by the
  71. previous parameter, and the strings are null-terminated.
  72. Return Value:
  73. 0 on success.
  74. Non-zero on failure.
  75. --*/
  76. {
  77. ULONG Failures;
  78. Failures = TestAioRun();
  79. if (Failures == 0) {
  80. return 0;
  81. }
  82. ERROR("*** %u failures in async I/O test. ***\n", Failures);
  83. return 1;
  84. }
  85. //
  86. // --------------------------------------------------------- Internal Functions
  87. //
  88. ULONG
  89. TestAioRun (
  90. VOID
  91. )
  92. /*++
  93. Routine Description:
  94. This routine runs all asynchronous I/O tests.
  95. Arguments:
  96. None.
  97. Return Value:
  98. 0 on success.
  99. Returns the number of errors on failure.
  100. --*/
  101. {
  102. struct sigaction Action;
  103. ULONG Failures;
  104. struct sigaction OldAction;
  105. int Pipe[2];
  106. int Status;
  107. Failures = 0;
  108. memset(&Action, 0, sizeof(Action));
  109. Action.sa_sigaction = TestAioSigioHandler;
  110. Action.sa_flags = SA_SIGINFO;
  111. TestAioSignalCount = 0;
  112. sigaction(SIGIO, &Action, &OldAction);
  113. Status = pipe(Pipe);
  114. if (Status != 0) {
  115. ERROR("Failed to create pipe.\n");
  116. Failures += 1;
  117. goto TestAioRunEnd;
  118. }
  119. Failures += TestAioExecute(Pipe);
  120. Status = socketpair(AF_UNIX, SOCK_STREAM, 0, Pipe);
  121. if (Status != 0) {
  122. ERROR("Failed to create socketpair.\n");
  123. Failures += 1;
  124. goto TestAioRunEnd;
  125. }
  126. Failures += TestAioExecute(Pipe);
  127. TestAioRunEnd:
  128. sigaction(SIGIO, &OldAction, NULL);
  129. return Failures;
  130. }
  131. ULONG
  132. TestAioExecute (
  133. int Pipe[2]
  134. )
  135. /*++
  136. Routine Description:
  137. This routine executes the asynchronous tests.
  138. Arguments:
  139. Pipe - Supplies the pair of descriptors to use for testing. This routine
  140. will close these descriptors.
  141. Return Value:
  142. 0 on success.
  143. Returns the number of errors on failure.
  144. --*/
  145. {
  146. int Count;
  147. char Buf[3];
  148. ULONG Failures;
  149. int Flags;
  150. pid_t Pid;
  151. if (TestAioSignalCount != 0) {
  152. Failures += TestAioSignalCount;
  153. ERROR("Unexpected signals before test\n");
  154. Failures += TestAioSignalCount;
  155. TestAioSignalCount = 0;
  156. }
  157. //
  158. // Enable SIGIO for both the read and write side. Use the fcntl method
  159. // for one and the ioctl for the other, and verify both.
  160. //
  161. Failures = 0;
  162. Pid = getpid();
  163. if ((fcntl(Pipe[0], F_SETOWN, Pid) != 0) ||
  164. (fcntl(Pipe[1], F_SETOWN, Pid) != 0) ||
  165. (fcntl(Pipe[0], F_GETOWN) != Pid) ||
  166. (fcntl(Pipe[1], F_GETOWN) != Pid)) {
  167. ERROR("Failed to F_SETOWN.\n");
  168. Failures += 1;
  169. goto TestAioExecuteEnd;
  170. }
  171. //
  172. // Reading a writing now should still not generate a signal.
  173. //
  174. write(Pipe[1], "o", 1);
  175. read(Pipe[0], Buf, 1);
  176. if (TestAioSignalCount != 0) {
  177. Failures += TestAioSignalCount;
  178. ERROR("Signals generated before O_ASYNC is set.\n");
  179. Failures += TestAioSignalCount;
  180. TestAioSignalCount = 0;
  181. }
  182. Flags = fcntl(Pipe[1], F_GETFL);
  183. if (Flags < 0) {
  184. ERROR("Failed to F_GETFL.\n");
  185. Failures += 1;
  186. goto TestAioExecuteEnd;
  187. }
  188. Flags |= O_ASYNC | O_NONBLOCK;
  189. if (fcntl(Pipe[1], F_SETFL, Flags) != 0) {
  190. ERROR("Failed to F_SETFL.\n");
  191. Failures += 1;
  192. goto TestAioExecuteEnd;
  193. }
  194. Flags = 1;
  195. if (ioctl(Pipe[0], FIOASYNC, &Flags) != 0) {
  196. ERROR("Failed to ioctl.\n");
  197. Failures += 1;
  198. goto TestAioExecuteEnd;
  199. }
  200. Flags = fcntl(Pipe[0], F_GETFL);
  201. if ((Flags < 0) || ((Flags & O_ASYNC) == 0)) {
  202. ERROR("Failed to get flags: %x\n", Flags);
  203. Failures += 1;
  204. goto TestAioExecuteEnd;
  205. }
  206. Flags = fcntl(Pipe[1], F_GETFL);
  207. if ((Flags < 0) || ((Flags & O_ASYNC) == 0)) {
  208. ERROR("Failed to get flags 2: %x\n", Flags);
  209. Failures += 1;
  210. goto TestAioExecuteEnd;
  211. }
  212. //
  213. // Simply turning async I/O on should not trigger an edge.
  214. //
  215. if (TestAioSignalCount != 0) {
  216. Failures += TestAioSignalCount;
  217. ERROR("Signals sent while turing AIO on.\n");
  218. Failures += TestAioSignalCount;
  219. TestAioSignalCount = 0;
  220. }
  221. //
  222. // Write something to generate a read edge.
  223. //
  224. write(Pipe[1], "123", 3);
  225. read(Pipe[0], Buf, 2);
  226. read(Pipe[0], Buf, 1);
  227. if (TestAioSignalCount != 1) {
  228. ERROR("Failed basic read AIO signal.\n");
  229. Failures += 1;
  230. }
  231. TestAioSignalCount = 0;
  232. //
  233. // Fill the buffer.
  234. //
  235. Count = 0;
  236. while (write(Pipe[1], "x", 1) == 1) {
  237. Count += 1;
  238. }
  239. //
  240. // This should generate a read edge.
  241. //
  242. if (TestAioSignalCount != 1) {
  243. ERROR("Failed basic read AIO signal 2.\n");
  244. Failures += 1;
  245. }
  246. TestAioSignalCount = 0;
  247. //
  248. // Reading a character should generate a write edge.
  249. //
  250. read(Pipe[0], Buf, 1);
  251. Count -= 1;
  252. if (TestAioSignalCount != 1) {
  253. ERROR("Failed basic write AIO signal.\n");
  254. Failures += 1;
  255. }
  256. TestAioSignalCount = 0;
  257. //
  258. // Read the rest of the characters.
  259. //
  260. while (Count != 0) {
  261. if (read(Pipe[0], Buf, 1) != 1) {
  262. ERROR("Failed read.\n");
  263. Failures += 1;
  264. }
  265. Count -= 1;
  266. }
  267. //
  268. // There should be no more signals just from draining buffer.
  269. //
  270. if (TestAioSignalCount != 0) {
  271. ERROR("Got extra AIO signals.\n");
  272. Failures += 1;
  273. TestAioSignalCount = 0;
  274. }
  275. TestAioExecuteEnd:
  276. Flags = 0;
  277. if ((ioctl(Pipe[0], FIOASYNC, &Flags) != 0) ||
  278. (ioctl(Pipe[1], FIOASYNC, &Flags) != 0)) {
  279. ERROR("Failed to clear async.\n");
  280. Failures += 1;
  281. }
  282. if (TestAioSignalCount != 0) {
  283. ERROR("Got extra AIO while disabling async.\n");
  284. Failures += 1;
  285. TestAioSignalCount = 0;
  286. }
  287. close(Pipe[0]);
  288. close(Pipe[1]);
  289. if (TestAioSignalCount != 0) {
  290. ERROR("Got extra AIO while closing.\n");
  291. Failures += 1;
  292. TestAioSignalCount = 0;
  293. }
  294. return Failures;
  295. }
  296. void
  297. TestAioSigioHandler (
  298. int Signal,
  299. siginfo_t *Information,
  300. void *Context
  301. )
  302. /*++
  303. Routine Description:
  304. This routine is called when an I/O signal comes in.
  305. Arguments:
  306. Signal - Supplies the signal that occurred. This should always be SIGIO.
  307. Information - Supplies a pointer to the signal information.
  308. Context - Supplies an unused context pointer.
  309. Return Value:
  310. None.
  311. --*/
  312. {
  313. assert(Signal == SIGIO);
  314. TestAioSignalCount += 1;
  315. return;
  316. }