Last active
May 24, 2016 08:41
-
-
Save keithduncan/e502aeec97a988fb04b6 to your computer and use it in GitHub Desktop.
Various options for streaming from the read end of a pipe until EOF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
pipe_source.m | |
clang pipe_source.m -o pipe -framework Foundation -D [ USE_SOURCE | USE_IO | USE_FILEHANDLE [ FILEHANDLE_READABILITY | FILEHANDLE_WAIT ] ] | |
*/ | |
#import <Foundation/Foundation.h> | |
int main(void) { | |
enum RunLoop { | |
Dispatch, | |
RunLoop, | |
} runLoop = Dispatch; | |
int filedes[2]; | |
int pipeError = pipe(filedes); | |
if (pipeError != 0) { | |
fprintf(stderr, "couldn't create pipe, error: %d\n", errno); | |
return 1; | |
} | |
int readFd = filedes[0], writeFd = filedes[1]; | |
/// | |
// Read Strategy | |
#if defined(USE_SOURCE) | |
dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, readFd, 0, dispatch_get_main_queue()); | |
dispatch_source_set_cancel_handler(readSource, ^{ | |
fprintf(stderr, "closing read fd\n"); | |
close(readFd); | |
}); | |
dispatch_source_set_event_handler(readSource, ^{ | |
uint8_t buffer[1024]; | |
int readCount = read(readFd, buffer, sizeof(buffer)); | |
fprintf(stderr, "read %d bytes\n", readCount); | |
bool done = (readCount == 0); | |
if (done) { | |
fprintf(stderr, "EOF encountered\n"); | |
dispatch_source_cancel(readSource); | |
exit(0); | |
} | |
}); | |
dispatch_resume(readSource); | |
#elif defined(USE_IO) | |
dispatch_io_t readChannel = dispatch_io_create(DISPATCH_IO_STREAM, readFd, dispatch_get_main_queue(), ^(int error) { | |
close(readFd); | |
}); | |
dispatch_io_set_interval(readChannel, NSEC_PER_SEC / 2, DISPATCH_IO_STRICT_INTERVAL); | |
__block int readCount = 0; | |
dispatch_io_read(readChannel, 0, SIZE_MAX, dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) { | |
fprintf(stderr, "readCount: %d done: %d dataSize: %ld error: %d\n", ++readCount, done, dispatch_data_get_size(data), error); | |
if (done) { | |
fprintf(stderr, "EOF encountered\n"); | |
dispatch_io_close(readChannel, 0); | |
exit(0); | |
} | |
}); | |
#elif defined(USE_FILEHANDLE) | |
NSFileHandle *readHandle = [[NSFileHandle alloc] initWithFileDescriptor:readFd closeOnDealloc:YES]; | |
#if defined(FILEHANDLE_READABILITY) | |
// EOF is not encountered | |
readHandle.readabilityHandler = ^(NSFileHandle *readHandle) { | |
int readCount = readHandle.availableData.length; | |
fprintf(stderr, "read %d bytes\n", readCount); | |
bool done = (readCount == 0); | |
if (done) { | |
fprintf(stderr, "EOF encountered\n"); | |
exit(0); | |
} | |
}; | |
#elif defined(FILEHANDLE_WAIT) | |
// EOF is encountered | |
id readObserver = [NSNotificationCenter.defaultCenter addObserverForName:NSFileHandleDataAvailableNotification object:readHandle queue:NSOperationQueue.mainQueue usingBlock:^(NSNotification *notification) { | |
int readCount = readHandle.availableData.length; | |
fprintf(stderr, "read %d bytes\n", readCount); | |
bool done = (readCount == 0); | |
if (done) { | |
fprintf(stderr, "EOF encountered\n"); | |
exit(0); | |
} | |
[readHandle waitForDataInBackgroundAndNotify]; | |
}]; | |
[readHandle waitForDataInBackgroundAndNotify]; | |
#else | |
#error no file handle strategy defined | |
#endif | |
runLoop = RunLoop; | |
#else | |
#error no read strategy defined | |
#endif | |
/// | |
// Write | |
char *const output = "Hello, world."; | |
write(writeFd, output, 6); | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
write(writeFd, output + 6, 7); | |
close(writeFd); | |
}); | |
/// | |
// Event Loop | |
switch (runLoop) { | |
case Dispatch: | |
dispatch_main(); | |
case RunLoop: | |
[NSRunLoop.currentRunLoop run]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment