Skip to content

Instantly share code, notes, and snippets.

@keithduncan
Last active May 24, 2016 08:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save keithduncan/e502aeec97a988fb04b6 to your computer and use it in GitHub Desktop.
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
/*
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