-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathMAAsyncWriter.m
More file actions
162 lines (130 loc) · 3.24 KB
/
MAAsyncWriter.m
File metadata and controls
162 lines (130 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//
// MAAsyncWriter.m
// MAAsyncIO
//
// Created by Michael Ash on 12/3/10.
// Copyright 2010 Michael Ash. All rights reserved.
//
#import "MAAsyncWriter.h"
#import "MAFDSource.h"
@interface MAAsyncWriter ()
- (void)_write;
@end
@implementation MAAsyncWriter
- (id)initWithFileDescriptor: (int)fd
{
if((self = [self init]))
{
_fdSource = [[MAFDSource alloc] initWithFileDescriptor: fd type: DISPATCH_SOURCE_TYPE_WRITE];
_fd = fd;
__block MAAsyncWriter *weakSelf = self;
[_fdSource setEventCallback: ^{ [weakSelf _write]; }];
_buffer = [[NSMutableData alloc] init];
}
return self;
}
- (void)dealloc
{
[self invalidate];
[super dealloc];
}
- (void)setErrorHandler: (void (^)(int err))block
{
block = [block copy];
[_errorHandler release];
_errorHandler = block;
}
- (void)setTargetQueue: (dispatch_queue_t)queue
{
[_fdSource setTargetQueue: queue];
}
- (void)setDidWriteCallback: (void (^)(void))block
{
block = [block copy];
[_didWriteCallback release];
_didWriteCallback = block;
}
- (void)setEOFCallback: (void (^)(void))block
{
block = [block copy];
[_eofCallback release];
_eofCallback = block;
}
- (void)writeData: (NSData *)data
{
dispatch_async([_fdSource queue], ^{
NSUInteger previousBufferLength = [_buffer length];
[_buffer appendData: data];
if(!previousBufferLength)
{
[self retain]; // keep the object alive until it's done writing
[_fdSource resume];
}
});
}
- (void)writeCString: (const char *)cstr
{
[self writeData: [NSData dataWithBytes: cstr length: strlen(cstr)]];
}
- (NSUInteger)bufferSize
{
return [_buffer length];
}
- (void)invalidate
{
[_fdSource invalidate];
[_fdSource release];
_fdSource = nil;
[_buffer release];
_buffer = nil;
[_errorHandler release];
_errorHandler = nil;
[_didWriteCallback release];
_didWriteCallback = nil;
[_eofCallback release];
_eofCallback = nil;
}
- (void)invalidateWhenEmptyBuffer {
dispatch_async([_fdSource queue], ^{
if([_buffer length] == 0)
[self invalidate];
else
_invalidateWhenEmptyBuffer = YES;
});
}
- (void)_write
{
BOOL emptyBuffer = YES;
if([_buffer length])
{
ssize_t result = write(_fd, [_buffer bytes], [_buffer length]);
NSUInteger didWrite = MAX(result, 0); // -1 (error) means wrote 0 bytes
[_buffer replaceBytesInRange: NSMakeRange(0, didWrite) withBytes: NULL length: 0];
emptyBuffer = ![_buffer length];
if(emptyBuffer)
[_fdSource suspend];
if(result < 0)
{
if(errno != EAGAIN && errno != EINTR)
if(_errorHandler)
_errorHandler(errno);
}
else if(result == 0)
{
if(_eofCallback)
_eofCallback();
}
else
{
if(_didWriteCallback)
_didWriteCallback();
}
}
if(emptyBuffer)
{
if(_invalidateWhenEmptyBuffer)
[self invalidate];
[self release]; // balance the retain in writeData:
}
}
@end