19
19
#import < CFNetwork/CFNetwork.h>
20
20
#endif
21
21
22
- #import < mach/mach.h>
23
-
24
22
#import < arpa/inet.h>
25
23
#import < fcntl.h>
26
24
#import < ifaddrs.h>
@@ -265,10 +263,28 @@ + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
265
263
#pragma mark -
266
264
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
267
265
268
- @interface GCDAsyncSocketRingBuffer : NSObject
266
+ /* *
267
+ * A PreBuffer is used when there is more data available on the socket
268
+ * than is being requested by current read request.
269
+ * In this case we slurp up all data from the socket (to minimize sys calls),
270
+ * and store additional yet unread data in a "prebuffer".
271
+ *
272
+ * The prebuffer is entirely drained before we read from the socket again.
273
+ * In other words, a large chunk of data is written is written to the prebuffer.
274
+ * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)).
275
+ *
276
+ * A ring buffer was once used for this purpose.
277
+ * But a ring buffer takes up twice as much memory as needed (double the size for mirroring).
278
+ * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size.
279
+ * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed.
280
+ *
281
+ * The current design is very simple and straight-forward, while also keeping memory requirements lower.
282
+ **/
283
+
284
+ @interface GCDAsyncSocketPreBuffer : NSObject
269
285
{
270
- uint8_t *ringBuffer ;
271
- size_t ringBufferSize ;
286
+ uint8_t *preBuffer ;
287
+ size_t preBufferSize ;
272
288
273
289
uint8_t *readPointer;
274
290
uint8_t *writePointer;
@@ -295,127 +311,46 @@ - (void)reset;
295
311
296
312
@end
297
313
298
- @implementation GCDAsyncSocketRingBuffer
299
-
300
- static void allocate_ring_buffer (uint8_t **ringBufferPtr, size_t ringBufferSize)
301
- {
302
- uint8_t *ringBuffer = NULL ;
303
-
304
- do
305
- {
306
- kern_return_t result;
307
-
308
- vm_address_t buffer;
309
- vm_size_t bufferSize = ringBufferSize;
310
-
311
- result = vm_allocate (mach_task_self (), &buffer, (bufferSize*2 ), VM_FLAGS_ANYWHERE);
312
- if (result != ERR_SUCCESS)
313
- {
314
- LogCError (@" vm_allocate error: %d " , result);
315
-
316
- continue ;
317
- }
318
-
319
- result = vm_deallocate (mach_task_self (), (buffer+bufferSize), bufferSize);
320
- if (result != ERR_SUCCESS)
321
- {
322
- LogCError (@" vm_deallocate error: %d " , result);
323
-
324
- vm_deallocate (mach_task_self (), buffer, (bufferSize*2 ));
325
- continue ;
326
- }
327
-
328
- vm_address_t bufferMirror = buffer + bufferSize;
329
- vm_prot_t cur_protection;
330
- vm_prot_t max_protection;
331
-
332
- result = vm_remap (mach_task_self (),
333
- &bufferMirror, // target address
334
- bufferSize, // target address size
335
- 0 , // target address alignment mask
336
- FALSE , // target address placement indicator
337
- mach_task_self (),
338
- buffer, // source address
339
- 0 , // copy
340
- &cur_protection, // unused
341
- &max_protection, // unused
342
- VM_INHERIT_DEFAULT);
343
-
344
- if (result != ERR_SUCCESS)
345
- {
346
- // Race condition we're prepared for.
347
- // This may occasionally happen, which is why we do this in a loop.
348
- LogCInfo (@" vm_remap error: %d " , result);
349
-
350
- vm_deallocate (mach_task_self (), buffer, bufferSize);
351
- }
352
- else
353
- {
354
- ringBuffer = (uint8_t *)buffer;
355
- }
356
-
357
-
358
- } while (ringBuffer == NULL );
359
-
360
- *ringBufferPtr = ringBuffer;
361
- }
314
+ @implementation GCDAsyncSocketPreBuffer
362
315
363
316
- (id )initWithCapacity : (size_t )numBytes
364
317
{
365
318
if ((self = [super init ]))
366
319
{
367
- // Round up to nearest vm_page_size
368
- ringBufferSize = round_page (numBytes);
369
-
370
- allocate_ring_buffer (&ringBuffer, ringBufferSize);
320
+ preBufferSize = numBytes;
321
+ preBuffer = malloc (preBufferSize);
371
322
372
- readPointer = ringBuffer ;
373
- writePointer = ringBuffer ;
323
+ readPointer = preBuffer ;
324
+ writePointer = preBuffer ;
374
325
}
375
326
return self;
376
327
}
377
328
378
329
- (void )dealloc
379
330
{
380
- kern_return_t result =
381
- vm_deallocate (mach_task_self (), (vm_address_t )ringBuffer, (vm_size_t )(ringBufferSize*2 ));
382
-
383
- if (result != ERR_SUCCESS)
384
- {
385
- LogError (@" vm_deallocate error: %d " , result);
386
- }
331
+ if (preBuffer)
332
+ free (preBuffer);
387
333
}
388
334
389
335
- (void )ensureCapacityForWrite : (size_t )numBytes
390
336
{
391
- size_t availableSpace = ringBufferSize - (writePointer - readPointer);
337
+ size_t availableSpace = preBufferSize - (writePointer - readPointer);
392
338
393
339
if (numBytes > availableSpace)
394
340
{
395
341
size_t additionalBytes = numBytes - availableSpace;
396
342
397
- uint8_t *newRingBuffer = NULL ;
398
- size_t newRingBufferSize = round_page (ringBufferSize + additionalBytes);
399
-
400
- allocate_ring_buffer (&newRingBuffer, newRingBufferSize);
343
+ size_t newPreBufferSize = preBufferSize + additionalBytes;
344
+ uint8_t *newPreBuffer = realloc (preBuffer, newPreBufferSize);
401
345
402
- size_t availableBytes = writePointer - readPointer;
346
+ size_t readPointerOffset = readPointer - preBuffer;
347
+ size_t writePointerOffset = writePointer - preBuffer;
403
348
404
- memcpy ((void *)newRingBuffer, (const void *)readPointer, (unsigned long )(availableBytes));
349
+ preBuffer = newPreBuffer;
350
+ preBufferSize = newPreBufferSize;
405
351
406
- kern_return_t result =
407
- vm_deallocate (mach_task_self (), (vm_address_t )ringBuffer, (vm_size_t )(ringBufferSize*2 ));
408
-
409
- if (result != ERR_SUCCESS)
410
- {
411
- LogError (@" vm_deallocate error: %d " , result);
412
- }
413
-
414
- ringBuffer = newRingBuffer;
415
- ringBufferSize = newRingBufferSize;
416
-
417
- readPointer = ringBuffer;
418
- writePointer = ringBuffer + availableBytes;
352
+ readPointer = preBuffer + readPointerOffset;
353
+ writePointer = preBuffer + writePointerOffset;
419
354
}
420
355
}
421
356
@@ -435,9 +370,21 @@ - (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBy
435
370
if (availableBytesPtr) *availableBytesPtr = writePointer - readPointer;
436
371
}
437
372
373
+ - (void )didRead : (size_t )bytesRead
374
+ {
375
+ readPointer += bytesRead;
376
+
377
+ if (readPointer == writePointer)
378
+ {
379
+ // The prebuffer has been drained. Reset pointers.
380
+ readPointer = preBuffer;
381
+ writePointer = preBuffer;
382
+ }
383
+ }
384
+
438
385
- (size_t )availableSpace
439
386
{
440
- return ringBufferSize - (writePointer - readPointer);
387
+ return preBufferSize - (writePointer - readPointer);
441
388
}
442
389
443
390
- (uint8_t *)writeBuffer
@@ -448,18 +395,7 @@ - (uint8_t *)writeBuffer
448
395
- (void )getWriteBuffer : (uint8_t **)bufferPtr availableSpace : (size_t *)availableSpacePtr
449
396
{
450
397
if (bufferPtr) *bufferPtr = writePointer;
451
- if (availableSpacePtr) *availableSpacePtr = ringBufferSize - (writePointer - readPointer);
452
- }
453
-
454
- - (void )didRead : (size_t )bytesRead
455
- {
456
- readPointer += bytesRead;
457
-
458
- if (readPointer >= (ringBuffer + ringBufferSize))
459
- {
460
- readPointer -= ringBufferSize;
461
- writePointer -= ringBufferSize;
462
- }
398
+ if (availableSpacePtr) *availableSpacePtr = preBufferSize - (writePointer - readPointer);
463
399
}
464
400
465
401
- (void )didWrite : (size_t )bytesWritten
@@ -469,8 +405,8 @@ - (void)didWrite:(size_t)bytesWritten
469
405
470
406
- (void )reset
471
407
{
472
- readPointer = ringBuffer ;
473
- writePointer = ringBuffer ;
408
+ readPointer = preBuffer ;
409
+ writePointer = preBuffer ;
474
410
}
475
411
476
412
@end
@@ -514,7 +450,7 @@ - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuf
514
450
515
451
- (NSUInteger )readLengthForNonTermWithHint : (NSUInteger )bytesAvailable ;
516
452
- (NSUInteger )readLengthForTermWithHint : (NSUInteger )bytesAvailable shouldPreBuffer : (BOOL *)shouldPreBufferPtr ;
517
- - (NSUInteger )readLengthForTermWithPreBuffer : (GCDAsyncSocketRingBuffer *)preBuffer found : (BOOL *)foundPtr ;
453
+ - (NSUInteger )readLengthForTermWithPreBuffer : (GCDAsyncSocketPreBuffer *)preBuffer found : (BOOL *)foundPtr ;
518
454
519
455
- (NSInteger )searchForTermAfterPreBuffering : (ssize_t )numBytes ;
520
456
@@ -778,7 +714,7 @@ - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuff
778
714
*
779
715
* It is assumed the terminator has not already been read.
780
716
**/
781
- - (NSUInteger )readLengthForTermWithPreBuffer : (GCDAsyncSocketRingBuffer *)preBuffer found : (BOOL *)foundPtr
717
+ - (NSUInteger )readLengthForTermWithPreBuffer : (GCDAsyncSocketPreBuffer *)preBuffer found : (BOOL *)foundPtr
782
718
{
783
719
NSAssert (term != nil , @" This method does not apply to non-term reads" );
784
720
NSAssert ([preBuffer availableBytes ] > 0 , @" Invoked with empty pre buffer!" );
@@ -1070,7 +1006,7 @@ - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQu
1070
1006
writeQueue = [[NSMutableArray alloc ] initWithCapacity: 5 ];
1071
1007
currentWrite = nil ;
1072
1008
1073
- preBuffer = [[GCDAsyncSocketRingBuffer alloc ] initWithCapacity: vm_page_size ];
1009
+ preBuffer = [[GCDAsyncSocketPreBuffer alloc ] initWithCapacity: ( 1024 * 4 ) ];
1074
1010
}
1075
1011
return self;
1076
1012
}
0 commit comments