~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to iocore/eventsystem/P_IOBuffer.h

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
4
 
 
5
  @section license License
 
6
 
 
7
  Licensed to the Apache Software Foundation (ASF) under one
 
8
  or more contributor license agreements.  See the NOTICE file
 
9
  distributed with this work for additional information
 
10
  regarding copyright ownership.  The ASF licenses this file
 
11
  to you under the Apache License, Version 2.0 (the
 
12
  "License"); you may not use this file except in compliance
 
13
  with the License.  You may obtain a copy of the License at
 
14
 
 
15
      http://www.apache.org/licenses/LICENSE-2.0
 
16
 
 
17
  Unless required by applicable law or agreed to in writing, software
 
18
  distributed under the License is distributed on an "AS IS" BASIS,
 
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
20
  See the License for the specific language governing permissions and
 
21
  limitations under the License.
 
22
 */
 
23
 
 
24
 
 
25
 
 
26
#if !defined (_P_IOBuffer_h)
 
27
#define _P_IOBuffer_h
 
28
#include "libts.h"
 
29
 
 
30
// TODO: I think we're overly aggressive here on making MIOBuffer 64-bit
 
31
// but not sure it's worthwhile changing anything to 32-bit honestly.
 
32
 
 
33
//////////////////////////////////////////////////////////////
 
34
//
 
35
// returns 0 for DEFAULT_BUFFER_BASE_SIZE,
 
36
// +1 for each power of 2
 
37
//
 
38
//////////////////////////////////////////////////////////////
 
39
TS_INLINE int64_t
 
40
buffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size)
 
41
{
 
42
  int64_t r = max;
 
43
 
 
44
  while (r && BUFFER_SIZE_FOR_INDEX(r - 1) >= size)
 
45
    r--;
 
46
  return r;
 
47
}
 
48
 
 
49
TS_INLINE int64_t
 
50
iobuffer_size_to_index(int64_t size, int64_t max)
 
51
{
 
52
  if (size > BUFFER_SIZE_FOR_INDEX(max))
 
53
    return BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size);
 
54
  return buffer_size_to_index(size, max);
 
55
}
 
56
 
 
57
TS_INLINE int64_t
 
58
index_to_buffer_size(int64_t idx)
 
59
{
 
60
  if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(idx))
 
61
    return BUFFER_SIZE_FOR_INDEX(idx);
 
62
  else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(idx))
 
63
    return BUFFER_SIZE_FOR_XMALLOC(idx);
 
64
  // coverity[dead_error_condition]
 
65
  else if (BUFFER_SIZE_INDEX_IS_CONSTANT(idx))
 
66
    return BUFFER_SIZE_FOR_CONSTANT(idx);
 
67
  // coverity[dead_error_line]
 
68
  return 0;
 
69
}
 
70
 
 
71
TS_INLINE IOBufferBlock *
 
72
iobufferblock_clone(IOBufferBlock * b, int64_t offset, int64_t len)
 
73
{
 
74
 
 
75
  IOBufferBlock *start_buf = NULL;
 
76
  IOBufferBlock *current_buf = NULL;
 
77
 
 
78
  while (b && len >= 0) {
 
79
    char *start = b->_start;
 
80
    char *end = b->_end;
 
81
    int64_t max_bytes = end - start;
 
82
    max_bytes -= offset;
 
83
    if (max_bytes <= 0) {
 
84
      offset = -max_bytes;
 
85
      b = b->next;
 
86
      continue;
 
87
    }
 
88
    int64_t bytes = len;
 
89
    if (bytes >= max_bytes)
 
90
      bytes = max_bytes;
 
91
    IOBufferBlock *new_buf = b->clone();
 
92
    new_buf->_start += offset;
 
93
    new_buf->_buf_end = new_buf->_end = new_buf->_start + bytes;
 
94
    if (!start_buf) {
 
95
      start_buf = new_buf;
 
96
      current_buf = start_buf;
 
97
    } else {
 
98
      current_buf->next = new_buf;
 
99
      current_buf = new_buf;
 
100
    }
 
101
    len -= bytes;
 
102
    b = b->next;
 
103
    offset = 0;
 
104
  }
 
105
  return start_buf;
 
106
}
 
107
 
 
108
TS_INLINE IOBufferBlock *
 
109
iobufferblock_skip(IOBufferBlock * b, int64_t *poffset, int64_t *plen, int64_t write)
 
110
{
 
111
  int64_t offset = *poffset;
 
112
  int64_t len = write;
 
113
  while (b && len >= 0) {
 
114
    int64_t max_bytes = b->read_avail();
 
115
    max_bytes -= offset;
 
116
    if (max_bytes <= 0) {
 
117
      offset = -max_bytes;
 
118
      b = b->next;
 
119
      continue;
 
120
    }
 
121
    if (len >= max_bytes) {
 
122
      b = b->next;
 
123
      len -= max_bytes;
 
124
      offset = 0;
 
125
    } else {
 
126
      offset = offset + len;
 
127
      break;
 
128
    }
 
129
  }
 
130
  *poffset = offset;
 
131
  *plen -= write;
 
132
  return b;
 
133
}
 
134
 
 
135
#ifdef TRACK_BUFFER_USER
 
136
struct Resource;
 
137
extern Resource *res_lookup(const char *path);
 
138
 
 
139
TS_INLINE void
 
140
iobuffer_mem_inc(const char *_loc, int64_t _size_index)
 
141
{
 
142
  if (!res_track_memory)
 
143
    return;
 
144
 
 
145
  if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
 
146
    return;
 
147
 
 
148
  if (!_loc)
 
149
    _loc = "memory/IOBuffer/UNKNOWN-LOCATION";
 
150
  Resource *res = res_lookup(_loc);
 
151
  ink_debug_assert(strcmp(_loc, res->path) == 0);
 
152
#ifdef DEBUG  
 
153
  int64_t r = ink_atomic_increment64(&res->value, index_to_buffer_size(_size_index));
 
154
  ink_debug_assert(r >= 0);
 
155
#else
 
156
  ink_atomic_increment64(&res->value, index_to_buffer_size(_size_index));
 
157
#endif
 
158
}
 
159
 
 
160
TS_INLINE void
 
161
iobuffer_mem_dec(const char *_loc, int64_t _size_index)
 
162
{
 
163
  if (!res_track_memory)
 
164
    return;
 
165
 
 
166
  if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
 
167
    return;
 
168
  if (!_loc)
 
169
    _loc = "memory/IOBuffer/UNKNOWN-LOCATION";
 
170
  Resource *res = res_lookup(_loc);
 
171
  ink_debug_assert(strcmp(_loc, res->path) == 0);
 
172
#ifdef DEBUG  
 
173
  int64_t r = ink_atomic_increment64(&res->value, -index_to_buffer_size(_size_index));
 
174
  ink_debug_assert(r >= index_to_buffer_size(_size_index));
 
175
#else
 
176
  ink_atomic_increment64(&res->value, -index_to_buffer_size(_size_index));
 
177
#endif
 
178
}
 
179
#endif
 
180
 
 
181
//////////////////////////////////////////////////////////////////
 
182
//
 
183
// inline functions definitions
 
184
//
 
185
//////////////////////////////////////////////////////////////////
 
186
//////////////////////////////////////////////////////////////////
 
187
//
 
188
//  class IOBufferData --
 
189
//         inline functions definitions
 
190
//
 
191
//////////////////////////////////////////////////////////////////
 
192
TS_INLINE int64_t
 
193
IOBufferData::block_size()
 
194
{
 
195
  return index_to_buffer_size(_size_index);
 
196
}
 
197
 
 
198
TS_INLINE IOBufferData *
 
199
new_IOBufferData_internal(
 
200
#ifdef TRACK_BUFFER_USER
 
201
                           const char *location,
 
202
#endif
 
203
                           void *b, int64_t size, int64_t asize_index)
 
204
{
 
205
  (void) size;
 
206
  IOBufferData *d = ioDataAllocator.alloc();
 
207
  d->_size_index = asize_index;
 
208
  ink_assert(BUFFER_SIZE_INDEX_IS_CONSTANT(asize_index)
 
209
             || size <= d->block_size());
 
210
#ifdef TRACK_BUFFER_USER
 
211
  d->_location = location;
 
212
#endif
 
213
  d->_data = (char *) b;
 
214
  return d;
 
215
}
 
216
 
 
217
TS_INLINE IOBufferData *
 
218
new_constant_IOBufferData_internal(
 
219
#ifdef TRACK_BUFFER_USER
 
220
                                    const char *loc,
 
221
#endif
 
222
                                    void *b, int64_t size)
 
223
{
 
224
  return new_IOBufferData_internal(
 
225
#ifdef TRACK_BUFFER_USER
 
226
                                    loc,
 
227
#endif
 
228
                                    b, size, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(size));
 
229
}
 
230
 
 
231
TS_INLINE IOBufferData *
 
232
new_xmalloc_IOBufferData_internal(
 
233
#ifdef TRACK_BUFFER_USER
 
234
                                   const char *location,
 
235
#endif
 
236
                                   void *b, int64_t size)
 
237
{
 
238
  return new_IOBufferData_internal(
 
239
#ifdef TRACK_BUFFER_USER
 
240
                                    location,
 
241
#endif
 
242
                                    b, size, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size));
 
243
}
 
244
 
 
245
TS_INLINE IOBufferData *
 
246
new_IOBufferData_internal(
 
247
#ifdef TRACK_BUFFER_USER
 
248
                           const char *location,
 
249
#endif
 
250
                           void *b, int64_t size)
 
251
{
 
252
  return new_IOBufferData_internal(
 
253
#ifdef TRACK_BUFFER_USER
 
254
                                    location,
 
255
#endif
 
256
                                    b, size, iobuffer_size_to_index(size));
 
257
}
 
258
 
 
259
TS_INLINE IOBufferData *
 
260
new_IOBufferData_internal(
 
261
#ifdef TRACK_BUFFER_USER
 
262
                           const char *loc,
 
263
#endif
 
264
                           int64_t size_index, AllocType type)
 
265
{
 
266
  IOBufferData *d = ioDataAllocator.alloc();
 
267
#ifdef TRACK_BUFFER_USER
 
268
  d->_location = loc;
 
269
#endif
 
270
  d->alloc(size_index, type);
 
271
  return d;
 
272
}
 
273
 
 
274
// IRIX has a compiler bug which prevents this function
 
275
// from being compiled correctly at -O3
 
276
// so it is DUPLICATED in IOBuffer.cc
 
277
// ****** IF YOU CHANGE THIS FUNCTION change that one as well.
 
278
TS_INLINE void
 
279
IOBufferData::alloc(int64_t size_index, AllocType type)
 
280
{
 
281
  if (_data)
 
282
    dealloc();
 
283
  _size_index = size_index;
 
284
  _mem_type = type;
 
285
#ifdef TRACK_BUFFER_USER
 
286
  iobuffer_mem_inc(_location, size_index);
 
287
#endif
 
288
  switch (type) {
 
289
  case MEMALIGNED:
 
290
    if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index))
 
291
      _data = (char *) ioBufAllocator[size_index].alloc_void();
 
292
    // coverity[dead_error_condition]
 
293
    else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index))
 
294
      // coverity[dead_error_line]
 
295
      _data = (char *) valloc(index_to_buffer_size(size_index));
 
296
    break;
 
297
  default:
 
298
  case DEFAULT_ALLOC:
 
299
    if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index))
 
300
      _data = (char *) ioBufAllocator[size_index].alloc_void();
 
301
    else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index))
 
302
      _data = (char *) xmalloc(BUFFER_SIZE_FOR_XMALLOC(size_index));
 
303
    break;
 
304
  }
 
305
}
 
306
 
 
307
// ****** IF YOU CHANGE THIS FUNCTION change that one as well.
 
308
 
 
309
 
 
310
TS_INLINE void
 
311
IOBufferData::dealloc()
 
312
{
 
313
#ifdef TRACK_BUFFER_USER
 
314
  iobuffer_mem_dec(_location, _size_index);
 
315
#endif
 
316
  switch (_mem_type) {
 
317
  case MEMALIGNED:
 
318
    if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
 
319
      ioBufAllocator[_size_index].free_void(_data);
 
320
    else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index))
 
321
      ::free((void *) _data);
 
322
    break;
 
323
  default:
 
324
  case DEFAULT_ALLOC:
 
325
    if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index))
 
326
      ioBufAllocator[_size_index].free_void(_data);
 
327
    else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index))
 
328
      xfree(_data);
 
329
    break;
 
330
  }
 
331
  _data = 0;
 
332
  _size_index = BUFFER_SIZE_NOT_ALLOCATED;
 
333
  _mem_type = NO_ALLOC;
 
334
}
 
335
 
 
336
TS_INLINE void
 
337
IOBufferData::free()
 
338
{
 
339
  dealloc();
 
340
  ioDataAllocator.free(this);
 
341
}
 
342
 
 
343
//////////////////////////////////////////////////////////////////
 
344
//
 
345
//  class IOBufferBlock --
 
346
//         inline functions definitions
 
347
//
 
348
//////////////////////////////////////////////////////////////////
 
349
TS_INLINE IOBufferBlock *
 
350
new_IOBufferBlock_internal(
 
351
#ifdef TRACK_BUFFER_USER
 
352
                            const char *location
 
353
#endif
 
354
  )
 
355
{
 
356
  IOBufferBlock *b = ioBlockAllocator.alloc();
 
357
#ifdef TRACK_BUFFER_USER
 
358
  b->_location = location;
 
359
#endif
 
360
  return b;
 
361
}
 
362
 
 
363
TS_INLINE IOBufferBlock *
 
364
new_IOBufferBlock_internal(
 
365
#ifdef TRACK_BUFFER_USER
 
366
                            const char *location,
 
367
#endif
 
368
                            IOBufferData * d, int64_t len, int64_t offset)
 
369
{
 
370
  IOBufferBlock *b = ioBlockAllocator.alloc();
 
371
#ifdef TRACK_BUFFER_USER
 
372
  b->_location = location;
 
373
#endif
 
374
  b->set(d, len, offset);
 
375
  return b;
 
376
}
 
377
 
 
378
TS_INLINE
 
379
IOBufferBlock::IOBufferBlock():
 
380
_start(0),
 
381
_end(0),
 
382
_buf_end(0)
 
383
#ifdef TRACK_BUFFER_USER
 
384
,
 
385
_location(0)
 
386
#endif
 
387
{
 
388
  return;
 
389
}
 
390
 
 
391
TS_INLINE void
 
392
IOBufferBlock::consume(int64_t len)
 
393
{
 
394
  _start += len;
 
395
  ink_assert(_start <= _end);
 
396
}
 
397
 
 
398
TS_INLINE void
 
399
IOBufferBlock::fill(int64_t len)
 
400
{
 
401
  _end += len;
 
402
  ink_assert(_end <= _buf_end);
 
403
}
 
404
 
 
405
TS_INLINE void
 
406
IOBufferBlock::reset()
 
407
{
 
408
  _end = _start = buf();
 
409
  _buf_end = buf() + data->block_size();
 
410
}
 
411
 
 
412
TS_INLINE void
 
413
IOBufferBlock::alloc(int64_t i)
 
414
{
 
415
  ink_debug_assert(BUFFER_SIZE_ALLOCATED(i));
 
416
#ifdef TRACK_BUFFER_USER
 
417
  data = new_IOBufferData_internal(_location, i);
 
418
#else
 
419
  data = new_IOBufferData_internal(i);
 
420
#endif
 
421
  reset();
 
422
}
 
423
 
 
424
TS_INLINE void
 
425
IOBufferBlock::clear()
 
426
{
 
427
  data = NULL;
 
428
  IOBufferBlock *p = next;
 
429
  while (p) {
 
430
    int r = p->refcount_dec();
 
431
    if (r)
 
432
      break;
 
433
    else {
 
434
      IOBufferBlock *n = p->next.m_ptr;
 
435
      p->next.m_ptr = NULL;
 
436
      p->free();
 
437
      p = n;
 
438
    }
 
439
  }
 
440
  next.m_ptr = NULL;
 
441
  _buf_end = _end = _start = NULL;
 
442
}
 
443
 
 
444
TS_INLINE IOBufferBlock *
 
445
IOBufferBlock::clone()
 
446
{
 
447
#ifdef TRACK_BUFFER_USER
 
448
  IOBufferBlock *b = new_IOBufferBlock_internal(_location);
 
449
#else
 
450
  IOBufferBlock *b = new_IOBufferBlock_internal();
 
451
#endif
 
452
  b->data = data;
 
453
  b->_start = _start;
 
454
  b->_end = _end;
 
455
  b->_buf_end = _end;
 
456
#ifdef TRACK_BUFFER_USER
 
457
  b->_location = _location;
 
458
#endif
 
459
  return b;
 
460
}
 
461
 
 
462
TS_INLINE void
 
463
IOBufferBlock::dealloc()
 
464
{
 
465
  clear();
 
466
}
 
467
 
 
468
TS_INLINE void
 
469
IOBufferBlock::free()
 
470
{
 
471
  dealloc();
 
472
  ioBlockAllocator.free(this);
 
473
}
 
474
 
 
475
TS_INLINE void
 
476
IOBufferBlock::set_internal(void *b, int64_t len, int64_t asize_index)
 
477
{
 
478
#ifdef TRACK_BUFFER_USER
 
479
  data = new_IOBufferData_internal(_location, BUFFER_SIZE_NOT_ALLOCATED);
 
480
#else
 
481
  data = new_IOBufferData_internal(BUFFER_SIZE_NOT_ALLOCATED);
 
482
#endif
 
483
  data->_data = (char *) b;
 
484
#ifdef TRACK_BUFFER_USER
 
485
  iobuffer_mem_inc(_location, asize_index);
 
486
#endif
 
487
  data->_size_index = asize_index;
 
488
  reset();
 
489
  _end = _start + len;
 
490
}
 
491
 
 
492
TS_INLINE void
 
493
IOBufferBlock::set(IOBufferData * d, int64_t len, int64_t offset)
 
494
{
 
495
  data = d;
 
496
  _start = buf() + offset;
 
497
  _end = _start + len;
 
498
  _buf_end = _start + d->block_size();
 
499
}
 
500
 
 
501
TS_INLINE void
 
502
IOBufferBlock::realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index)
 
503
{
 
504
  int64_t data_size = size();
 
505
  memcpy(b, _start, size());
 
506
  dealloc();
 
507
  set_internal(b, buf_size, asize_index);
 
508
  _end = _start + data_size;
 
509
}
 
510
 
 
511
TS_INLINE void
 
512
IOBufferBlock::realloc(void *b, int64_t buf_size)
 
513
{
 
514
  realloc_set_internal(b, buf_size, BUFFER_SIZE_NOT_ALLOCATED);
 
515
}
 
516
 
 
517
TS_INLINE void
 
518
IOBufferBlock::realloc_xmalloc(void *b, int64_t buf_size)
 
519
{
 
520
  realloc_set_internal(b, buf_size, -buf_size);
 
521
}
 
522
 
 
523
TS_INLINE void
 
524
IOBufferBlock::realloc_xmalloc(int64_t buf_size)
 
525
{
 
526
  realloc_set_internal(xmalloc(buf_size), buf_size, -buf_size);
 
527
}
 
528
 
 
529
TS_INLINE void
 
530
IOBufferBlock::realloc(int64_t i)
 
531
{
 
532
  if (i == data->_size_index)
 
533
    return;
 
534
  if (i >= (int64_t) sizeof(ioBufAllocator))
 
535
    return;
 
536
 
 
537
  ink_release_assert(i > data->_size_index && i != BUFFER_SIZE_NOT_ALLOCATED);
 
538
  void *b = ioBufAllocator[i].alloc_void();
 
539
  realloc_set_internal(b, BUFFER_SIZE_FOR_INDEX(i), i);
 
540
}
 
541
 
 
542
//////////////////////////////////////////////////////////////////
 
543
//
 
544
//  class IOBufferReader --
 
545
//         inline functions definitions
 
546
//
 
547
//////////////////////////////////////////////////////////////////
 
548
TS_INLINE void
 
549
IOBufferReader::skip_empty_blocks()
 
550
{
 
551
  while (block->next && block->next->read_avail() && start_offset >= block->size()) {
 
552
    start_offset -= block->size();
 
553
    block = block->next;
 
554
  }
 
555
}
 
556
 
 
557
TS_INLINE bool
 
558
IOBufferReader::low_water()
 
559
{
 
560
  return mbuf->low_water();
 
561
}
 
562
 
 
563
TS_INLINE bool
 
564
IOBufferReader::high_water()
 
565
{
 
566
  return read_avail() >= mbuf->water_mark;
 
567
}
 
568
 
 
569
TS_INLINE bool
 
570
IOBufferReader::current_low_water()
 
571
{
 
572
  return mbuf->current_low_water();
 
573
}
 
574
 
 
575
TS_INLINE IOBufferBlock *
 
576
IOBufferReader::get_current_block()
 
577
{
 
578
  return (block);
 
579
}
 
580
 
 
581
TS_INLINE char *
 
582
IOBufferReader::start()
 
583
{
 
584
  if (block == 0)
 
585
    return (0);
 
586
  skip_empty_blocks();
 
587
  return block->start() + start_offset;
 
588
}
 
589
 
 
590
TS_INLINE char *
 
591
IOBufferReader::end()
 
592
{
 
593
  if (block == 0)
 
594
    return (0);
 
595
  skip_empty_blocks();
 
596
  return block->end();
 
597
}
 
598
 
 
599
TS_INLINE int64_t
 
600
IOBufferReader::block_read_avail()
 
601
{
 
602
  if (block == 0)
 
603
    return (0);
 
604
  skip_empty_blocks();
 
605
  return (int64_t) (block->end() - (block->start() + start_offset));
 
606
}
 
607
 
 
608
TS_INLINE int
 
609
IOBufferReader::block_count()
 
610
{
 
611
  int count = 0;
 
612
  IOBufferBlock *b = block;
 
613
 
 
614
  while (b) {
 
615
    count++;
 
616
    b = b->next;
 
617
  }
 
618
  return count;
 
619
}
 
620
 
 
621
TS_INLINE int64_t
 
622
IOBufferReader::read_avail()
 
623
{
 
624
  int64_t t = 0;
 
625
  IOBufferBlock *b = block;
 
626
 
 
627
  while (b) {
 
628
    t += b->read_avail();
 
629
    b = b->next;
 
630
  }
 
631
  t -= start_offset;
 
632
  if (size_limit != INT64_MAX && t > size_limit)
 
633
    t = size_limit;
 
634
  return t;
 
635
}
 
636
 
 
637
TS_INLINE void
 
638
IOBufferReader::consume(int64_t n)
 
639
{
 
640
  start_offset += n;
 
641
  if (size_limit != INT64_MAX)
 
642
    size_limit -= n;
 
643
  ink_assert(size_limit >= 0);
 
644
  if (block == 0)
 
645
    return;
 
646
  int64_t r = block->read_avail();
 
647
  int64_t s = start_offset;
 
648
  while (r <= s && block->next && block->next->read_avail()) {
 
649
    s -= r;
 
650
    start_offset = s;
 
651
    block = block->next;
 
652
    r = block->read_avail();
 
653
  }
 
654
  ink_debug_assert(read_avail() >= 0);
 
655
}
 
656
 
 
657
TS_INLINE char &
 
658
IOBufferReader::operator[] (int64_t i)
 
659
{
 
660
  static char
 
661
    _error = '\0';
 
662
 
 
663
  IOBufferBlock *
 
664
    b = block;
 
665
  i += start_offset;
 
666
  while (b) {
 
667
    int64_t bytes = b->read_avail();
 
668
    if (bytes > i)
 
669
      return b->start()[i];
 
670
    i -= bytes;
 
671
    b = b->next;
 
672
  }
 
673
 
 
674
  ink_assert(!"out of range");
 
675
  if (unlikely(b))
 
676
    return *b->start();
 
677
 
 
678
  return _error;
 
679
}
 
680
 
 
681
TS_INLINE void
 
682
IOBufferReader::clear()
 
683
{
 
684
  accessor = NULL;
 
685
  block = NULL;
 
686
  mbuf = NULL;
 
687
  start_offset = 0;
 
688
  size_limit = INT64_MAX;
 
689
}
 
690
 
 
691
TS_INLINE void
 
692
IOBufferReader::reset()
 
693
{
 
694
  block = mbuf->_writer;
 
695
  start_offset = 0;
 
696
  size_limit = INT64_MAX;
 
697
}
 
698
 
 
699
////////////////////////////////////////////////////////////////
 
700
//
 
701
//  class MIOBuffer --
 
702
//      inline functions definitions
 
703
//
 
704
////////////////////////////////////////////////////////////////
 
705
inkcoreapi extern ClassAllocator<MIOBuffer> ioAllocator;
 
706
////////////////////////////////////////////////////////////////
 
707
//
 
708
//  MIOBuffer::MIOBuffer()
 
709
//
 
710
//  This constructor accepts a pre-allocated memory buffer,
 
711
//  wraps if in a IOBufferData and IOBufferBlock structures
 
712
//  and sets it as the current block.
 
713
//  NOTE that in this case the memory buffer will not be freed
 
714
//  by the MIOBuffer class. It is the user responsibility to
 
715
//  free the memory buffer. The wrappers (MIOBufferBlock and
 
716
//  MIOBufferData) will be freed by this class.
 
717
//
 
718
////////////////////////////////////////////////////////////////
 
719
TS_INLINE
 
720
MIOBuffer::MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark)
 
721
{
 
722
  set(b, bufsize);
 
723
  water_mark = aWater_mark;
 
724
  size_index = BUFFER_SIZE_NOT_ALLOCATED;
 
725
#ifdef TRACK_BUFFER_USER
 
726
  _location = NULL;
 
727
#endif
 
728
  return;
 
729
}
 
730
 
 
731
TS_INLINE
 
732
MIOBuffer::MIOBuffer(int64_t default_size_index)
 
733
{
 
734
  clear();
 
735
  size_index = default_size_index;
 
736
#ifdef TRACK_BUFFER_USER
 
737
  _location = NULL;
 
738
#endif
 
739
  return;
 
740
}
 
741
 
 
742
TS_INLINE
 
743
MIOBuffer::MIOBuffer()
 
744
{
 
745
  clear();
 
746
#ifdef TRACK_BUFFER_USER
 
747
  _location = NULL;
 
748
#endif
 
749
  return;
 
750
}
 
751
 
 
752
TS_INLINE
 
753
MIOBuffer::~
 
754
MIOBuffer()
 
755
{
 
756
  _writer = NULL;
 
757
  dealloc_all_readers();
 
758
}
 
759
 
 
760
TS_INLINE MIOBuffer * new_MIOBuffer_internal(
 
761
#ifdef TRACK_BUFFER_USER
 
762
                                               const char *location,
 
763
#endif
 
764
                                               int64_t size_index)
 
765
{
 
766
  MIOBuffer *b = ioAllocator.alloc();
 
767
#ifdef TRACK_BUFFER_USER
 
768
  b->_location = location;
 
769
#endif
 
770
  b->alloc(size_index);
 
771
  return b;
 
772
}
 
773
 
 
774
TS_INLINE void
 
775
free_MIOBuffer(MIOBuffer * mio)
 
776
{
 
777
  mio->_writer = NULL;
 
778
  mio->dealloc_all_readers();
 
779
  ioAllocator.free(mio);
 
780
}
 
781
 
 
782
TS_INLINE MIOBuffer * new_empty_MIOBuffer_internal(
 
783
#ifdef TRACK_BUFFER_USER
 
784
                                                     const char *location,
 
785
#endif
 
786
                                                     int64_t size_index)
 
787
{
 
788
  MIOBuffer *b = ioAllocator.alloc();
 
789
  b->size_index = size_index;
 
790
#ifdef TRACK_BUFFER_USER
 
791
  b->_location = location;
 
792
#endif
 
793
  return b;
 
794
}
 
795
 
 
796
TS_INLINE void
 
797
free_empty_MIOBuffer(MIOBuffer * mio)
 
798
{
 
799
  ioAllocator.free(mio);
 
800
}
 
801
 
 
802
TS_INLINE IOBufferReader *
 
803
MIOBuffer::alloc_accessor(MIOBufferAccessor * anAccessor)
 
804
{
 
805
  int i;
 
806
  for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
 
807
    if (!readers[i].allocated())
 
808
      break;
 
809
 
 
810
  // TODO refactor code to return NULL at some point
 
811
  ink_release_assert(i < MAX_MIOBUFFER_READERS);
 
812
 
 
813
  IOBufferReader *e = &readers[i];
 
814
  e->mbuf = this;
 
815
  e->reset();
 
816
  e->accessor = anAccessor;
 
817
 
 
818
  return e;
 
819
}
 
820
 
 
821
TS_INLINE IOBufferReader *
 
822
MIOBuffer::alloc_reader()
 
823
{
 
824
  int i;
 
825
  for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
 
826
    if (!readers[i].allocated())
 
827
      break;
 
828
 
 
829
  // TODO refactor code to return NULL at some point
 
830
  ink_release_assert(i < MAX_MIOBUFFER_READERS);
 
831
 
 
832
  IOBufferReader *e = &readers[i];
 
833
  e->mbuf = this;
 
834
  e->reset();
 
835
  e->accessor = NULL;
 
836
 
 
837
  return e;
 
838
}
 
839
 
 
840
TS_INLINE int64_t
 
841
MIOBuffer::block_size()
 
842
{
 
843
  return index_to_buffer_size(size_index);
 
844
}
 
845
TS_INLINE IOBufferReader *
 
846
MIOBuffer::clone_reader(IOBufferReader * r)
 
847
{
 
848
  int i;
 
849
  for (i = 0; i < MAX_MIOBUFFER_READERS; i++)
 
850
    if (!readers[i].allocated())
 
851
      break;
 
852
 
 
853
  // TODO refactor code to return NULL at some point
 
854
  ink_release_assert(i < MAX_MIOBUFFER_READERS);
 
855
 
 
856
  IOBufferReader *e = &readers[i];
 
857
  e->mbuf = this;
 
858
  e->accessor = NULL;
 
859
  e->block = r->block;
 
860
  e->start_offset = r->start_offset;
 
861
  e->size_limit = r->size_limit;
 
862
  ink_assert(e->size_limit >= 0);
 
863
 
 
864
  return e;
 
865
}
 
866
 
 
867
TS_INLINE int64_t
 
868
MIOBuffer::block_write_avail()
 
869
{
 
870
  IOBufferBlock *b = first_write_block();
 
871
  return b ? b->write_avail() : 0;
 
872
}
 
873
 
 
874
////////////////////////////////////////////////////////////////
 
875
//
 
876
//  MIOBuffer::append_block()
 
877
//
 
878
//  Appends a block to writer->next and make it the current
 
879
//  block.
 
880
//  Note that the block is not appended to the end of the list.
 
881
//  That means that if writer->next was not null before this
 
882
//  call then the block that writer->next was pointing to will
 
883
//  have its reference count decremented and writer->next
 
884
//  will have a new value which is the new block.
 
885
//  In any case the new appended block becomes the current
 
886
//  block.
 
887
//
 
888
////////////////////////////////////////////////////////////////
 
889
TS_INLINE void
 
890
MIOBuffer::append_block_internal(IOBufferBlock * b)
 
891
{
 
892
  // It would be nice to remove an empty buffer at the beginning,
 
893
  // but this breaks HTTP.
 
894
  // if (!_writer || !_writer->read_avail())
 
895
  if (!_writer) {
 
896
    _writer = b;
 
897
    init_readers();
 
898
  } else {
 
899
    ink_assert(!_writer->next || !_writer->next->read_avail());
 
900
    _writer->next = b;
 
901
    while (b->read_avail()) {
 
902
      _writer = b;
 
903
      b = b->next;
 
904
      if (!b)
 
905
        break;
 
906
    }
 
907
  }
 
908
  while (_writer->next && !_writer->write_avail() && _writer->next->read_avail())
 
909
    _writer = _writer->next;
 
910
}
 
911
 
 
912
TS_INLINE void
 
913
MIOBuffer::append_block(IOBufferBlock * b)
 
914
{
 
915
  ink_assert(b->read_avail());
 
916
  append_block_internal(b);
 
917
}
 
918
 
 
919
////////////////////////////////////////////////////////////////
 
920
//
 
921
//  MIOBuffer::append_block()
 
922
//
 
923
//  Allocate a block, appends it to current->next
 
924
//  and make the new block the current block (writer).
 
925
//
 
926
////////////////////////////////////////////////////////////////
 
927
TS_INLINE void
 
928
MIOBuffer::append_block(int64_t asize_index)
 
929
{
 
930
  ink_debug_assert(BUFFER_SIZE_ALLOCATED(asize_index));
 
931
#ifdef TRACK_BUFFER_USER
 
932
  IOBufferBlock *b = new_IOBufferBlock_internal(_location);
 
933
#else
 
934
  IOBufferBlock *b = new_IOBufferBlock_internal();
 
935
#endif
 
936
  b->alloc(asize_index);
 
937
  append_block_internal(b);
 
938
  return;
 
939
}
 
940
 
 
941
TS_INLINE void
 
942
MIOBuffer::add_block()
 
943
{
 
944
  append_block(size_index);
 
945
}
 
946
 
 
947
TS_INLINE void
 
948
MIOBuffer::check_add_block()
 
949
{
 
950
  if (!high_water() && current_low_water())
 
951
    add_block();
 
952
}
 
953
 
 
954
TS_INLINE IOBufferBlock *
 
955
MIOBuffer::get_current_block()
 
956
{
 
957
  return first_write_block();
 
958
}
 
959
 
 
960
//////////////////////////////////////////////////////////////////
 
961
//
 
962
//  MIOBuffer::current_write_avail()
 
963
//
 
964
//  returns the total space available in all blocks.
 
965
//  This function is different than write_avail() because
 
966
//  it will not append a new block if there is no space
 
967
//  or below the watermark space available.
 
968
//
 
969
//////////////////////////////////////////////////////////////////
 
970
TS_INLINE int64_t
 
971
MIOBuffer::current_write_avail()
 
972
{
 
973
  int64_t t = 0;
 
974
  IOBufferBlock *b = _writer;
 
975
  while (b) {
 
976
    t += b->write_avail();
 
977
    b = b->next;
 
978
  }
 
979
  return t;
 
980
}
 
981
 
 
982
//////////////////////////////////////////////////////////////////
 
983
//
 
984
//  MIOBuffer::write_avail()
 
985
//
 
986
//  returns the number of bytes available in the current block.
 
987
//  If there is no current block or not enough free space in
 
988
//  the current block then a new block is appended.
 
989
//
 
990
//////////////////////////////////////////////////////////////////
 
991
TS_INLINE int64_t
 
992
MIOBuffer::write_avail()
 
993
{
 
994
  check_add_block();
 
995
  return current_write_avail();
 
996
}
 
997
 
 
998
TS_INLINE void
 
999
MIOBuffer::fill(int64_t len)
 
1000
{
 
1001
  int64_t f = _writer->write_avail();
 
1002
  while (f < len) {
 
1003
    _writer->fill(f);
 
1004
    len -= f;
 
1005
    if (len > 0)
 
1006
      _writer = _writer->next;
 
1007
    f = _writer->write_avail();
 
1008
  }
 
1009
  _writer->fill(len);
 
1010
}
 
1011
 
 
1012
TS_INLINE int
 
1013
MIOBuffer::max_block_count()
 
1014
{
 
1015
  int maxb = 0;
 
1016
  for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) {
 
1017
    if (readers[i].allocated()) {
 
1018
      int c = readers[i].block_count();
 
1019
      if (c > maxb) {
 
1020
        maxb = c;
 
1021
      }
 
1022
    }
 
1023
  }
 
1024
  return maxb;
 
1025
}
 
1026
 
 
1027
TS_INLINE int64_t
 
1028
MIOBuffer::max_read_avail()
 
1029
{
 
1030
  int64_t s = 0;
 
1031
  int found = 0;
 
1032
  for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) {
 
1033
    if (readers[i].allocated()) {
 
1034
      int64_t ss = readers[i].read_avail();
 
1035
      if (ss > s) {
 
1036
        s = ss;
 
1037
      }
 
1038
      found = 1;
 
1039
    }
 
1040
  }
 
1041
  if (!found && _writer)
 
1042
    return _writer->read_avail();
 
1043
  return s;
 
1044
}
 
1045
 
 
1046
TS_INLINE void
 
1047
MIOBuffer::set(void *b, int64_t len)
 
1048
{
 
1049
#ifdef TRACK_BUFFER_USER
 
1050
  _writer = new_IOBufferBlock_internal(_location);
 
1051
#else
 
1052
  _writer = new_IOBufferBlock_internal();
 
1053
#endif
 
1054
  _writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(len));
 
1055
  init_readers();
 
1056
}
 
1057
 
 
1058
TS_INLINE void
 
1059
MIOBuffer::set_xmalloced(void *b, int64_t len)
 
1060
{
 
1061
#ifdef TRACK_BUFFER_USER
 
1062
  _writer = new_IOBufferBlock_internal(_location);
 
1063
#else
 
1064
  _writer = new_IOBufferBlock_internal();
 
1065
#endif
 
1066
  _writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len));
 
1067
  init_readers();
 
1068
}
 
1069
 
 
1070
TS_INLINE void
 
1071
MIOBuffer::append_xmalloced(void *b, int64_t len)
 
1072
{
 
1073
#ifdef TRACK_BUFFER_USER
 
1074
  IOBufferBlock *x = new_IOBufferBlock_internal(_location);
 
1075
#else
 
1076
  IOBufferBlock *x = new_IOBufferBlock_internal();
 
1077
#endif
 
1078
  x->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len));
 
1079
  append_block_internal(x);
 
1080
}
 
1081
 
 
1082
TS_INLINE void
 
1083
MIOBuffer::append_fast_allocated(void *b, int64_t len, int64_t fast_size_index)
 
1084
{
 
1085
#ifdef TRACK_BUFFER_USER
 
1086
  IOBufferBlock *x = new_IOBufferBlock_internal(_location);
 
1087
#else
 
1088
  IOBufferBlock *x = new_IOBufferBlock_internal();
 
1089
#endif
 
1090
  x->set_internal(b, len, fast_size_index);
 
1091
  append_block_internal(x);
 
1092
}
 
1093
 
 
1094
TS_INLINE void
 
1095
MIOBuffer::alloc(int64_t i)
 
1096
{
 
1097
#ifdef TRACK_BUFFER_USER
 
1098
  _writer = new_IOBufferBlock_internal(_location);
 
1099
#else
 
1100
  _writer = new_IOBufferBlock_internal();
 
1101
#endif
 
1102
  _writer->alloc(i);
 
1103
  size_index = i;
 
1104
  init_readers();
 
1105
}
 
1106
 
 
1107
TS_INLINE void
 
1108
MIOBuffer::alloc_xmalloc(int64_t buf_size)
 
1109
{
 
1110
  char *b = (char *) xmalloc(buf_size);
 
1111
  set_xmalloced(b, buf_size);
 
1112
}
 
1113
 
 
1114
TS_INLINE void
 
1115
MIOBuffer::dealloc_reader(IOBufferReader * e)
 
1116
{
 
1117
  if (e->accessor) {
 
1118
    ink_assert(e->accessor->mbuf == this);
 
1119
    ink_assert(e->accessor->entry == e);
 
1120
    e->accessor->reset();
 
1121
  }
 
1122
  e->clear();
 
1123
}
 
1124
 
 
1125
TS_INLINE IOBufferReader *
 
1126
IOBufferReader::clone()
 
1127
{
 
1128
  return mbuf->clone_reader(this);
 
1129
}
 
1130
 
 
1131
TS_INLINE void
 
1132
IOBufferReader::dealloc()
 
1133
{
 
1134
  mbuf->dealloc_reader(this);
 
1135
}
 
1136
 
 
1137
TS_INLINE void
 
1138
MIOBuffer::dealloc_all_readers()
 
1139
{
 
1140
  for (int i = 0; i < MAX_MIOBUFFER_READERS; i++)
 
1141
    if (readers[i].allocated())
 
1142
      dealloc_reader(&readers[i]);
 
1143
}
 
1144
 
 
1145
TS_INLINE void
 
1146
MIOBuffer::set_size_index(int64_t size)
 
1147
{
 
1148
  size_index = iobuffer_size_to_index(size);
 
1149
}
 
1150
 
 
1151
TS_INLINE void
 
1152
MIOBufferAccessor::reader_for(MIOBuffer * abuf)
 
1153
{
 
1154
  mbuf = abuf;
 
1155
  if (abuf)
 
1156
    entry = mbuf->alloc_accessor(this);
 
1157
  else
 
1158
    entry = NULL;
 
1159
}
 
1160
 
 
1161
TS_INLINE void
 
1162
MIOBufferAccessor::reader_for(IOBufferReader * areader)
 
1163
{
 
1164
  if (entry == areader)
 
1165
    return;
 
1166
  mbuf = areader->mbuf;
 
1167
  entry = areader;
 
1168
  ink_assert(mbuf);
 
1169
}
 
1170
 
 
1171
TS_INLINE void
 
1172
MIOBufferAccessor::writer_for(MIOBuffer * abuf)
 
1173
{
 
1174
  mbuf = abuf;
 
1175
  entry = NULL;
 
1176
}
 
1177
 
 
1178
TS_INLINE void
 
1179
MIOBufferAccessor::clear()
 
1180
{
 
1181
  entry = NULL;
 
1182
  mbuf = NULL;
 
1183
}
 
1184
 
 
1185
TS_INLINE
 
1186
MIOBufferAccessor::~
 
1187
MIOBufferAccessor()
 
1188
{
 
1189
}
 
1190
 
 
1191
#endif