]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/mem/PageStack.cc
2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 54 Interprocess Communication */
13 #include "base/TextException.h"
15 #include "ipc/mem/Page.h"
16 #include "ipc/mem/PageStack.h"
18 /* Ipc::Mem::PageStackStorageSlot */
20 static_assert(sizeof(Ipc::Mem::PageStackStorageSlot::Pointer
) ==
21 sizeof(decltype(Ipc::Mem::PageId::number
)), "page indexing types are consistent");
24 Ipc::Mem::PageStackStorageSlot::take()
26 const auto nxt
= nextOrMarker
.exchange(TakenPage
);
27 assert(nxt
!= TakenPage
);
31 Ipc::Mem::PageStackStorageSlot::put(const PointerOrMarker expected
, const Pointer nxt
)
33 assert(nxt
!= TakenPage
);
34 const auto old
= nextOrMarker
.exchange(nxt
);
35 assert(old
== expected
);
38 /* Ipc::Mem::PageStack */
40 Ipc::Mem::PageStack::PageStack(const PoolId aPoolId
, const PageCount aCapacity
, const size_t aPageSize
):
41 thePoolId(aPoolId
), capacity_(aCapacity
), thePageSize(aPageSize
),
48 assert(capacity_
< Slot::TakenPage
);
49 assert(capacity_
< Slot::NilPtr
);
51 // initially, all pages are free
53 const auto lastIndex
= capacity_
-1;
54 // FlexibleArray cannot construct its phantom elements so, technically,
55 // all slots (except the very first one) are uninitialized until now.
56 for (Slot::Pointer i
= 0; i
< lastIndex
; ++i
)
57 (void)new(&slots_
[i
])Slot(i
+1);
58 (void)new(&slots_
[lastIndex
])Slot(Slot::NilPtr
);
65 Ipc::Mem::PageStack::pop(PageId
&page
)
69 Slot::Pointer current
= head_
.load();
71 auto nextFree
= Slot::NilPtr
;
73 if (current
== Slot::NilPtr
)
75 nextFree
= slots_
[current
].next();
76 } while (!head_
.compare_exchange_weak(current
, nextFree
));
78 // must decrement after removing the page to avoid underflow
79 const auto newSize
= --size_
;
80 assert(newSize
< capacity_
);
82 slots_
[current
].take();
83 page
.number
= current
+ 1;
84 page
.pool
= thePoolId
;
85 debugs(54, 8, page
<< " size: " << newSize
);
90 Ipc::Mem::PageStack::push(PageId
&page
)
94 assert(pageIdIsValid(page
));
96 const auto pageIndex
= page
.number
- 1;
97 auto &slot
= slots_
[pageIndex
];
99 // must increment before inserting the page to avoid underflow in pop()
100 const auto newSize
= ++size_
;
101 assert(newSize
<= capacity_
);
103 auto current
= head_
.load();
104 auto expected
= Slot::TakenPage
;
106 slot
.put(expected
, current
);
108 } while (!head_
.compare_exchange_weak(current
, pageIndex
));
110 debugs(54, 8, page
<< " size: " << newSize
);
115 Ipc::Mem::PageStack::pageIdIsValid(const PageId
&page
) const
117 return page
.pool
== thePoolId
&&
118 0 < page
.number
&& page
.number
<= capacity();
122 Ipc::Mem::PageStack::sharedMemorySize() const
124 return SharedMemorySize(thePoolId
, capacity_
, thePageSize
);
128 Ipc::Mem::PageStack::SharedMemorySize(const PoolId
, const PageCount capacity
, const size_t pageSize
)
130 const auto levelsSize
= PageId::maxPurpose
* sizeof(Levels_t
);
131 const size_t pagesDataSize
= capacity
* pageSize
;
132 return StackSize(capacity
) + LevelsPaddingSize(capacity
) + levelsSize
+ pagesDataSize
;
136 Ipc::Mem::PageStack::StackSize(const PageCount capacity
)
138 return sizeof(PageStack
) + capacity
* sizeof(Slot
);
142 Ipc::Mem::PageStack::stackSize() const
144 return StackSize(capacity_
);
148 Ipc::Mem::PageStack::LevelsPaddingSize(const PageCount capacity
)
150 const auto displacement
= StackSize(capacity
) % alignof(Levels_t
);
151 return displacement
? alignof(Levels_t
) - displacement
: 0;