#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include <dispatch/dispatch.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <IOKit/serial/ioss.h>
#include "IOSerialTestLib.h"
int _testIOSSIOSPEEDIoctl(int fd, speed_t speed);
int _modifyAttributes(int fd, struct termios *originalOptions);
int _modifyModemLines(int fd);
void _sleepAndReenumerate(const char *deviceid, struct timespec tim);
void _sleepAndClose(int fd, struct timespec tim);
void _sleepAndWrite(int fd, struct timespec tim);
void _sleepAndRead(int fd, struct timespec tim);
int _openAndClose(const char *path);
#pragma mark -
int _testIOSSIOSPEEDIoctl(int fd, speed_t speed)
{
struct termios options;
if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
printf("[WARN] ioctl(..., IOSSIOSPEED, %lu).\n", speed);
goto fail;
}
if (tcgetattr(fd, &options) == -1) {
printf("[WARN] _modifyAttributes: tcgetattr failed\n");
goto fail;
}
if (cfgetispeed(&options) != speed ||
cfgetospeed(&options) != speed) {
printf("[WARN] _modifyAttributes: cfsetspeed failed, %lu, %lu.\n",
speed,
cfgetispeed(&options));
goto fail;
}
return 0;
fail:
return -1;
}
int _modifyAttributes(int fd, struct termios *originalOptions)
{
int result = 0;
unsigned long mics = 1UL;
struct termios options;
if (!originalOptions) {
printf("[FAIL] _modifyAttributes: NULL argument unexpected\n");
goto fail;
}
if (ioctl(fd, TIOCEXCL) == -1) {
printf("[FAIL] _modifyAttributes: ioctl TIOCEXCL failed\n");
goto fail;
}
if (fcntl(fd, F_SETFL, 0) == -1) {
printf("[FAIL] _modifyAttributes: fcntl failed\n");
goto fail;
}
if (tcgetattr(fd, originalOptions) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
goto fail;
}
options = *originalOptions;
cfmakeraw(&options);
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
if (cfsetspeed(&options, B19200) == -1) {
printf("[FAIL] _modifyAttributes: cfsetspeed failed\n");
goto fail;
}
options.c_cflag |= (CS7 | PARENB | CCTS_OFLOW | CRTS_IFLOW);
if (tcsetattr(fd, TCSANOW, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcsetattr failed\n");
goto fail;
}
if (tcgetattr(fd, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
goto fail;
}
if ((options.c_cflag & (CS7 | PARENB | CCTS_OFLOW | CRTS_IFLOW)) !=
(CS7 | PARENB | CCTS_OFLOW | CRTS_IFLOW)) {
printf("[FAIL] _modifyAttributes: tcsetattr/tcgetattr failed\n");
goto fail;
}
if (cfgetispeed(&options) != B19200 ||
cfgetospeed(&options) != B19200) {
printf("[FAIL] _modifyAttributes: cfsetspeed failed\n");
goto fail;
}
if (ioctl(fd, IOSSDATALAT, &mics) == -1) {
printf("[FAIL] _modifyAttributes: ioctl IOSSDATALAT failed\n");
goto fail;
}
return result;
fail:
return -1;
}
int _modifyModemLines(int fd)
{
int handshake;
if (ioctl(fd, TIOCSDTR) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCSDTR failed\n");
goto fail;
}
if (ioctl(fd, TIOCCDTR) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCCDTR failed\n");
goto fail;
}
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
if (ioctl(fd, TIOCMSET, &handshake) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCMSET failed\n");
goto fail;
}
if (ioctl(fd, TIOCMGET, &handshake) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCMGET failed\n");
goto fail;
}
return 0;
fail:
return -1;
}
inline void _sleepAndReenumerate(const char *deviceid, struct timespec tim)
{
struct timespec tim2;
nanosleep(&tim, &tim2);
execlp("/AppleInternal/Applications/USB Prober.app/Contents/Resources/reenumerate",
"reenumerate", "-v", deviceid,
NULL);
}
inline void _sleepAndClose(int fd, struct timespec tim)
{
struct timespec tim2;
int result = 0;
nanosleep(&tim, &tim2);
printf("closing\n");
result = close(fd);
if (result) {
printf("close failed\n");
return;
}
printf("closed\n");
}
inline void _sleepAndWrite(int fd, struct timespec tim)
{
struct timespec tim2;
int result = 0;
ssize_t numBytes;
nanosleep(&tim, &tim2);
printf("writing\n");
numBytes = write(fd, "Hello World", strnlen("Hello World", 256));
if (numBytes == -1) {
printf("write returned -1\n");
}
else if ((size_t)numBytes < strnlen("Hello World", 256)) {
printf("write did not complete\n");
}
printf("write returned %zd\n", numBytes);
printf("closing\n");
result = close(fd);
if (result) {
printf("close failed\n");
return;
}
printf("closed\n");
}
inline void _sleepAndRead(int fd, struct timespec tim)
{
struct timespec tim2;
int result = 0;
ssize_t numBytes;
char *string;
string = malloc(11 *sizeof(char));
if (!string) {
printf("malloc failed\n");
return;
}
nanosleep(&tim, &tim2);
printf("reading\n");
numBytes = read(fd, string, 11);
if (numBytes == -1) {
printf("read returned -1\n");
}
else {
if ((size_t)numBytes < 11) {
printf("read did not complete\n");
}
printf("read returned %zd\n", numBytes);
}
printf("closing\n");
result = close(fd);
if (result) {
printf("close failed\n");
goto finish;
}
printf("closed\n");
finish:
if (string) {
free(string);
}
}
inline int _openAndClose(const char *path)
{
int fd = -1;
int result = 0;
printf("opening\n");
fd = open(path, O_RDWR|O_NONBLOCK);
if (fd == -1) {
printf("open failed\n");
return -1;
}
printf("opened\n");
sleep(3);
printf("closing\n");
result = close(fd);
if (result) {
printf("close failed\n");
return -1;
}
printf("closed\n");
return 0;
}
#pragma mark -
int testOpenClose(const char *path)
{
int fd = -1;
int result = 0;
fd = open(path, O_RDWR|O_NONBLOCK);
if (fd == -1) {
return -1;
}
result = close(fd);
if (result) {
return -1;
}
return 0;
}
int testModifyConfig(const char *path)
{
int fd = -1;
int result = 0;
speed_t speed;
struct termios originalTTYAttrs;
fd = open(path, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd == -1) {
printf("[FAIL] testModifyConfig: open failed\n");
goto fail;
}
if (_modifyAttributes(fd, &originalTTYAttrs)) {
printf("[FAIL] testModifyConfig: config failed\n");
goto fail;
}
if (_modifyModemLines(fd)) {
printf("[FAIL] testModifyConfig: config failed\n");
goto fail;
}
speed = 40000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 58000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 250000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 10400;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 8192;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 128000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 31250;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 38400;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[FAIL] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
goto fail;
}
speed = 115200;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[FAIL] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
goto fail;
}
speed = 19200;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[FAIL] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
goto fail;
}
tcsetattr(fd, TCSANOW, &originalTTYAttrs);
result = close(fd);
if (result == -1) {
printf("[FAIL] testModifyConfig: close failed\n");
goto fail;
}
return 0;
fail:
if (fd != -1) close(fd);
return -1;
}
#define kHelloWorldString "Hello World"
int testReadWrite(const char *readPath, const char *writePath, const char *message)
{
int readFd = -1;
int writeFd = -1;
int result = 0;
ssize_t numBytes;
char myMessage[256];
char buffer[256]; char *bufPtr;
struct termios originalReadTTYAttrs;
struct termios originalWriteTTYAttrs;
if (!message) {
if (strlcpy(myMessage, kHelloWorldString, sizeof(myMessage)) >=
sizeof(myMessage)) {
myMessage[sizeof(myMessage)-1] = '\0';
}
}
else {
if (strlcpy(myMessage, message, sizeof(myMessage)) >= sizeof(myMessage)) {
myMessage[sizeof(myMessage)-1] = '\0';
}
}
readFd = open(readPath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (readFd == -1) {
printf("[FAIL] testReadWrite: open failed\n");
goto fail;
}
if (_modifyAttributes(readFd, &originalReadTTYAttrs)) {
printf("[FAIL] testReadWrite: _modifyAttributes failed\n");
goto fail;
}
writeFd = open(writePath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (writeFd == -1) {
printf("[FAIL] testReadWrite: open failed\n");
goto fail;
}
if (_modifyAttributes(writeFd, &originalWriteTTYAttrs)) {
printf("[FAIL] testReadWrite: _modifyAttributes failed\n");
goto fail;
}
if (_modifyModemLines(readFd) ||
_modifyModemLines(writeFd)) {
printf("[FAIL] testReadWrite: _modifyModemLines failed\n");
goto fail;
}
numBytes = write(writeFd, myMessage, strnlen(myMessage, 256));
if (numBytes == -1) {
printf("[FAIL] write returned -1\n");
goto fail;
}
if ((size_t)numBytes < strnlen(myMessage, 256)) {
printf("[FAIL] write did not complete\n");
goto fail;
}
memset(buffer, 0, sizeof(buffer));
bufPtr = buffer;
do {
numBytes = read(readFd, bufPtr, &buffer[sizeof(buffer)] - bufPtr - 1);
if (numBytes > 0) {
bufPtr += numBytes;
if (*(bufPtr - 1) == '\n' || *(bufPtr - 1) == '\r') {
break;
}
}
} while (numBytes > 0);
if (strncmp(buffer, myMessage, sizeof(myMessage))) {
printf("[FAIL] testReadWrite: read string was: \"%s\", "
"expected: \"%s\"\n", buffer, myMessage);
goto fail;
}
tcsetattr(readFd, TCSANOW, &originalReadTTYAttrs);
tcsetattr(writeFd, TCSANOW, &originalWriteTTYAttrs);
result = close(readFd);
readFd = -1;
if (result == -1) {
printf("[FAIL] testReadWrite: close failed\n");
goto fail;
}
result = close(writeFd);
writeFd = -1;
if (result == -1) {
printf("[FAIL] testReadWrite: close failed\n");
goto fail;
}
return 0;
fail:
if (readFd != -1) close(readFd);
if (writeFd != -1) close(writeFd);
return -1;
}
int testOpenReenumerate(const char *path, const char *deviceid)
{
int pid;
struct stat file_stat;
int exists = 0;
struct timespec tim[34];
for (int i=0; i<20; i++) {
tim[i].tv_sec = 0;
tim[i].tv_nsec = i*50*1000*1000;
}
for (int i=0; i<14; i++) {
tim[20+i].tv_sec = 1;
tim[20+i].tv_nsec = i*50*1000*1000;
}
int i = 0;
while (1) {
printf(" testOpen: i: %d\n", i);
if (!(exists = stat(path, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
continue;
}
pid = fork();
if (pid == 0) {
_sleepAndReenumerate(deviceid, tim[i]);
}
else if (pid > 0) {
_openAndClose(path);
wait(NULL);
printf("[PASS] testOpen\n");
}
sleep(4);
i++;
if (i >= 34) {
break;
}
}
return 0;
}
int testCloseReenumerate(const char *path, const char *deviceid)
{
int pid;
struct stat file_stat;
int exists = 0;
struct timespec tim[20];
for (int i=0; i<20; i++) {
tim[i].tv_sec = 0;
tim[i].tv_nsec = 25*100*1000 + i*250*1000;
}
int i = 0;
while (1) {
int fd;
printf(" testClose: i: %d\n", i);
if (!(exists = stat(path, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
continue;
}
printf("opening i: %d\n", i);
fd = open(path, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd == -1) {
printf("open failed\n");
return -1;
}
printf("opened\n");
ioctl(fd, TIOCEXCL);
fcntl(fd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(fd, TIOCMSET, &handshake);
pid = fork();
if (pid == 0) {
execlp("/AppleInternal/Applications/USB Prober.app/Contents/Resources/reenumerate",
"reenumerate", "-v", deviceid,
NULL);
}
else if (pid > 0) {
_sleepAndClose(fd, tim[i]);
wait(NULL);
printf("[PASS] testClose\n");
}
sleep(3);
i++;
if (i >= 20) {
break;
}
}
return 0;
}
int testWriteReenumerate(const char *path, const char *deviceid)
{
int pid;
struct stat file_stat;
int exists = 0;
struct timespec tim[24];
for (int i=0; i<24; i++) {
tim[i].tv_sec = 0;
tim[i].tv_nsec = 5*1000*1000 + i*125*1000;
}
int i = 0;
while (1) {
int fd;
printf(" testWrite: i: %d\n", i);
if (!(exists = stat(path, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
continue;
}
printf("opening i: %d\n", i);
fd = open(path, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd == -1) {
printf("open failed\n");
return -1;
}
printf("opened\n");
ioctl(fd, TIOCEXCL);
fcntl(fd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(fd, TIOCMSET, &handshake);
pid = fork();
if (pid == 0) {
execlp("/AppleInternal/Applications/USB Prober.app/Contents/Resources/reenumerate",
"reenumerate", "-v", deviceid,
NULL);
}
else if (pid > 0) {
_sleepAndWrite(fd, tim[i]);
wait(NULL);
printf("[PASS] testWrite\n");
}
sleep(3);
i++;
if (i >= 24) {
break;
}
}
return 0;
}
int testReadReenumerate(const char *writepath, const char *readpath, const char *locationid)
{
int pid;
struct stat file_stat;
int exists = 0;
int writefd;
struct timespec tim[20];
for (int i=0; i<20; i++) {
tim[i].tv_sec = 0;
tim[i].tv_nsec = 3*1000*1000 + i*300*1000;
}
writefd = open(writepath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (writefd == -1) {
printf("open failed: writefd\n");
return -1;
}
ioctl(writefd, TIOCEXCL);
fcntl(writefd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(writefd, TIOCMSET, &handshake);
dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);
int i = 0;
while (1) {
int readfd;
printf(" testRead: i: %d\n", i);
if (!(exists = stat(readpath, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
continue;
}
printf("opening i: %d\n", i);
readfd = open(readpath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (readfd == -1) {
printf("open failed\n");
return -1;
}
printf("opened\n");
ioctl(readfd, TIOCEXCL);
fcntl(readfd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(readfd, TIOCMSET, &handshake);
dispatch_async(queue, ^{
write(writefd, "Hello World", 11);
});
sleep(1);
pid = fork();
if (pid == 0) {
execlp("/AppleInternal/Applications/USB Prober.app/Contents/Resources/reenumerate",
"reenumerate", "-v", "-l", locationid,
NULL);
}
else if (pid > 0) {
_sleepAndRead(readfd, tim[i]);
wait(NULL);
printf("[PASS] testRead\n");
}
sleep(3);
i++;
if (i >= 20) {
break;
}
}
dispatch_barrier_async(queue, ^{
dispatch_suspend(queue);
dispatch_release(queue);
});
return 0;
}
int testWriteClose(const char *path)
{
struct stat file_stat;
int exists = 0;
struct timespec tim[20];
dispatch_queue_t queue;
for (int i=0; i<20; i++) {
tim[i].tv_sec = 0;
tim[i].tv_nsec = i*800;
}
queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
int i = 0;
while (1) {
int fd;
printf(" testWriteClose: i: %d\n", i);
if (!(exists = stat(path, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
continue;
}
printf("opening i: %d\n", i);
fd = open(path, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd == -1) {
printf("[FAIL] open failed\n");
return -1;
}
printf("opened\n");
ioctl(fd, TIOCEXCL);
fcntl(fd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(fd, TIOCMSET, &handshake);
struct termios options;
struct termios originalOptions;
if (tcgetattr(fd, &originalOptions) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
return -1;
}
options = originalOptions;
options.c_cflag |= (CLOCAL);
if (tcsetattr(fd, TCSANOW, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcsetattr failed\n");
return -1;
}
struct timespec tim1 = tim[i];
dispatch_async(queue, ^{
printf("writing\n");
ssize_t numBytes;
numBytes = write(fd, "Hello World", strnlen("Hello World", 256));
if (numBytes == -1) {
printf("write returned -1\n");
return;
}
else if ((size_t)numBytes < strnlen("Hello World", 256)) {
printf("write did not complete\n");
}
printf("write returned %zd\n", numBytes);
});
struct timespec tim2;
nanosleep(&tim1, &tim2);
int result = close(fd);
if (result) {
printf("[FAIL] closing: failed\n");
return -1;
}
printf("closing: closed\n");
sleep(1);
dispatch_sync(queue, ^{
});
i++;
if (i >= 20) {
break;
}
}
dispatch_barrier_async(queue, ^{
dispatch_suspend(queue);
dispatch_release(queue);
});
printf("[PASS] testWriteClose\n");
return 0;
}
int testReadClose(const char *writepath, const char *readpath)
{
struct stat file_stat;
int exists = 0;
int writefd;
struct timespec tim[20];
dispatch_queue_t queue;
for (int i=0; i<20; i++) {
tim[i].tv_sec = 0;
tim[i].tv_nsec = i*3*1000;
}
if (!(exists = stat(writepath, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
return -1;
}
writefd = open(writepath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (writefd == -1) {
printf("[FAIL] open failed\n");
return -1;
}
ioctl(writefd, TIOCEXCL);
fcntl(writefd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(writefd, TIOCMSET, &handshake);
struct termios options;
struct termios originalOptions;
if (tcgetattr(writefd, &originalOptions) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
return -1;
}
options = originalOptions;
options.c_cflag |= (CLOCAL);
if (tcsetattr(writefd, TCSANOW, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcsetattr failed\n");
return -1;
}
queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
int i = 0;
while (1) {
int readfd;
printf(" testReadClose: i: %d\n", i);
if (!(exists = stat(readpath, &file_stat) == 0)) {
printf("file does not exist\n");
sleep(3);
continue;
}
printf("opening i: %d\n", i);
readfd = open(readpath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (readfd == -1) {
printf("[FAIL] open failed\n");
return -1;
}
printf("opened\n");
ioctl(readfd, TIOCEXCL);
fcntl(readfd, F_SETFL, 0);
int handshake;
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
ioctl(readfd, TIOCMSET, &handshake);
struct termios options;
struct termios originalOptions;
if (tcgetattr(readfd, &originalOptions) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
return -1;
}
options = originalOptions;
options.c_cflag |= (CLOCAL);
if (tcsetattr(readfd, TCSANOW, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcsetattr failed\n");
return -1;
}
sleep(1);
dispatch_async(queue, ^{
write(writefd, "Hello World", 11);
});
sleep(1);
dispatch_async(queue, ^{
printf("reading\n");
char buf[20];
ssize_t numBytes;
numBytes = read(readfd, buf, strnlen("Hello World", 256));
if (numBytes == -1) {
printf("read returned -1\n");
return;
}
else if ((size_t)numBytes < strnlen("Hello World", 256)) {
printf("read did not complete\n");
}
printf("read returned %zd\n", numBytes);
});
struct timespec tim1 = tim[i];
struct timespec tim2;
nanosleep(&tim1, &tim2);
int result = close(readfd);
if (result) {
printf("[FAIL] closing: failed\n");
return -1;
}
printf("closing: closed\n");
sleep(1);
dispatch_sync(queue, ^{
});
i++;
if (i >= 20) {
break;
}
}
dispatch_barrier_async(queue, ^{
dispatch_suspend(queue);
dispatch_release(queue);
});
printf("[PASS] testReadClose\n");
return 0;
}