]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc/mem/PageStack.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / ipc / mem / PageStack.cc
CommitLineData
be17aa82 1/*
5b74111a 2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
be17aa82 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
be17aa82
AR
7 */
8
bbc27441
AJ
9/* DEBUG: section 54 Interprocess Communication */
10
f7f3304a 11#include "squid.h"
be17aa82
AR
12
13#include "base/TextException.h"
383ff927 14#include "Debug.h"
68353d5a 15#include "ipc/mem/Page.h"
be17aa82
AR
16#include "ipc/mem/PageStack.h"
17
18/// used to mark a stack slot available for storing free page offsets
19const Ipc::Mem::PageStack::Value Writable = 0;
20
68353d5a 21Ipc::Mem::PageStack::PageStack(const uint32_t aPoolId, const unsigned int aCapacity, const size_t aPageSize):
f53969cc
SM
22 thePoolId(aPoolId), theCapacity(aCapacity), thePageSize(aPageSize),
23 theSize(theCapacity),
24 theLastReadable(prev(theSize)), theFirstWritable(next(theLastReadable)),
25 theItems(aCapacity)
c011f9bc 26{
68353d5a
DK
27 // initially, all pages are free
28 for (Offset i = 0; i < theSize; ++i)
29 theItems[i] = i + 1; // skip page number zero to keep numbers positive
2cde0303
FC
30}
31
be17aa82
AR
32/*
33 * TODO: We currently rely on the theLastReadable hint during each
34 * loop iteration. We could also use hint just for the start position:
35 * (const Offset start = theLastReadable) and then scan the stack
36 * sequentially regardless of theLastReadable changes by others. Which
37 * approach is better? Same for push().
38 */
39bool
68353d5a 40Ipc::Mem::PageStack::pop(PageId &page)
be17aa82 41{
8ed94021
DK
42 Must(!page);
43
be17aa82 44 // we may fail to dequeue, but be conservative to prevent long searches
68353d5a 45 --theSize;
be17aa82
AR
46
47 // find a Readable slot, starting with theLastReadable and going left
68353d5a 48 while (theSize >= 0) {
2253ee0b 49 Offset idx = theLastReadable;
be17aa82 50 // mark the slot at ids Writable while extracting its current value
2253ee0b 51 const Value value = theItems[idx].fetch_and(0); // works if Writable is 0
be17aa82
AR
52 const bool popped = value != Writable;
53 // theItems[idx] is probably not Readable [any more]
03055efe
AR
54
55 // Whether we popped a Readable value or not, we should try going left
56 // to maintain the index (and make progress).
57 // We may fail if others already updated the index, but that is OK.
2253ee0b 58 theLastReadable.compare_exchange_weak(idx, prev(idx)); // may fail or lie
03055efe 59
be17aa82
AR
60 if (popped) {
61 // the slot we emptied may already be filled, but that is OK
68353d5a
DK
62 theFirstWritable = idx; // may lie
63 page.pool = thePoolId;
64 page.number = value;
383ff927 65 debugs(54, 9, page << " at " << idx << " size: " << theSize);
be17aa82
AR
66 return true;
67 }
68 // TODO: report suspiciously long loops
69 }
70
68353d5a 71 ++theSize;
be17aa82
AR
72 return false;
73}
74
75void
68353d5a 76Ipc::Mem::PageStack::push(PageId &page)
be17aa82 77{
383ff927
AR
78 debugs(54, 9, page);
79
8ed94021
DK
80 if (!page)
81 return;
82
68353d5a 83 Must(pageIdIsValid(page));
be17aa82 84 // find a Writable slot, starting with theFirstWritable and going right
68353d5a 85 while (theSize < theCapacity) {
2253ee0b
AJ
86 Offset idx = theFirstWritable;
87 auto isWritable = Writable;
88 const bool pushed = theItems[idx].compare_exchange_strong(isWritable, page.number);
be17aa82 89 // theItems[idx] is probably not Writable [any more];
03055efe 90
68353d5a 91 // Whether we pushed the page number or not, we should try going right
03055efe
AR
92 // to maintain the index (and make progress).
93 // We may fail if others already updated the index, but that is OK.
2253ee0b 94 theFirstWritable.compare_exchange_weak(idx, next(idx)); // may fail or lie
03055efe 95
be17aa82
AR
96 if (pushed) {
97 // the enqueued value may already by gone, but that is OK
68353d5a
DK
98 theLastReadable = idx; // may lie
99 ++theSize;
383ff927 100 debugs(54, 9, page << " at " << idx << " size: " << theSize);
68353d5a 101 page = PageId();
be17aa82
AR
102 return;
103 }
104 // TODO: report suspiciously long loops
105 }
106 Must(false); // the number of pages cannot exceed theCapacity
107}
108
68353d5a
DK
109bool
110Ipc::Mem::PageStack::pageIdIsValid(const PageId &page) const
be17aa82 111{
68353d5a 112 return page.pool == thePoolId && page.number != Writable &&
9199139f 113 page.number <= capacity();
68353d5a
DK
114}
115
116size_t
117Ipc::Mem::PageStack::sharedMemorySize() const
118{
119 return SharedMemorySize(thePoolId, theCapacity, thePageSize);
be17aa82 120}
2d0647fb
DK
121
122size_t
68353d5a 123Ipc::Mem::PageStack::SharedMemorySize(const uint32_t, const unsigned int capacity, const size_t pageSize)
2d0647fb 124{
2253ee0b 125 const size_t levelsSize = PageId::maxPurpose * sizeof(std::atomic<Ipc::Mem::PageStack::Value>);
551f8a18
DK
126 const size_t pagesDataSize = capacity * pageSize;
127 return StackSize(capacity) + pagesDataSize + levelsSize;
128}
129
130size_t
131Ipc::Mem::PageStack::StackSize(const unsigned int capacity)
132{
133 return sizeof(PageStack) + capacity * sizeof(Item);
134}
135
136size_t
137Ipc::Mem::PageStack::stackSize() const
138{
139 return StackSize(theCapacity);
2d0647fb 140}
f53969cc 141