123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- /*++
- Copyright (c) 2016 Minoca Corp. All Rights Reserved
- Module Name:
- aiotest.c
- Abstract:
- This module implements the asynchronous I/O test suite.
- Author:
- Evan Green 27-Jun-2016
- Environment:
- User
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <poll.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <minoca/lib/types.h>
- //
- // --------------------------------------------------------------------- Macros
- //
- #define ERROR(...) fprintf(stderr, __VA_ARGS__)
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- ULONG
- TestAioRun (
- VOID
- );
- ULONG
- TestAioExecute (
- int Pipe[2]
- );
- void
- TestAioSigioHandler (
- int Signal,
- siginfo_t *Information,
- void *Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- ULONG TestAioSignalCount;
- //
- // ------------------------------------------------------------------ Functions
- //
- int
- main (
- int ArgumentCount,
- char **Arguments
- )
- /*++
- Routine Description:
- This routine implements the signal test program.
- Arguments:
- ArgumentCount - Supplies the number of elements in the arguments array.
- Arguments - Supplies an array of strings. The array count is bounded by the
- previous parameter, and the strings are null-terminated.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- ULONG Failures;
- Failures = TestAioRun();
- if (Failures == 0) {
- return 0;
- }
- ERROR("*** %u failures in async I/O test. ***\n", Failures);
- return 1;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- ULONG
- TestAioRun (
- VOID
- )
- /*++
- Routine Description:
- This routine runs all asynchronous I/O tests.
- Arguments:
- None.
- Return Value:
- 0 on success.
- Returns the number of errors on failure.
- --*/
- {
- struct sigaction Action;
- ULONG Failures;
- struct sigaction OldAction;
- int Pipe[2];
- int Status;
- Failures = 0;
- memset(&Action, 0, sizeof(Action));
- Action.sa_sigaction = TestAioSigioHandler;
- Action.sa_flags = SA_SIGINFO;
- TestAioSignalCount = 0;
- sigaction(SIGIO, &Action, &OldAction);
- Status = pipe(Pipe);
- if (Status != 0) {
- ERROR("Failed to create pipe.\n");
- Failures += 1;
- goto TestAioRunEnd;
- }
- Failures += TestAioExecute(Pipe);
- Status = socketpair(AF_UNIX, SOCK_STREAM, 0, Pipe);
- if (Status != 0) {
- ERROR("Failed to create socketpair.\n");
- Failures += 1;
- goto TestAioRunEnd;
- }
- Failures += TestAioExecute(Pipe);
- TestAioRunEnd:
- sigaction(SIGIO, &OldAction, NULL);
- return Failures;
- }
- ULONG
- TestAioExecute (
- int Pipe[2]
- )
- /*++
- Routine Description:
- This routine executes the asynchronous tests.
- Arguments:
- Pipe - Supplies the pair of descriptors to use for testing. This routine
- will close these descriptors.
- Return Value:
- 0 on success.
- Returns the number of errors on failure.
- --*/
- {
- int Count;
- char Buf[3];
- ULONG Failures;
- int Flags;
- pid_t Pid;
- if (TestAioSignalCount != 0) {
- Failures += TestAioSignalCount;
- ERROR("Unexpected signals before test\n");
- Failures += TestAioSignalCount;
- TestAioSignalCount = 0;
- }
- //
- // Enable SIGIO for both the read and write side. Use the fcntl method
- // for one and the ioctl for the other, and verify both.
- //
- Failures = 0;
- Pid = getpid();
- if ((fcntl(Pipe[0], F_SETOWN, Pid) != 0) ||
- (fcntl(Pipe[1], F_SETOWN, Pid) != 0) ||
- (fcntl(Pipe[0], F_GETOWN) != Pid) ||
- (fcntl(Pipe[1], F_GETOWN) != Pid)) {
- ERROR("Failed to F_SETOWN.\n");
- Failures += 1;
- goto TestAioExecuteEnd;
- }
- //
- // Reading a writing now should still not generate a signal.
- //
- write(Pipe[1], "o", 1);
- read(Pipe[0], Buf, 1);
- if (TestAioSignalCount != 0) {
- Failures += TestAioSignalCount;
- ERROR("Signals generated before O_ASYNC is set.\n");
- Failures += TestAioSignalCount;
- TestAioSignalCount = 0;
- }
- Flags = fcntl(Pipe[1], F_GETFL);
- if (Flags < 0) {
- ERROR("Failed to F_GETFL.\n");
- Failures += 1;
- goto TestAioExecuteEnd;
- }
- Flags |= O_ASYNC | O_NONBLOCK;
- if (fcntl(Pipe[1], F_SETFL, Flags) != 0) {
- ERROR("Failed to F_SETFL.\n");
- Failures += 1;
- goto TestAioExecuteEnd;
- }
- Flags = 1;
- if (ioctl(Pipe[0], FIOASYNC, &Flags) != 0) {
- ERROR("Failed to ioctl.\n");
- Failures += 1;
- goto TestAioExecuteEnd;
- }
- Flags = fcntl(Pipe[0], F_GETFL);
- if ((Flags < 0) || ((Flags & O_ASYNC) == 0)) {
- ERROR("Failed to get flags: %x\n", Flags);
- Failures += 1;
- goto TestAioExecuteEnd;
- }
- Flags = fcntl(Pipe[1], F_GETFL);
- if ((Flags < 0) || ((Flags & O_ASYNC) == 0)) {
- ERROR("Failed to get flags 2: %x\n", Flags);
- Failures += 1;
- goto TestAioExecuteEnd;
- }
- //
- // Simply turning async I/O on should not trigger an edge.
- //
- if (TestAioSignalCount != 0) {
- Failures += TestAioSignalCount;
- ERROR("Signals sent while turing AIO on.\n");
- Failures += TestAioSignalCount;
- TestAioSignalCount = 0;
- }
- //
- // Write something to generate a read edge.
- //
- write(Pipe[1], "123", 3);
- read(Pipe[0], Buf, 2);
- read(Pipe[0], Buf, 1);
- if (TestAioSignalCount != 1) {
- ERROR("Failed basic read AIO signal.\n");
- Failures += 1;
- }
- TestAioSignalCount = 0;
- //
- // Fill the buffer.
- //
- Count = 0;
- while (write(Pipe[1], "x", 1) == 1) {
- Count += 1;
- }
- //
- // This should generate a read edge.
- //
- if (TestAioSignalCount != 1) {
- ERROR("Failed basic read AIO signal 2.\n");
- Failures += 1;
- }
- TestAioSignalCount = 0;
- //
- // Reading a character should generate a write edge.
- //
- read(Pipe[0], Buf, 1);
- Count -= 1;
- if (TestAioSignalCount != 1) {
- ERROR("Failed basic write AIO signal.\n");
- Failures += 1;
- }
- TestAioSignalCount = 0;
- //
- // Read the rest of the characters.
- //
- while (Count != 0) {
- if (read(Pipe[0], Buf, 1) != 1) {
- ERROR("Failed read.\n");
- Failures += 1;
- }
- Count -= 1;
- }
- //
- // There should be no more signals just from draining buffer.
- //
- if (TestAioSignalCount != 0) {
- ERROR("Got extra AIO signals.\n");
- Failures += 1;
- TestAioSignalCount = 0;
- }
- TestAioExecuteEnd:
- Flags = 0;
- if ((ioctl(Pipe[0], FIOASYNC, &Flags) != 0) ||
- (ioctl(Pipe[1], FIOASYNC, &Flags) != 0)) {
- ERROR("Failed to clear async.\n");
- Failures += 1;
- }
- if (TestAioSignalCount != 0) {
- ERROR("Got extra AIO while disabling async.\n");
- Failures += 1;
- TestAioSignalCount = 0;
- }
- close(Pipe[0]);
- close(Pipe[1]);
- if (TestAioSignalCount != 0) {
- ERROR("Got extra AIO while closing.\n");
- Failures += 1;
- TestAioSignalCount = 0;
- }
- return Failures;
- }
- void
- TestAioSigioHandler (
- int Signal,
- siginfo_t *Information,
- void *Context
- )
- /*++
- Routine Description:
- This routine is called when an I/O signal comes in.
- Arguments:
- Signal - Supplies the signal that occurred. This should always be SIGIO.
- Information - Supplies a pointer to the signal information.
- Context - Supplies an unused context pointer.
- Return Value:
- None.
- --*/
- {
- assert(Signal == SIGIO);
- TestAioSignalCount += 1;
- return;
- }
|