~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to lib/ts/ink_queue.cc

  • 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
  ink_queue.cc (This used to be ink_queue.c)
 
26
 
 
27
  This implements an atomic push/pop queue, and the freelist memory
 
28
  pools that are built from it.
 
29
 
 
30
  The change from ink_queue.cc to ink_queue.c resulted in some changes
 
31
  in access and store of 64 bit values. This is standardized by using
 
32
  the INK_QUEUE_LD64 macro which loads the version before the pointer
 
33
  (independent of endianness of native architecture) on 32 bit platforms
 
34
  or loads the 64 bit quantity directory on the DECs.
 
35
 
 
36
 
 
37
  ****************************************************************************/
 
38
 
 
39
#include "ink_config.h"
 
40
#include <assert.h>
 
41
#include <memory.h>
 
42
#include <stdlib.h>
 
43
#include <sys/types.h>
 
44
#include <sys/mman.h>
 
45
#include "ink_atomic.h"
 
46
#include "ink_queue.h"
 
47
#include "ink_memory.h"
 
48
#include "ink_error.h"
 
49
#include "ink_assert.h"
 
50
#include "ink_resource.h"
 
51
 
 
52
 
 
53
#ifdef __x86_64__
 
54
#define INK_QUEUE_LD64(dst,src) *((uint64_t*)&(dst)) = *((uint64_t*)&(src))
 
55
#else
 
56
#define INK_QUEUE_LD64(dst,src) (ink_queue_load_64((void *)&(dst), (void *)&(src)))
 
57
#endif
 
58
 
 
59
typedef struct _ink_freelist_list
 
60
{
 
61
  InkFreeList *fl;
 
62
  struct _ink_freelist_list *next;
 
63
}
 
64
ink_freelist_list;
 
65
 
 
66
inkcoreapi volatile int64_t fastalloc_mem_in_use = 0;
 
67
inkcoreapi volatile int64_t fastalloc_mem_total = 0;
 
68
 
 
69
/*
 
70
 * SANITY and DEADBEEF are compute-intensive memory debugging to
 
71
 * help in diagnosing freelist corruption.  We turn them off in
 
72
 * release builds.
 
73
 */
 
74
 
 
75
#ifdef DEBUG
 
76
#define SANITY
 
77
#define DEADBEEF
 
78
#endif
 
79
 
 
80
// #define MEMPROTECT 1
 
81
 
 
82
#define MEMPROTECT_SIZE  0x200
 
83
 
 
84
#ifdef MEMPROTECT
 
85
static const int page_size = 8192;   /* sysconf (_SC_PAGESIZE); */
 
86
#endif
 
87
 
 
88
static ink_freelist_list *freelists = NULL;
 
89
 
 
90
inkcoreapi volatile int64_t freelist_allocated_mem = 0;
 
91
 
 
92
#define fl_memadd(_x_) \
 
93
   ink_atomic_increment64(&freelist_allocated_mem, (int64_t) (_x_));
 
94
 
 
95
//static void ink_queue_load_64(void *dst, void *src)
 
96
//{
 
97
//    int32_t src_version =  (*(head_p *) src).s.version;
 
98
//    void *src_pointer = (*(head_p *) src).s.pointer;
 
99
//
 
100
//    (*(head_p *) dst).s.version = src_version;
 
101
//    (*(head_p *) dst).s.pointer = src_pointer;
 
102
//}
 
103
 
 
104
 
 
105
void
 
106
ink_freelist_init(InkFreeList * f,
 
107
                  const char *name, uint32_t type_size, uint32_t chunk_size, uint32_t offset, uint32_t alignment)
 
108
{
 
109
  ink_freelist_list *fll;
 
110
 
 
111
  /* its safe to add to this global list because ink_freelist_init()
 
112
     is only called from single-threaded initialization code. */
 
113
  if ((fll = (ink_freelist_list *) ink_malloc(sizeof(ink_freelist_list))) != 0) {
 
114
    fll->fl = f;
 
115
    fll->next = freelists;
 
116
    freelists = fll;
 
117
  }
 
118
  ink_assert(fll != NULL);
 
119
 
 
120
  f->name = name;
 
121
  f->offset = offset;
 
122
  /* quick test for power of 2 */
 
123
  ink_assert(!(alignment & (alignment - 1)));
 
124
  f->alignment = alignment;
 
125
  f->chunk_size = chunk_size;
 
126
  f->type_size = type_size;
 
127
#if defined(INK_USE_MUTEX_FOR_FREELISTS)
 
128
  ink_mutex_init(&(f->inkfreelist_mutex), name);
 
129
#endif
 
130
#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE))
 
131
  ink_mutex_init(&(f->freelist_mutex), name);
 
132
  f->head = NULL;
 
133
#ifdef CHECK_FOR_DOUBLE_FREE
 
134
  f->tail = NULL;
 
135
#endif
 
136
#else
 
137
  SET_FREELIST_POINTER_VERSION(f->head, FROM_PTR(0), 0);
 
138
#endif
 
139
 
 
140
  f->count = 0;
 
141
  f->allocated = 0;
 
142
  f->allocated_base = 0;
 
143
  f->count_base = 0;
 
144
}
 
145
 
 
146
InkFreeList *
 
147
ink_freelist_create(const char *name, uint32_t type_size, uint32_t chunk_size, uint32_t offset, uint32_t alignment)
 
148
{
 
149
  InkFreeList *f = ink_type_malloc(InkFreeList);
 
150
  ink_freelist_init(f, name, type_size, chunk_size, offset, alignment);
 
151
  return f;
 
152
}
 
153
 
 
154
#define ADDRESS_OF_NEXT(x, offset) ((void **)((char *)x + offset))
 
155
 
 
156
#ifdef SANITY
 
157
int fake_global_for_ink_queue = 0;
 
158
#endif
 
159
 
 
160
int fastmemtotal = 0;
 
161
 
 
162
#if defined(INK_USE_MUTEX_FOR_FREELISTS)
 
163
void *
 
164
ink_freelist_new_wrap(InkFreeList * f)
 
165
#else /* !INK_USE_MUTEX_FOR_FREELISTS */
 
166
void *
 
167
ink_freelist_new(InkFreeList * f)
 
168
#endif                          /* !INK_USE_MUTEX_FOR_FREELISTS */
 
169
{                               //static uint32_t cntf = 0;
 
170
 
 
171
#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE))
 
172
  void *foo;
 
173
  uint32_t type_size = f->type_size;
 
174
 
 
175
  ink_mutex_acquire(&(f->freelist_mutex));
 
176
  ink_assert(f->type_size != 0);
 
177
 
 
178
  //printf("ink_freelist_new %d - %d - %u\n",f ->type_size,(f->head != NULL) ? 1 : 0,cntf++);
 
179
 
 
180
 
 
181
  if (f->head != NULL) {
 
182
    /*
 
183
     * We have something on the free list..
 
184
     */
 
185
    void_p *h = (void_p *) f->head;
 
186
#ifdef CHECK_FOR_DOUBLE_FREE
 
187
    if (f->head == f->tail)
 
188
      f->tail = NULL;
 
189
#endif /* CHECK_FOR_DOUBLE_FREE */
 
190
 
 
191
    foo = (void *) h;
 
192
    f->head = (volatile void_p *) *h;
 
193
    f->count += 1;
 
194
    ink_mutex_release(&(f->freelist_mutex));
 
195
    return foo;
 
196
  } else {
 
197
    /*
 
198
     * Might as well unlock the freelist mutex, since
 
199
     * we're just going to do a malloc now..
 
200
     */
 
201
    uint32_t alignment;
 
202
 
 
203
#ifdef MEMPROTECT
 
204
    if (type_size >= MEMPROTECT_SIZE) {
 
205
      if (f->alignment < page_size)
 
206
        f->alignment = page_size;
 
207
      type_size = ((type_size + page_size - 1) / page_size) * page_size * 2;
 
208
    }
 
209
#endif /* MEMPROTECT */
 
210
 
 
211
    alignment = f->alignment;
 
212
    ink_mutex_release(&(f->freelist_mutex));
 
213
 
 
214
    if (alignment) {
 
215
      foo = ink_memalign(alignment, type_size);
 
216
    } else {
 
217
      foo = ink_malloc(type_size);
 
218
    }
 
219
    if (likely(foo))
 
220
      fl_memadd(type_size);
 
221
 
 
222
 
 
223
#ifdef MEMPROTECT
 
224
    if (type_size >= MEMPROTECT_SIZE) {
 
225
      if (mprotect((char *) foo + type_size - page_size, page_size, PROT_NONE) < 0)
 
226
        perror("mprotect");
 
227
    }
 
228
#endif /* MEMPROTECT */
 
229
    return foo;
 
230
  }
 
231
 
 
232
#else /* #if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) */
 
233
  head_p item;
 
234
  head_p next;
 
235
  int result = 0;
 
236
 
 
237
  //printf("ink_freelist_new %d - %d - %u\n",f ->type_size,(f->head != NULL) ? 1 : 0,cntf++);
 
238
 
 
239
 
 
240
  do {
 
241
    INK_QUEUE_LD64(item, f->head);
 
242
    if (TO_PTR(FREELIST_POINTER(item)) == NULL) {
 
243
      uint32_t type_size = f->type_size;
 
244
      uint32_t i;
 
245
 
 
246
#ifdef MEMPROTECT
 
247
      if (type_size >= MEMPROTECT_SIZE) {
 
248
        if (f->alignment < page_size)
 
249
          f->alignment = page_size;
 
250
        type_size = ((type_size + page_size - 1) / page_size) * page_size * 2;
 
251
      }
 
252
#endif /* MEMPROTECT */
 
253
 
 
254
      void *newp = NULL;
 
255
#ifndef NO_MEMALIGN
 
256
#ifdef DEBUG
 
257
      char *oldsbrk = (char *) sbrk(0), *newsbrk = NULL;
 
258
#endif
 
259
      if (f->alignment)
 
260
        newp = ink_memalign(f->alignment, f->chunk_size * type_size);
 
261
      else
 
262
        newp = ink_malloc(f->chunk_size * type_size);
 
263
      if (newp)
 
264
        fl_memadd(f->chunk_size * type_size);
 
265
#ifdef DEBUG
 
266
      newsbrk = (char *) sbrk(0);
 
267
      ink_atomic_increment(&fastmemtotal, newsbrk - oldsbrk);
 
268
      /*      printf("fastmem %d, %d, %d\n", f->chunk_size * type_size,
 
269
         newsbrk - oldsbrk, fastmemtotal); */
 
270
#endif
 
271
      SET_FREELIST_POINTER_VERSION(item, newp, 0);
 
272
#else
 
273
      uintptr_t add;
 
274
      uintptr_t mask;
 
275
      if (f->alignment) {
 
276
        add = f->alignment - 1;
 
277
        mask = ~(uintptr_t) add;
 
278
      } else {
 
279
        add = 0;
 
280
        mask = ~0;
 
281
      }
 
282
      newp = ink_malloc(f->chunk_size * type_size + add);
 
283
      if (newp)
 
284
        fl_memadd(f->chunk_size * type_size + add);
 
285
      newp = (void *) ((((uintptr_t) newp) + add) & mask);
 
286
      SET_FREELIST_POINTER_VERSION(item, newp, 0);
 
287
#endif
 
288
 
 
289
#if !defined(INK_USE_MUTEX_FOR_FREELISTS)
 
290
      ink_atomic_increment((int *) &f->allocated, f->chunk_size);
 
291
      ink_atomic_increment64(&fastalloc_mem_total, (int64_t) f->chunk_size * f->type_size);
 
292
#else
 
293
      f->allocated += f->chunk_size;
 
294
      fastalloc_mem_total += f->chunk_size * f->type_size;
 
295
#endif
 
296
 
 
297
      /* free each of the new elements */
 
298
      for (i = 0; i < f->chunk_size; i++) {
 
299
        char *a = ((char *) FREELIST_POINTER(item)) + i * type_size;
 
300
#ifdef DEADBEEF
 
301
        memset(a, 0xDEADCAFE, type_size);
 
302
#endif
 
303
        ink_freelist_free(f, a);
 
304
#ifdef MEMPROTECT
 
305
        if (f->type_size >= MEMPROTECT_SIZE) {
 
306
          a += type_size - page_size;
 
307
          if (mprotect(a, page_size, PROT_NONE) < 0)
 
308
            perror("mprotect");
 
309
        }
 
310
#endif /* MEMPROTECT */
 
311
 
 
312
      }
 
313
#if !defined(INK_USE_MUTEX_FOR_FREELISTS)
 
314
      ink_atomic_increment((int *) &f->count, f->chunk_size);
 
315
      ink_atomic_increment64(&fastalloc_mem_in_use, (int64_t) f->chunk_size * f->type_size);
 
316
#else
 
317
      f->count += f->chunk_size;
 
318
      fastalloc_mem_in_use += f->chunk_size * f->type_size;
 
319
#endif
 
320
 
 
321
    } else {
 
322
      SET_FREELIST_POINTER_VERSION(next, *ADDRESS_OF_NEXT(TO_PTR(FREELIST_POINTER(item)), f->offset),
 
323
                                   FREELIST_VERSION(item) + 1);
 
324
#if !defined(INK_USE_MUTEX_FOR_FREELISTS)
 
325
      result = ink_atomic_cas64((int64_t *) & f->head.data, item.data, next.data);
 
326
#else
 
327
      f->head.data = next.data;
 
328
      result = 1;
 
329
#endif
 
330
 
 
331
#ifdef SANITY
 
332
      if (result) {
 
333
        if (FREELIST_POINTER(item) == TO_PTR(FREELIST_POINTER(next)))
 
334
          ink_fatal(1, "ink_freelist_new: loop detected");
 
335
        if (((uintptr_t) (TO_PTR(FREELIST_POINTER(next)))) & 3)
 
336
          ink_fatal(1, "ink_freelist_new: bad list");
 
337
        if (TO_PTR(FREELIST_POINTER(next)))
 
338
          fake_global_for_ink_queue = *(int *) TO_PTR(FREELIST_POINTER(next));
 
339
      }
 
340
#endif /* SANITY */
 
341
 
 
342
    }
 
343
  }
 
344
  while (result == 0);
 
345
  ink_assert(!((uintptr_t)TO_PTR(FREELIST_POINTER(item))&(((uintptr_t)f->alignment)-1)));
 
346
 
 
347
  ink_atomic_increment((int *) &f->count, 1);
 
348
  ink_atomic_increment64(&fastalloc_mem_in_use, (int64_t) f->type_size);
 
349
 
 
350
  return TO_PTR(FREELIST_POINTER(item));
 
351
#endif /* #if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) */
 
352
}
 
353
typedef volatile void *volatile_void_p;
 
354
 
 
355
#if defined(INK_USE_MUTEX_FOR_FREELISTS)
 
356
void
 
357
ink_freelist_free_wrap(InkFreeList * f, void *item)
 
358
#else /* !INK_USE_MUTEX_FOR_FREELISTS */
 
359
void
 
360
ink_freelist_free(InkFreeList * f, void *item)
 
361
#endif                          /* !INK_USE_MUTEX_FOR_FREELISTS */
 
362
{
 
363
#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE))
 
364
  void_p *foo;
 
365
 
 
366
  //printf("ink_freelist_free\n");
 
367
  ink_mutex_acquire(&(f->freelist_mutex));
 
368
 
 
369
  foo = (void_p *) item;
 
370
#ifdef CHECK_FOR_DOUBLE_FREE
 
371
  void_p *p = (void_p *) f->head;
 
372
  while (p) {
 
373
    if (p == (void_p *) item)
 
374
      ink_release_assert(!"ink_freelist_free: Double free");
 
375
    p = (void_p *) * p;
 
376
  }
 
377
 
 
378
  if (f->tail)
 
379
    *f->tail = foo;
 
380
  *foo = (void_p) NULL;
 
381
 
 
382
  if (f->head == NULL)
 
383
    f->head = foo;
 
384
  f->tail = foo;
 
385
#else
 
386
  *foo = (void_p) f->head;
 
387
  f->head = foo;
 
388
#endif
 
389
  f->count -= 1;
 
390
 
 
391
  ink_mutex_release(&(f->freelist_mutex));
 
392
#else
 
393
 
 
394
  volatile_void_p *adr_of_next = (volatile_void_p *) ADDRESS_OF_NEXT(item, f->offset);
 
395
  head_p h;
 
396
  head_p item_pair;
 
397
  int result;
 
398
 
 
399
  // ink_assert(!((long)item&(f->alignment-1))); XXX - why is this no longer working? -bcall
 
400
 
 
401
#ifdef DEADBEEF
 
402
  {
 
403
    // set string to DEADBEEF
 
404
    const char str[4] = { (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef };
 
405
 
 
406
    // search for DEADBEEF anywhere after a pointer offset in the item
 
407
    char *position = (char *) item + sizeof(void *);    // start
 
408
    char *end = (char *) item + f->type_size;   // end
 
409
 
 
410
    int i, j;
 
411
    for (i = sizeof(void *) & 0x3, j = 0; position < end; ++position) {
 
412
      if (i == j) {
 
413
        if (*position == str[i]) {
 
414
          if (j++ == 3) {
 
415
            ink_fatal(1, "ink_freelist_free: trying to free item twice");
 
416
          }
 
417
        }
 
418
      } else {
 
419
        j = 0;
 
420
      }
 
421
      i = (i + 1) & 0x3;
 
422
    }
 
423
 
 
424
    // set the entire item to DEADBEEF
 
425
    memset(item, 0xDEADBEEF, f->type_size);
 
426
  }
 
427
#endif /* DEADBEEF */
 
428
 
 
429
  result = 0;
 
430
  do {
 
431
    INK_QUEUE_LD64(h, f->head);
 
432
#ifdef SANITY
 
433
    if (TO_PTR(FREELIST_POINTER(h)) == item)
 
434
      ink_fatal(1, "ink_freelist_free: trying to free item twice");
 
435
    if (((uintptr_t) (TO_PTR(FREELIST_POINTER(h)))) & 3)
 
436
      ink_fatal(1, "ink_freelist_free: bad list");
 
437
    if (TO_PTR(FREELIST_POINTER(h)))
 
438
      fake_global_for_ink_queue = *(int *) TO_PTR(FREELIST_POINTER(h));
 
439
#endif /* SANITY */
 
440
    *adr_of_next = FREELIST_POINTER(h);
 
441
    SET_FREELIST_POINTER_VERSION(item_pair, FROM_PTR(item), FREELIST_VERSION(h));
 
442
    INK_MEMORY_BARRIER;
 
443
#if !defined(INK_USE_MUTEX_FOR_FREELISTS)
 
444
    result = ink_atomic_cas64((int64_t *) & f->head, h.data, item_pair.data);
 
445
#else
 
446
    f->head.data = item_pair.data;
 
447
    result = 1;
 
448
#endif
 
449
 
 
450
  }
 
451
  while (result == 0);
 
452
 
 
453
  ink_atomic_increment((int *) &f->count, -1);
 
454
  ink_atomic_increment64(&fastalloc_mem_in_use, -(int64_t) f->type_size);
 
455
#endif
 
456
}
 
457
 
 
458
void
 
459
ink_freelists_snap_baseline()
 
460
{
 
461
  ink_freelist_list *fll;
 
462
  fll = freelists;
 
463
  while (fll) {
 
464
    fll->fl->allocated_base = fll->fl->allocated;
 
465
    fll->fl->count_base = fll->fl->count;
 
466
    fll = fll->next;
 
467
  }
 
468
}
 
469
 
 
470
void
 
471
ink_freelists_dump_baselinerel(FILE * f)
 
472
{
 
473
  ink_freelist_list *fll;
 
474
  if (f == NULL)
 
475
    f = stderr;
 
476
 
 
477
  fprintf(f, " allocated  | in-use     |  count  | type size  |   free list name\n");
 
478
  fprintf(f, "rel. to base|rel. to base|         |            |                 \n");
 
479
  fprintf(f, "------------|------------|---------|------------|----------------------------------\n");
 
480
 
 
481
  fll = freelists;
 
482
  while (fll) {
 
483
    int a = fll->fl->allocated - fll->fl->allocated_base;
 
484
    if (a != 0) {
 
485
      fprintf(f, " %10u | %10u | %7u | %10u | memory/%s\n",
 
486
              (fll->fl->allocated - fll->fl->allocated_base) * fll->fl->type_size,
 
487
              (fll->fl->count - fll->fl->count_base) * fll->fl->type_size,
 
488
              fll->fl->count - fll->fl->count_base, fll->fl->type_size, fll->fl->name ? fll->fl->name : "<unknown>");
 
489
    }
 
490
    fll = fll->next;
 
491
  }
 
492
}
 
493
 
 
494
void
 
495
ink_freelists_dump(FILE * f)
 
496
{
 
497
  ink_freelist_list *fll;
 
498
  if (f == NULL)
 
499
    f = stderr;
 
500
 
 
501
  fprintf(f, " allocated  | in-use     | type size  |   free list name\n");
 
502
  fprintf(f, "------------|------------|------------|----------------------------------\n");
 
503
 
 
504
  fll = freelists;
 
505
  while (fll) {
 
506
    fprintf(f, " %10u | %10u | %10u | memory/%s\n",
 
507
            fll->fl->allocated * fll->fl->type_size,
 
508
            fll->fl->count * fll->fl->type_size, fll->fl->type_size, fll->fl->name ? fll->fl->name : "<unknown>");
 
509
    fll = fll->next;
 
510
  }
 
511
}
 
512
 
 
513
 
 
514
#define INK_FREELIST_CREATE(T, n) \
 
515
ink_freelist_create("<unknown>", sizeof(T), n, (uintptr_t)&((T *)0)->next, 4)
 
516
 
 
517
void
 
518
ink_atomiclist_init(InkAtomicList * l, const char *name, uint32_t offset_to_next)
 
519
{
 
520
#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
521
  ink_mutex_init(&(l->inkatomiclist_mutex), name);
 
522
#endif
 
523
  l->name = name;
 
524
  l->offset = offset_to_next;
 
525
  SET_FREELIST_POINTER_VERSION(l->head, FROM_PTR(0), 0);
 
526
}
 
527
 
 
528
#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
529
void *
 
530
ink_atomiclist_pop_wrap(InkAtomicList * l)
 
531
#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
532
void *
 
533
ink_atomiclist_pop(InkAtomicList * l)
 
534
#endif                          /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
535
{
 
536
  head_p item;
 
537
  head_p next;
 
538
  int result = 0;
 
539
  do {
 
540
    INK_QUEUE_LD64(item, l->head);
 
541
    if (TO_PTR(FREELIST_POINTER(item)) == NULL)
 
542
      return NULL;
 
543
    SET_FREELIST_POINTER_VERSION(next, *ADDRESS_OF_NEXT(TO_PTR(FREELIST_POINTER(item)), l->offset),
 
544
                                 FREELIST_VERSION(item) + 1);
 
545
#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
546
    result = ink_atomic_cas64((int64_t *) & l->head.data, item.data, next.data);
 
547
#else
 
548
    l->head.data = next.data;
 
549
    result = 1;
 
550
#endif
 
551
 
 
552
  }
 
553
  while (result == 0);
 
554
  {
 
555
    void *ret = TO_PTR(FREELIST_POINTER(item));
 
556
    *ADDRESS_OF_NEXT(ret, l->offset) = NULL;
 
557
    return ret;
 
558
  }
 
559
}
 
560
 
 
561
#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
562
void *
 
563
ink_atomiclist_popall_wrap(InkAtomicList * l)
 
564
#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
565
void *
 
566
ink_atomiclist_popall(InkAtomicList * l)
 
567
#endif                          /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
568
{
 
569
  head_p item;
 
570
  head_p next;
 
571
  int result = 0;
 
572
  do {
 
573
    INK_QUEUE_LD64(item, l->head);
 
574
    if (TO_PTR(FREELIST_POINTER(item)) == NULL)
 
575
      return NULL;
 
576
    SET_FREELIST_POINTER_VERSION(next, FROM_PTR(NULL), FREELIST_VERSION(item) + 1);
 
577
#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
578
    result = ink_atomic_cas64((int64_t *) & l->head.data, item.data, next.data);
 
579
#else
 
580
    l->head.data = next.data;
 
581
    result = 1;
 
582
#endif
 
583
 
 
584
  }
 
585
  while (result == 0);
 
586
  {
 
587
    void *ret = TO_PTR(FREELIST_POINTER(item));
 
588
    void *e = ret;
 
589
    /* fixup forward pointers */
 
590
    while (e) {
 
591
      void *n = TO_PTR(*ADDRESS_OF_NEXT(e, l->offset));
 
592
      *ADDRESS_OF_NEXT(e, l->offset) = n;
 
593
      e = n;
 
594
    }
 
595
    return ret;
 
596
  }
 
597
}
 
598
 
 
599
#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
600
void *
 
601
ink_atomiclist_push_wrap(InkAtomicList * l, void *item)
 
602
#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
603
void *
 
604
ink_atomiclist_push(InkAtomicList * l, void *item)
 
605
#endif                          /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
606
{
 
607
  volatile_void_p *adr_of_next = (volatile_void_p *) ADDRESS_OF_NEXT(item, l->offset);
 
608
  head_p head;
 
609
  head_p item_pair;
 
610
  int result = 0;
 
611
  void *h = NULL;
 
612
  ink_assert(*adr_of_next == NULL);
 
613
  do {
 
614
    INK_QUEUE_LD64(head, l->head);
 
615
    h = FREELIST_POINTER(head);
 
616
    *adr_of_next = h;
 
617
    ink_assert(item != TO_PTR(h));
 
618
    SET_FREELIST_POINTER_VERSION(item_pair, FROM_PTR(item), FREELIST_VERSION(head));
 
619
    INK_MEMORY_BARRIER;
 
620
#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
621
    result = ink_atomic_cas64((int64_t *) & l->head, head.data, item_pair.data);
 
622
#else
 
623
    l->head.data = item_pair.data;
 
624
    result = 1;
 
625
#endif
 
626
 
 
627
  }
 
628
  while (result == 0);
 
629
 
 
630
  return TO_PTR(h);
 
631
}
 
632
 
 
633
#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
634
void *
 
635
ink_atomiclist_remove_wrap(InkAtomicList * l, void *item)
 
636
#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
637
void *
 
638
ink_atomiclist_remove(InkAtomicList * l, void *item)
 
639
#endif                          /* !INK_USE_MUTEX_FOR_ATOMICLISTS */
 
640
{
 
641
  head_p head;
 
642
  void *prev = NULL;
 
643
  void **addr_next = ADDRESS_OF_NEXT(item, l->offset);
 
644
  void *item_next = *addr_next;
 
645
  int result = 0;
 
646
 
 
647
  /*
 
648
   * first, try to pop it if it is first
 
649
   */
 
650
  INK_QUEUE_LD64(head, l->head);
 
651
  while (TO_PTR(FREELIST_POINTER(head)) == item) {
 
652
    head_p next;
 
653
    SET_FREELIST_POINTER_VERSION(next, item_next, FREELIST_VERSION(head) + 1);
 
654
#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS)
 
655
    result = ink_atomic_cas64((int64_t *) & l->head.data, head.data, next.data);
 
656
#else
 
657
    l->head.data = next.data;
 
658
    result = 1;
 
659
#endif
 
660
    if (result) {
 
661
      *addr_next = NULL;
 
662
      return item;
 
663
    }
 
664
    INK_QUEUE_LD64(head, l->head);
 
665
  }
 
666
 
 
667
  /*
 
668
   * then, go down the list, trying to remove it
 
669
   */
 
670
  prev = TO_PTR(FREELIST_POINTER(head));
 
671
  while (prev) {
 
672
    void **prev_adr_of_next = ADDRESS_OF_NEXT(prev, l->offset);
 
673
    void *prev_prev = prev;
 
674
    prev = TO_PTR(*prev_adr_of_next);
 
675
    if (prev == item) {
 
676
      ink_assert(prev_prev != item_next);
 
677
      *prev_adr_of_next = item_next;
 
678
      *addr_next = NULL;
 
679
      return item;
 
680
    }
 
681
  }
 
682
  return NULL;
 
683
}